<p>George Joseph <strong>submitted</strong> this change.</p><p><a href="https://gerrit.asterisk.org/c/asterisk/+/18783">View Change</a></p><div style="white-space:pre-wrap">Approvals:
  Kevin Harwell: Looks good to me, but someone else must approve
  George Joseph: Looks good to me, approved; Approved for Submit

</div><pre style="font-family: monospace,monospace; white-space: pre-wrap;">Geolocation:  Core Capability Preview<br><br>This commit adds res_geolocation which creates the core capabilities<br>to manipulate Geolocation information on SIP INVITEs.<br><br>An upcoming commit will add res_pjsip_geolocation which will<br>allow the capabilities to be used with the pjsip channel driver.<br><br>This commit message is intentionally short because this isn't<br>a simple capability.  See the documentation at<br>https://wiki.asterisk.org/wiki/display/AST/Geolocation<br>for more information.<br><br>THE CAPABILITIES IMPLEMENTED HERE MAY CHANGE BASED ON<br>USER FEEDBACK!<br><br>ASTERISK-30127<br><br>Change-Id: Ibfde963121b1ecf57fd98ee7060c4f0808416303<br>---<br>M Makefile.rules<br>A configs/samples/geolocation.conf.sample<br>A doc/CHANGES-staging/res_geolocation.txt<br>A include/asterisk/res_geolocation.h<br>M res/Makefile<br>A res/res_geolocation.c<br>A res/res_geolocation.exports.in<br>A res/res_geolocation/eprofile_to_pidf.xslt<br>A res/res_geolocation/geoloc_civicaddr.c<br>A res/res_geolocation/geoloc_common.c<br>A res/res_geolocation/geoloc_config.c<br>A res/res_geolocation/geoloc_datastore.c<br>A res/res_geolocation/geoloc_dialplan.c<br>A res/res_geolocation/geoloc_doc.xml<br>A res/res_geolocation/geoloc_eprofile.c<br>A res/res_geolocation/geoloc_gml.c<br>A res/res_geolocation/geoloc_private.h<br>A res/res_geolocation/pidf_lo_test.xml<br>A res/res_geolocation/pidf_to_eprofile.xslt<br>19 files changed, 4,910 insertions(+), 0 deletions(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;"><span>diff --git a/Makefile.rules b/Makefile.rules</span><br><span>index 934e44a..e6b6589 100644</span><br><span>--- a/Makefile.rules</span><br><span>+++ b/Makefile.rules</span><br><span>@@ -204,4 +204,19 @@</span><br><span>      $(ECHO_PREFIX) echo "   [LD] $^ -> $@"</span><br><span>  $(CMD_PREFIX) $(CXX) -o $@ $(PTHREAD_CFLAGS) $(_ASTLDFLAGS) $^ $(CXX_LIBS) $(ASTLDFLAGS)</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+# These CC commands just create an object file with the input file embedded in it.</span><br><span style="color: hsl(120, 100%, 40%);">+# It can be access from code as follows:</span><br><span style="color: hsl(120, 100%, 40%);">+# If your input file is named abc_def.xml...</span><br><span style="color: hsl(120, 100%, 40%);">+#</span><br><span style="color: hsl(120, 100%, 40%);">+# extern const uint8_t _binary_abc_def_xml_start[];</span><br><span style="color: hsl(120, 100%, 40%);">+# extern const uint8_t _binary_abc_def_xml_end[];</span><br><span style="color: hsl(120, 100%, 40%);">+# extern const size_t _binary_abc_def_xml_size;</span><br><span style="color: hsl(120, 100%, 40%);">+%.o: %.xml</span><br><span style="color: hsl(120, 100%, 40%);">+      $(ECHO_PREFIX) echo "   [LD] $^ -> $@"</span><br><span style="color: hsl(120, 100%, 40%);">+   $(CMD_PREFIX) $(CC) -g -nostartfiles  -nodefaultlibs -nostdlib -r -Wl,-b,binary -o $@ $^</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+%.o: %.xslt</span><br><span style="color: hsl(120, 100%, 40%);">+       $(ECHO_PREFIX) echo "   [LD] $^ -> $@"</span><br><span style="color: hsl(120, 100%, 40%);">+   $(CMD_PREFIX) $(CC) -g -nostartfiles  -nodefaultlibs -nostdlib -r -Wl,-b,binary -o $@ $^</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> dist-clean:: clean</span><br><span>diff --git a/configs/samples/geolocation.conf.sample b/configs/samples/geolocation.conf.sample</span><br><span>new file mode 100644</span><br><span>index 0000000..0566cbd</span><br><span>--- /dev/null</span><br><span>+++ b/configs/samples/geolocation.conf.sample</span><br><span>@@ -0,0 +1,264 @@</span><br><span style="color: hsl(120, 100%, 40%);">+;--</span><br><span style="color: hsl(120, 100%, 40%);">+  Geolocation Profile Sample Configuration</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+--;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+;--</span><br><span style="color: hsl(120, 100%, 40%);">+=======================================================================</span><br><span style="color: hsl(120, 100%, 40%);">+  Overview</span><br><span style="color: hsl(120, 100%, 40%);">+=======================================================================</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+Geolocation information is actually comprised of two objects, a</span><br><span style="color: hsl(120, 100%, 40%);">+Location object, and a Profile object.</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+Location objects must contain one of the following:</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  - Location information specified in Geographic Markup Language</span><br><span style="color: hsl(120, 100%, 40%);">+    (GML) or civicAddress formats.</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  - A URI that points to externally hosted location information.</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+Profile objects contain instructions for the disposition of location</span><br><span style="color: hsl(120, 100%, 40%);">+information, an optional reference to a Location object, and updates or</span><br><span style="color: hsl(120, 100%, 40%);">+overrides to that Location object if specified.</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+Channel drivers and the dialplan functions are responsible for</span><br><span style="color: hsl(120, 100%, 40%);">+associating Profiles to endpoints/devices and calls.  Normally, two</span><br><span style="color: hsl(120, 100%, 40%);">+profiles would be assigned to an endpoint to control behavior in each</span><br><span style="color: hsl(120, 100%, 40%);">+direction and to optionally specify location information.  One for</span><br><span style="color: hsl(120, 100%, 40%);">+incoming calls (Asterisk is the UAS) and and one for outgoing calls</span><br><span style="color: hsl(120, 100%, 40%);">+(Asterisk is the UAC).</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+NOTE:</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+See https://wiki.asterisk.org/wiki/display/AST/Geolocation for the most</span><br><span style="color: hsl(120, 100%, 40%);">+complete and up-to-date information on valid values for the object</span><br><span style="color: hsl(120, 100%, 40%);">+parameters and a full list of references.</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+GENERAL CAUTION:  You must coordinate with your partners with regards</span><br><span style="color: hsl(120, 100%, 40%);">+to what location information is expected by each party and how it should</span><br><span style="color: hsl(120, 100%, 40%);">+be formatted.  An outgoing configuration mismatch for instance, could</span><br><span style="color: hsl(120, 100%, 40%);">+result in misinformation or no information being sent to an emergency</span><br><span style="color: hsl(120, 100%, 40%);">+response center or even call failure for which you are solely responsible.</span><br><span style="color: hsl(120, 100%, 40%);">+--;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+;--</span><br><span style="color: hsl(120, 100%, 40%);">+=======================================================================</span><br><span style="color: hsl(120, 100%, 40%);">+  Location Object Description</span><br><span style="color: hsl(120, 100%, 40%);">+=======================================================================</span><br><span style="color: hsl(120, 100%, 40%);">+[<location_id>]</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+-- type (required) ----------------------------------------------------</span><br><span style="color: hsl(120, 100%, 40%);">+Defines the object type.</span><br><span style="color: hsl(120, 100%, 40%);">+type = location</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+Must be "location" to identify this configuration section as a</span><br><span style="color: hsl(120, 100%, 40%);">+Geolocation Location object.</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+-- format (required) --------------------------------------------------</span><br><span style="color: hsl(120, 100%, 40%);">+Sets the format used to express the location.</span><br><span style="color: hsl(120, 100%, 40%);">+format = < civicAddress | GML | URI ></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+Values:</span><br><span style="color: hsl(120, 100%, 40%);">+civicAddress: [RFC4119] [RFC5139] [RFC5491]</span><br><span style="color: hsl(120, 100%, 40%);">+              The location information will be placed in an XML document</span><br><span style="color: hsl(120, 100%, 40%);">+              conforming to the PIDF-LO standard.</span><br><span style="color: hsl(120, 100%, 40%);">+              For chan_pjsip, this will be placed in the body of</span><br><span style="color: hsl(120, 100%, 40%);">+              outgoing INVITE messages in addition to any SDP.</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+GML:          [RFC4119] [RFC5491] [GeoShape]</span><br><span style="color: hsl(120, 100%, 40%);">+              The location information will be placed in an XML document</span><br><span style="color: hsl(120, 100%, 40%);">+              conforming to the PIDF-LO standard.</span><br><span style="color: hsl(120, 100%, 40%);">+              For chan_pjsip, this will be placed in the body of</span><br><span style="color: hsl(120, 100%, 40%);">+              outgoing INVITE messages in addition to any SDP.</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+URI:          [RFC6442]</span><br><span style="color: hsl(120, 100%, 40%);">+              The external URI at which the the location information</span><br><span style="color: hsl(120, 100%, 40%);">+              can be found.  For chan_pjsip, this URI will be placed</span><br><span style="color: hsl(120, 100%, 40%);">+              in a "Geolocation" header in outgoing INVITE messages.</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+There is no default.</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+Example:</span><br><span style="color: hsl(120, 100%, 40%);">+format = civicAddress</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+-- location_info (required) -------------------------------------------</span><br><span style="color: hsl(120, 100%, 40%);">+The location-format-specific information describing the location.</span><br><span style="color: hsl(120, 100%, 40%);">+location_info = <location_format_specific_description></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+For readability, multiple "location" parameters can be specified and</span><br><span style="color: hsl(120, 100%, 40%);">+they will be concatenated into one specification.  The description may</span><br><span style="color: hsl(120, 100%, 40%);">+contain replacement variables which may be the names of common channel</span><br><span style="color: hsl(120, 100%, 40%);">+variables like ${EXTEN}, channel variables you may have added in the</span><br><span style="color: hsl(120, 100%, 40%);">+dialplan, or variables you may have specified in the profile that</span><br><span style="color: hsl(120, 100%, 40%);">+references this location object.</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+NOTE: See https://wiki.asterisk.org/wiki/display/AST/Geolocation for the</span><br><span style="color: hsl(120, 100%, 40%);">+most complete and up-to-date information on valid values for the object</span><br><span style="color: hsl(120, 100%, 40%);">+parameters and a full list of references.</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+WARNING: Asterisk can only validate that a particular sub-parameter</span><br><span style="color: hsl(120, 100%, 40%);">+name is valid for a particular format. It can't validate the actual</span><br><span style="color: hsl(120, 100%, 40%);">+value of the sub-parameter.</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+Example for civicAddress:</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+location_info = country=US</span><br><span style="color: hsl(120, 100%, 40%);">+location_info = A1="New York", A3="New York", A4=Manhattan,  </span><br><span style="color: hsl(120, 100%, 40%);">+location_info = HNO=1633, PRD=W, RD=46th, STS=Street  </span><br><span style="color: hsl(120, 100%, 40%);">+location_info = PC=10222</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+Example for GML with replacement variables:</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+location_info = type=Point, crs=2d, pos="${mylat} ${mylon}"</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+Example for URI with replacement variables:</span><br><span style="color: hsl(120, 100%, 40%);">+location_info = URI=https://some.company.com?number=${phone_number}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+-- method (optional) --------------------------------------------------</span><br><span style="color: hsl(120, 100%, 40%);">+The method used to determine the location_info</span><br><span style="color: hsl(120, 100%, 40%);">+method = <"GPS" | "A-GPS" | "Manual" | "DHCP"</span><br><span style="color: hsl(120, 100%, 40%);">+              | "Triangulation" | "Cell" | "802.11"></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+Example:</span><br><span style="color: hsl(120, 100%, 40%);">+method = Manual</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+-- location_source (optional) -----------------------------------------</span><br><span style="color: hsl(120, 100%, 40%);">+Original source of the location-info.</span><br><span style="color: hsl(120, 100%, 40%);">+location_source = < FQDN ></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+The value MUST be a FQDN.  IP addresses are specifically not</span><br><span style="color: hsl(120, 100%, 40%);">+allowed.  See RFC8787.</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+Example:</span><br><span style="color: hsl(120, 100%, 40%);">+location_source = sip1.myserver.net</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+-- Location Example ---------------------------------------------------</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+[mylocation]</span><br><span style="color: hsl(120, 100%, 40%);">+type = location</span><br><span style="color: hsl(120, 100%, 40%);">+format = civicAddress</span><br><span style="color: hsl(120, 100%, 40%);">+location_info = country=US</span><br><span style="color: hsl(120, 100%, 40%);">+location_info = A1="New York", A3="New York", A4=Manhattan  </span><br><span style="color: hsl(120, 100%, 40%);">+location_info = HNO=1633, PRD=W, RD=46th, STS=Street  </span><br><span style="color: hsl(120, 100%, 40%);">+location_info = PC=10222</span><br><span style="color: hsl(120, 100%, 40%);">+method = Manual</span><br><span style="color: hsl(120, 100%, 40%);">+location_source = sip1.myserver.net</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+=======================================================================</span><br><span style="color: hsl(120, 100%, 40%);">+--;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+;--</span><br><span style="color: hsl(120, 100%, 40%);">+=======================================================================</span><br><span style="color: hsl(120, 100%, 40%);">+  Profile Object Descriptions</span><br><span style="color: hsl(120, 100%, 40%);">+=======================================================================</span><br><span style="color: hsl(120, 100%, 40%);">+[<profile_id>]</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+-- type (required) ----------------------------------------------------</span><br><span style="color: hsl(120, 100%, 40%);">+Defines the object type.</span><br><span style="color: hsl(120, 100%, 40%);">+type = profile</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+-- profile_action (optional) ------------------------------------------</span><br><span style="color: hsl(120, 100%, 40%);">+Sets how to reconcile incoming and configured profiles.</span><br><span style="color: hsl(120, 100%, 40%);">+profile_action = < prefer_incoming | prefer_config | discard_incoming</span><br><span style="color: hsl(120, 100%, 40%);">+    | discard_config ></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+On an incoming call leg, "incoming" is the location description</span><br><span style="color: hsl(120, 100%, 40%);">+received in the SIP INVITE (if any) and "config" is this profile.</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+On an outgoing call leg, "incoming" is the location description</span><br><span style="color: hsl(120, 100%, 40%);">+passed through the dialplan to this channel (if any) and "config"</span><br><span style="color: hsl(120, 100%, 40%);">+is this profile.</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+Values:</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+prefer_incoming:  If there's an incoming location description, use it</span><br><span style="color: hsl(120, 100%, 40%);">+                  even if there's also a configured one.</span><br><span style="color: hsl(120, 100%, 40%);">+prefer_config:    If there's a configured location description, use it</span><br><span style="color: hsl(120, 100%, 40%);">+                  even if there's also an incoming one.</span><br><span style="color: hsl(120, 100%, 40%);">+discard_incoming: Discard any incoming location description. If there's</span><br><span style="color: hsl(120, 100%, 40%);">+                  a configured one, use it.  If not, no location</span><br><span style="color: hsl(120, 100%, 40%);">+                  information is propagated.</span><br><span style="color: hsl(120, 100%, 40%);">+discard_config:   Discard any configured location description. If</span><br><span style="color: hsl(120, 100%, 40%);">+                  there's an incoming one, use it.  If not, no location</span><br><span style="color: hsl(120, 100%, 40%);">+                  information is propagated.</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+discard_incoming is the default.</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+Example:</span><br><span style="color: hsl(120, 100%, 40%);">+profile_action = prefer_config</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+-- pidf_element (optional) --------------------------------------------</span><br><span style="color: hsl(120, 100%, 40%);">+PIDF-LO element in which to place the location description.</span><br><span style="color: hsl(120, 100%, 40%);">+pidf_element = < tuple | device | person ></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+If the format is civicAddress or GML, this sets the PIDF element into</span><br><span style="color: hsl(120, 100%, 40%);">+which the location information will be placed.</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+Values:</span><br><span style="color: hsl(120, 100%, 40%);">+tuple:  Places the information in a "tuple" element.</span><br><span style="color: hsl(120, 100%, 40%);">+device: Places the information in a "device" element.</span><br><span style="color: hsl(120, 100%, 40%);">+person: Places the information in a "person" element.</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+Per [RFC5491], "device" is preferred and therefore the default.</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+Example:</span><br><span style="color: hsl(120, 100%, 40%);">+pidf_element = tuple</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+-- geolocation_routing (optional) -------------------------------------</span><br><span style="color: hsl(120, 100%, 40%);">+Sets whether the "Geolocation-Routing" header is added to outgoing</span><br><span style="color: hsl(120, 100%, 40%);">+requests.</span><br><span style="color: hsl(120, 100%, 40%);">+geolocation_routing = < yes | no ></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+Set to "yes" to indicate that servers later in the path</span><br><span style="color: hsl(120, 100%, 40%);">+can use the location information for routing purposes.  Set to "no"</span><br><span style="color: hsl(120, 100%, 40%);">+if they should not.  If this value isn't specified, no</span><br><span style="color: hsl(120, 100%, 40%);">+"Geolocation-Routing" header will be added.</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+Example:</span><br><span style="color: hsl(120, 100%, 40%);">+geolocation_routing = yes</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+-- location_reference (optional) --------------------------------------</span><br><span style="color: hsl(120, 100%, 40%);">+The name of an existing Location object.</span><br><span style="color: hsl(120, 100%, 40%);">+location_reference = <location_id></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+The location_info_refinement and location_variables parameters below can</span><br><span style="color: hsl(120, 100%, 40%);">+be used to refine the location object for this specific profile.</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+Example:</span><br><span style="color: hsl(120, 100%, 40%);">+location_reference = "my_building"</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+-- location_info_refinement (optional) --------------------------------</span><br><span style="color: hsl(120, 100%, 40%);">+Location info to add to that already retrieved from the location object.</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+location_info_refinement = <location_format_specific_description></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+The information in the referenced Location object can be refined on a</span><br><span style="color: hsl(120, 100%, 40%);">+per-profile basis.  For example, if the referenced Location object has a</span><br><span style="color: hsl(120, 100%, 40%);">+civicAddress for a building, you could set location_refinement to add a</span><br><span style="color: hsl(120, 100%, 40%);">+floor and room just for this profile</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+Example:</span><br><span style="color: hsl(120, 100%, 40%);">+location_info_refinement = floor=20, room=20a2</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+-- location_variables -------------------------------------------------</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+If the referenced Location object uses any replacement variables, they</span><br><span style="color: hsl(120, 100%, 40%);">+can be assigned here.  There is no need to define variables that come</span><br><span style="color: hsl(120, 100%, 40%);">+from the channel using this profile.  They get assigned automatically.</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+location_variables = myfloor=20, myroom=222</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+-- Profile Example ----------------------------------------------------</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+[myprofile]</span><br><span style="color: hsl(120, 100%, 40%);">+type = profile</span><br><span style="color: hsl(120, 100%, 40%);">+location_reference = mylocation</span><br><span style="color: hsl(120, 100%, 40%);">+location_info_refinement = floor=20, room=20a2</span><br><span style="color: hsl(120, 100%, 40%);">+pidf_element = tuple</span><br><span style="color: hsl(120, 100%, 40%);">+profile_action = discard_incoming</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+=======================================================================</span><br><span style="color: hsl(120, 100%, 40%);">+--;</span><br><span>diff --git a/doc/CHANGES-staging/res_geolocation.txt b/doc/CHANGES-staging/res_geolocation.txt</span><br><span>new file mode 100644</span><br><span>index 0000000..5fe7316</span><br><span>--- /dev/null</span><br><span>+++ b/doc/CHANGES-staging/res_geolocation.txt</span><br><span>@@ -0,0 +1,4 @@</span><br><span style="color: hsl(120, 100%, 40%);">+Subject: res_geolocation</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+Added res_geolocation which creates the core capabilities</span><br><span style="color: hsl(120, 100%, 40%);">+to manipulate Geolocation information on SIP INVITEs.</span><br><span>diff --git a/include/asterisk/res_geolocation.h b/include/asterisk/res_geolocation.h</span><br><span>new file mode 100644</span><br><span>index 0000000..403e6c8</span><br><span>--- /dev/null</span><br><span>+++ b/include/asterisk/res_geolocation.h</span><br><span>@@ -0,0 +1,353 @@</span><br><span style="color: hsl(120, 100%, 40%);">+ /*</span><br><span style="color: hsl(120, 100%, 40%);">+ * Asterisk -- An open source telephony toolkit.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * Copyright (C) 2022, Sangoma Technologies Corporation</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * George Joseph <gjoseph@sangoma.com></span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * See http://www.asterisk.org for more information about</span><br><span style="color: hsl(120, 100%, 40%);">+ * the Asterisk project. Please do not directly contact</span><br><span style="color: hsl(120, 100%, 40%);">+ * any of the maintainers of this project for assistance;</span><br><span style="color: hsl(120, 100%, 40%);">+ * the project provides a web site, mailing lists and IRC</span><br><span style="color: hsl(120, 100%, 40%);">+ * channels for your use.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * This program is free software, distributed under the terms of</span><br><span style="color: hsl(120, 100%, 40%);">+ * the GNU General Public License Version 2. See the LICENSE file</span><br><span style="color: hsl(120, 100%, 40%);">+ * at the top of the source tree.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#ifndef INCLUDE_ASTERISK_RES_GEOLOCATION_H_</span><br><span style="color: hsl(120, 100%, 40%);">+#define INCLUDE_ASTERISK_RES_GEOLOCATION_H_</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include "asterisk/channel.h"</span><br><span style="color: hsl(120, 100%, 40%);">+#include "asterisk/config.h"</span><br><span style="color: hsl(120, 100%, 40%);">+#include "asterisk/sorcery.h"</span><br><span style="color: hsl(120, 100%, 40%);">+#include "asterisk/xml.h"</span><br><span style="color: hsl(120, 100%, 40%);">+#include "asterisk/optional_api.h"</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#define AST_GEOLOC_INVALID_VALUE -1</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+enum ast_geoloc_pidf_element {</span><br><span style="color: hsl(120, 100%, 40%);">+       AST_PIDF_ELEMENT_NONE = 0,</span><br><span style="color: hsl(120, 100%, 40%);">+    AST_PIDF_ELEMENT_TUPLE,</span><br><span style="color: hsl(120, 100%, 40%);">+       AST_PIDF_ELEMENT_DEVICE,</span><br><span style="color: hsl(120, 100%, 40%);">+      AST_PIDF_ELEMENT_PERSON,</span><br><span style="color: hsl(120, 100%, 40%);">+      AST_PIDF_ELEMENT_LAST,</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+enum ast_geoloc_format {</span><br><span style="color: hsl(120, 100%, 40%);">+        AST_GEOLOC_FORMAT_NONE = 0,</span><br><span style="color: hsl(120, 100%, 40%);">+   AST_GEOLOC_FORMAT_CIVIC_ADDRESS,</span><br><span style="color: hsl(120, 100%, 40%);">+      AST_GEOLOC_FORMAT_GML,</span><br><span style="color: hsl(120, 100%, 40%);">+        AST_GEOLOC_FORMAT_URI,</span><br><span style="color: hsl(120, 100%, 40%);">+        AST_GEOLOC_FORMAT_LAST,</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+enum ast_geoloc_action {</span><br><span style="color: hsl(120, 100%, 40%);">+       AST_GEOLOC_ACT_PREFER_INCOMING = 0,</span><br><span style="color: hsl(120, 100%, 40%);">+   AST_GEOLOC_ACT_PREFER_CONFIG,</span><br><span style="color: hsl(120, 100%, 40%);">+ AST_GEOLOC_ACT_DISCARD_INCOMING,</span><br><span style="color: hsl(120, 100%, 40%);">+      AST_GEOLOC_ACT_DISCARD_CONFIG,</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct ast_geoloc_location {</span><br><span style="color: hsl(120, 100%, 40%);">+    SORCERY_OBJECT(details);</span><br><span style="color: hsl(120, 100%, 40%);">+      AST_DECLARE_STRING_FIELDS(</span><br><span style="color: hsl(120, 100%, 40%);">+            AST_STRING_FIELD(method);</span><br><span style="color: hsl(120, 100%, 40%);">+             AST_STRING_FIELD(location_source);</span><br><span style="color: hsl(120, 100%, 40%);">+    );</span><br><span style="color: hsl(120, 100%, 40%);">+    enum ast_geoloc_format format;</span><br><span style="color: hsl(120, 100%, 40%);">+        struct ast_variable *location_info;</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct ast_geoloc_profile {</span><br><span style="color: hsl(120, 100%, 40%);">+        SORCERY_OBJECT(details);</span><br><span style="color: hsl(120, 100%, 40%);">+      AST_DECLARE_STRING_FIELDS(</span><br><span style="color: hsl(120, 100%, 40%);">+            AST_STRING_FIELD(location_reference);</span><br><span style="color: hsl(120, 100%, 40%);">+         AST_STRING_FIELD(notes);</span><br><span style="color: hsl(120, 100%, 40%);">+      );</span><br><span style="color: hsl(120, 100%, 40%);">+    enum ast_geoloc_pidf_element pidf_element;</span><br><span style="color: hsl(120, 100%, 40%);">+    enum ast_geoloc_action action;</span><br><span style="color: hsl(120, 100%, 40%);">+        int geolocation_routing;</span><br><span style="color: hsl(120, 100%, 40%);">+      struct ast_variable *location_refinement;</span><br><span style="color: hsl(120, 100%, 40%);">+     struct ast_variable *location_variables;</span><br><span style="color: hsl(120, 100%, 40%);">+      struct ast_variable *usage_rules;</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct ast_geoloc_eprofile {</span><br><span style="color: hsl(120, 100%, 40%);">+ AST_DECLARE_STRING_FIELDS(</span><br><span style="color: hsl(120, 100%, 40%);">+            AST_STRING_FIELD(id);</span><br><span style="color: hsl(120, 100%, 40%);">+         AST_STRING_FIELD(location_reference);</span><br><span style="color: hsl(120, 100%, 40%);">+         AST_STRING_FIELD(location_source);</span><br><span style="color: hsl(120, 100%, 40%);">+            AST_STRING_FIELD(method);</span><br><span style="color: hsl(120, 100%, 40%);">+             AST_STRING_FIELD(notes);</span><br><span style="color: hsl(120, 100%, 40%);">+      );</span><br><span style="color: hsl(120, 100%, 40%);">+    enum ast_geoloc_pidf_element pidf_element;</span><br><span style="color: hsl(120, 100%, 40%);">+    enum ast_geoloc_action action;</span><br><span style="color: hsl(120, 100%, 40%);">+        int geolocation_routing;</span><br><span style="color: hsl(120, 100%, 40%);">+      enum ast_geoloc_format format;</span><br><span style="color: hsl(120, 100%, 40%);">+        struct ast_variable *location_info;</span><br><span style="color: hsl(120, 100%, 40%);">+   struct ast_variable *location_refinement;</span><br><span style="color: hsl(120, 100%, 40%);">+     struct ast_variable *location_variables;</span><br><span style="color: hsl(120, 100%, 40%);">+      struct ast_variable *effective_location;</span><br><span style="color: hsl(120, 100%, 40%);">+      struct ast_variable *usage_rules;</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*!</span><br><span style="color: hsl(120, 100%, 40%);">+ * \brief Check if res_geolocation is available</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \return 1 if available, 0 otherwise.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+AST_OPTIONAL_API(int, ast_geoloc_is_loaded,    (void), { return 0; });</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*!</span><br><span style="color: hsl(120, 100%, 40%);">+ * \brief Retrieve a geolocation location object by id.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param id Location object id.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \return Location object or NULL if not found.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+AST_OPTIONAL_API(struct ast_geoloc_location *, ast_geoloc_get_location,</span><br><span style="color: hsl(120, 100%, 40%);">+              (const char *id),</span><br><span style="color: hsl(120, 100%, 40%);">+             { return NULL; });</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*!</span><br><span style="color: hsl(120, 100%, 40%);">+ * \brief Retrieve a geolocation profile by id.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param id profile id.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \return Profile or NULL if not found.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+AST_OPTIONAL_API(struct ast_geoloc_profile *, ast_geoloc_get_profile,</span><br><span style="color: hsl(120, 100%, 40%);">+            (const char *id),</span><br><span style="color: hsl(120, 100%, 40%);">+             { return NULL; });</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*!</span><br><span style="color: hsl(120, 100%, 40%);">+ * \brief Given a civicAddress code, check whether it's valid.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param code Pointer to the code to check</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \return 1 if valid, 0 otherwise.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+int ast_geoloc_civicaddr_is_code_valid(const char *code);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+enum ast_geoloc_validate_result {</span><br><span style="color: hsl(120, 100%, 40%);">+ AST_GEOLOC_VALIDATE_INVALID_VALUE = -1,</span><br><span style="color: hsl(120, 100%, 40%);">+       AST_GEOLOC_VALIDATE_SUCCESS = 0,</span><br><span style="color: hsl(120, 100%, 40%);">+      AST_GEOLOC_VALIDATE_MISSING_SHAPE,</span><br><span style="color: hsl(120, 100%, 40%);">+    AST_GEOLOC_VALIDATE_INVALID_SHAPE,</span><br><span style="color: hsl(120, 100%, 40%);">+    AST_GEOLOC_VALIDATE_INVALID_VARNAME,</span><br><span style="color: hsl(120, 100%, 40%);">+  AST_GEOLOC_VALIDATE_NOT_ENOUGH_VARNAMES,</span><br><span style="color: hsl(120, 100%, 40%);">+      AST_GEOLOC_VALIDATE_TOO_MANY_VARNAMES,</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+const char *ast_geoloc_validate_result_to_str(enum ast_geoloc_validate_result result);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*!</span><br><span style="color: hsl(120, 100%, 40%);">+ * \brief Validate that the names of the variables in the list are valid codes or synonyms</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param varlist Variable list to check.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param result[OUT] Pointer to char * to receive failing item.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \return result code.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+enum ast_geoloc_validate_result ast_geoloc_civicaddr_validate_varlist(</span><br><span style="color: hsl(120, 100%, 40%);">+    const struct ast_variable *varlist, const char **result);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*!</span><br><span style="color: hsl(120, 100%, 40%);">+ * \brief Validate that the variables in the list represent a valid GML shape</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param varlist Variable list to check.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param result[OUT] Pointer to char * to receive failing item.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \return result code.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+enum ast_geoloc_validate_result ast_geoloc_gml_validate_varlist(const struct ast_variable *varlist,</span><br><span style="color: hsl(120, 100%, 40%);">+       const char **result);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*!</span><br><span style="color: hsl(120, 100%, 40%);">+ * \brief Geolocation datastore Functions</span><br><span style="color: hsl(120, 100%, 40%);">+ * @{</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*!</span><br><span style="color: hsl(120, 100%, 40%);">+ * \brief Create a geoloc datastore from a profile name</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param profile_name The name of the profile to use.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \return The datastore.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+struct ast_datastore *ast_geoloc_datastore_create_from_profile_name(const char *profile_name);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*!</span><br><span style="color: hsl(120, 100%, 40%);">+ * \brief Create a geoloc datastore from an effective profile.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param eprofile The effective profile to use.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \return The datastore.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+struct ast_datastore *ast_geoloc_datastore_create_from_eprofile(</span><br><span style="color: hsl(120, 100%, 40%);">+      struct ast_geoloc_eprofile *eprofile);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*!</span><br><span style="color: hsl(120, 100%, 40%);">+ * \brief Create an empty geoloc datastore.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param id  An id to use for the datastore.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \return The datastore.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+struct ast_datastore *ast_geoloc_datastore_create(const char *id);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*!</span><br><span style="color: hsl(120, 100%, 40%);">+ * \brief Retrieve a geoloc datastore's id.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param ds The datastore</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \return The datastore's id.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+const char *ast_geoloc_datastore_get_id(struct ast_datastore *ds);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*!</span><br><span style="color: hsl(120, 100%, 40%);">+ * \brief Add an eprofile to a datastore</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param ds       The datastore</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param eprofile The eprofile to add.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \return The new number of eprofiles or -1 to indicate a failure.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+int ast_geoloc_datastore_add_eprofile(struct ast_datastore *ds,</span><br><span style="color: hsl(120, 100%, 40%);">+ struct ast_geoloc_eprofile *eprofile);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*!</span><br><span style="color: hsl(120, 100%, 40%);">+ * \brief Insert an eprofile to a datastore at the specified position</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param ds       The datastore</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param eprofile The eprofile to add.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param index    The position to insert at.  Existing eprofiles will</span><br><span style="color: hsl(120, 100%, 40%);">+ *                 be moved up to make room.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \return The new number of eprofiles or -1 to indicate a failure.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+int ast_geoloc_datastore_insert_eprofile(struct ast_datastore *ds,</span><br><span style="color: hsl(120, 100%, 40%);">+   struct ast_geoloc_eprofile *eprofile, int index);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*!</span><br><span style="color: hsl(120, 100%, 40%);">+ * \brief Retrieves the number of eprofiles in the datastore</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param ds The datastore</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \return The number of eprofiles.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+int ast_geoloc_datastore_size(struct ast_datastore *ds);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*!</span><br><span style="color: hsl(120, 100%, 40%);">+ * \brief Sets the inheritance flag on the datastore</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param ds      The datastore</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param inherit 1 to allow the datastore to be inherited by other channels</span><br><span style="color: hsl(120, 100%, 40%);">+ *                0 to prevent the datastore to be inherited by other channels</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \return 0 if successful, -1 otherwise.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+int ast_geoloc_datastore_set_inheritance(struct ast_datastore *ds, int inherit);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*!</span><br><span style="color: hsl(120, 100%, 40%);">+ * \brief Retrieve a specific eprofile from a datastore by index</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param ds The datastore</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param ix The index</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \return The effective profile ao2 object with its reference count bumped.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+struct ast_geoloc_eprofile *ast_geoloc_datastore_get_eprofile(struct ast_datastore *ds, int ix);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*!</span><br><span style="color: hsl(120, 100%, 40%);">+ * \brief Delete a specific eprofile from a datastore by index</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param ds The datastore</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param ix The index</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \return 0 if succesful, -1 otherwise.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+int ast_geoloc_datastore_delete_eprofile(struct ast_datastore *ds, int ix);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*!</span><br><span style="color: hsl(120, 100%, 40%);">+ * \brief Retrieves the geoloc datastore from a channel, if any</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param chan Channel</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \return datastore if found, NULL otherwise.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+struct ast_datastore *ast_geoloc_datastore_find(struct ast_channel *chan);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*!</span><br><span style="color: hsl(120, 100%, 40%);">+ *  @}</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*!</span><br><span style="color: hsl(120, 100%, 40%);">+ * \brief Geolocation Effective Profile Functions</span><br><span style="color: hsl(120, 100%, 40%);">+ * @{</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*!</span><br><span style="color: hsl(120, 100%, 40%);">+ * \brief Allocate a new, empty effective profile.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param name The profile's name</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \return The effective profile ao2 object.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+struct ast_geoloc_eprofile *ast_geoloc_eprofile_alloc(const char *name);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*!</span><br><span style="color: hsl(120, 100%, 40%);">+ * \brief Allocate a new effective profile from an existing profile.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param profile The profile to use.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \return The effective profile ao2 object.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+struct ast_geoloc_eprofile *ast_geoloc_eprofile_create_from_profile(struct ast_geoloc_profile *profile);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*!</span><br><span style="color: hsl(120, 100%, 40%);">+ * \brief Allocate a new effective profile from an XML PIDF-LO document</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param pidf_xmldoc       The ast_xml_doc to use.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param geoloc_uri        The URI that referenced this document.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param reference_string  An identifying string to use in error messages.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \return The effective profile ao2 object.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+struct ast_geoloc_eprofile *ast_geoloc_eprofile_create_from_pidf(</span><br><span style="color: hsl(120, 100%, 40%);">+  struct ast_xml_doc *pidf_xmldoc, const char *geoloc_uri, const char *reference_string);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*!</span><br><span style="color: hsl(120, 100%, 40%);">+ * \brief Allocate a new effective profile from a URI.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param uri               The URI to use.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param reference_string  An identifying string to use in error messages.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \return The effective profile ao2 object.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+struct ast_geoloc_eprofile *ast_geoloc_eprofile_create_from_uri(const char *uri,</span><br><span style="color: hsl(120, 100%, 40%);">+ const char *reference_string);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+const char *ast_geoloc_eprofile_to_uri(struct ast_geoloc_eprofile *eprofile,</span><br><span style="color: hsl(120, 100%, 40%);">+        struct ast_channel *chan, struct ast_str **buf, const char *ref_string);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+const char *ast_geoloc_eprofiles_to_pidf(struct ast_datastore *ds,</span><br><span style="color: hsl(120, 100%, 40%);">+        struct ast_channel *chan, struct ast_str **buf, const char * ref_string);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*!</span><br><span style="color: hsl(120, 100%, 40%);">+ * \brief Refresh the effective profile with any changed info.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param eprofile The eprofile to refresh.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \return 0 on success, any other value on error.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+int ast_geoloc_eprofile_refresh_location(struct ast_geoloc_eprofile *eprofile);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*!</span><br><span style="color: hsl(120, 100%, 40%);">+ *  @}</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#endif /* INCLUDE_ASTERISK_RES_GEOLOCATION_H_ */</span><br><span>diff --git a/res/Makefile b/res/Makefile</span><br><span>index d541300..0987f43 100644</span><br><span>--- a/res/Makefile</span><br><span>+++ b/res/Makefile</span><br><span>@@ -70,6 +70,10 @@</span><br><span> $(call MOD_ADD_C,res_stasis_recording,stasis_recording/stored.c)</span><br><span> $(call MOD_ADD_C,res_stir_shaken,$(wildcard res_stir_shaken/*.c))</span><br><span> $(call MOD_ADD_C,res_aeap,$(wildcard res_aeap/*.c))</span><br><span style="color: hsl(120, 100%, 40%);">+$(call MOD_ADD_C,res_geolocation,$(wildcard res_geolocation/*.c))</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+# These are the xml and xslt files to be embedded</span><br><span style="color: hsl(120, 100%, 40%);">+res_geolocation.so: res_geolocation/pidf_lo_test.o res_geolocation/pidf_to_eprofile.o res_geolocation/eprofile_to_pidf.o</span><br><span> </span><br><span> res_parking.o: _ASTCFLAGS+=$(AST_NO_FORMAT_TRUNCATION)</span><br><span> snmp/agent.o: _ASTCFLAGS+=-fPIC</span><br><span>@@ -77,3 +81,4 @@</span><br><span> </span><br><span> # Dependencies for res_ari_*.so are generated, so they're in this file</span><br><span> include ari.make</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>diff --git a/res/res_geolocation.c b/res/res_geolocation.c</span><br><span>new file mode 100644</span><br><span>index 0000000..19dd84b</span><br><span>--- /dev/null</span><br><span>+++ b/res/res_geolocation.c</span><br><span>@@ -0,0 +1,125 @@</span><br><span style="color: hsl(120, 100%, 40%);">+/*</span><br><span style="color: hsl(120, 100%, 40%);">+ * Asterisk -- An open source telephony toolkit.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * Copyright (C) 2022, Sangoma Technologies Corporation</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * George Joseph <gjoseph@sangoma.com></span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * See http://www.asterisk.org for more information about</span><br><span style="color: hsl(120, 100%, 40%);">+ * the Asterisk project. Please do not directly contact</span><br><span style="color: hsl(120, 100%, 40%);">+ * any of the maintainers of this project for assistance;</span><br><span style="color: hsl(120, 100%, 40%);">+ * the project provides a web site, mailing lists and IRC</span><br><span style="color: hsl(120, 100%, 40%);">+ * channels for your use.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * This program is free software, distributed under the terms of</span><br><span style="color: hsl(120, 100%, 40%);">+ * the GNU General Public License Version 2. See the LICENSE file</span><br><span style="color: hsl(120, 100%, 40%);">+ * at the top of the source tree.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*** MODULEINFO</span><br><span style="color: hsl(120, 100%, 40%);">+     <depend>libxml2</depend></span><br><span style="color: hsl(120, 100%, 40%);">+  <depend>libxslt</depend></span><br><span style="color: hsl(120, 100%, 40%);">+  <support_level>core</support_level></span><br><span style="color: hsl(120, 100%, 40%);">+ ***/</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include "asterisk.h"</span><br><span style="color: hsl(120, 100%, 40%);">+#define AST_API_MODULE</span><br><span style="color: hsl(120, 100%, 40%);">+#include "asterisk/res_geolocation.h"</span><br><span style="color: hsl(120, 100%, 40%);">+#include "res_geolocation/geoloc_private.h"</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static int reload_module(void)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+      int res = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        res = geoloc_civicaddr_reload();</span><br><span style="color: hsl(120, 100%, 40%);">+      if (res) {</span><br><span style="color: hsl(120, 100%, 40%);">+            return AST_MODULE_LOAD_DECLINE;</span><br><span style="color: hsl(120, 100%, 40%);">+       }</span><br><span style="color: hsl(120, 100%, 40%);">+     res = geoloc_gml_reload();</span><br><span style="color: hsl(120, 100%, 40%);">+    if (res) {</span><br><span style="color: hsl(120, 100%, 40%);">+            return AST_MODULE_LOAD_DECLINE;</span><br><span style="color: hsl(120, 100%, 40%);">+       }</span><br><span style="color: hsl(120, 100%, 40%);">+     res = geoloc_config_reload();</span><br><span style="color: hsl(120, 100%, 40%);">+ if (res) {</span><br><span style="color: hsl(120, 100%, 40%);">+            return AST_MODULE_LOAD_DECLINE;</span><br><span style="color: hsl(120, 100%, 40%);">+       }</span><br><span style="color: hsl(120, 100%, 40%);">+     res = geoloc_eprofile_reload();</span><br><span style="color: hsl(120, 100%, 40%);">+       if (res) {</span><br><span style="color: hsl(120, 100%, 40%);">+            return AST_MODULE_LOAD_DECLINE;</span><br><span style="color: hsl(120, 100%, 40%);">+       }</span><br><span style="color: hsl(120, 100%, 40%);">+     res = geoloc_dialplan_reload();</span><br><span style="color: hsl(120, 100%, 40%);">+       if (res) {</span><br><span style="color: hsl(120, 100%, 40%);">+            return AST_MODULE_LOAD_DECLINE;</span><br><span style="color: hsl(120, 100%, 40%);">+       }</span><br><span style="color: hsl(120, 100%, 40%);">+     res = geoloc_channel_reload();</span><br><span style="color: hsl(120, 100%, 40%);">+        if (res) {</span><br><span style="color: hsl(120, 100%, 40%);">+            return AST_MODULE_LOAD_DECLINE;</span><br><span style="color: hsl(120, 100%, 40%);">+       }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   return AST_MODULE_LOAD_SUCCESS;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static int unload_module(void)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+       int res = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        res += geoloc_channel_unload();</span><br><span style="color: hsl(120, 100%, 40%);">+       res += geoloc_dialplan_unload();</span><br><span style="color: hsl(120, 100%, 40%);">+      res += geoloc_eprofile_unload();</span><br><span style="color: hsl(120, 100%, 40%);">+      res += geoloc_config_unload();</span><br><span style="color: hsl(120, 100%, 40%);">+        res += geoloc_gml_unload();</span><br><span style="color: hsl(120, 100%, 40%);">+   res += geoloc_civicaddr_unload();</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   return (res != 0);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static int load_module(void)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+      int res = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        res = geoloc_civicaddr_load();</span><br><span style="color: hsl(120, 100%, 40%);">+        if (res) {</span><br><span style="color: hsl(120, 100%, 40%);">+            unload_module();</span><br><span style="color: hsl(120, 100%, 40%);">+              return AST_MODULE_LOAD_DECLINE;</span><br><span style="color: hsl(120, 100%, 40%);">+       }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   res = geoloc_gml_load();</span><br><span style="color: hsl(120, 100%, 40%);">+      if (res) {</span><br><span style="color: hsl(120, 100%, 40%);">+            return AST_MODULE_LOAD_DECLINE;</span><br><span style="color: hsl(120, 100%, 40%);">+       }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   res = geoloc_config_load();</span><br><span style="color: hsl(120, 100%, 40%);">+   if (res) {</span><br><span style="color: hsl(120, 100%, 40%);">+            unload_module();</span><br><span style="color: hsl(120, 100%, 40%);">+              return AST_MODULE_LOAD_DECLINE;</span><br><span style="color: hsl(120, 100%, 40%);">+       }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   res = geoloc_eprofile_load();</span><br><span style="color: hsl(120, 100%, 40%);">+ if (res) {</span><br><span style="color: hsl(120, 100%, 40%);">+            unload_module();</span><br><span style="color: hsl(120, 100%, 40%);">+              return AST_MODULE_LOAD_DECLINE;</span><br><span style="color: hsl(120, 100%, 40%);">+       }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   res = geoloc_dialplan_load();</span><br><span style="color: hsl(120, 100%, 40%);">+ if (res) {</span><br><span style="color: hsl(120, 100%, 40%);">+            unload_module();</span><br><span style="color: hsl(120, 100%, 40%);">+              return AST_MODULE_LOAD_DECLINE;</span><br><span style="color: hsl(120, 100%, 40%);">+       }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   res = geoloc_channel_load();</span><br><span style="color: hsl(120, 100%, 40%);">+  if (res) {</span><br><span style="color: hsl(120, 100%, 40%);">+            unload_module();</span><br><span style="color: hsl(120, 100%, 40%);">+              return AST_MODULE_LOAD_DECLINE;</span><br><span style="color: hsl(120, 100%, 40%);">+       }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   return AST_MODULE_LOAD_SUCCESS;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS | AST_MODFLAG_LOAD_ORDER, "res_geolocation Module for Asterisk",</span><br><span style="color: hsl(120, 100%, 40%);">+ .support_level = AST_MODULE_SUPPORT_CORE,</span><br><span style="color: hsl(120, 100%, 40%);">+     .load = load_module,</span><br><span style="color: hsl(120, 100%, 40%);">+  .unload = unload_module,</span><br><span style="color: hsl(120, 100%, 40%);">+      .reload = reload_module,</span><br><span style="color: hsl(120, 100%, 40%);">+      .load_pri = AST_MODPRI_CHANNEL_DEPEND - 10,</span><br><span style="color: hsl(120, 100%, 40%);">+);</span><br><span>diff --git a/res/res_geolocation.exports.in b/res/res_geolocation.exports.in</span><br><span>new file mode 100644</span><br><span>index 0000000..da0a981</span><br><span>--- /dev/null</span><br><span>+++ b/res/res_geolocation.exports.in</span><br><span>@@ -0,0 +1,6 @@</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+    global:</span><br><span style="color: hsl(120, 100%, 40%);">+               LINKER_SYMBOL_PREFIXast_geo*;</span><br><span style="color: hsl(120, 100%, 40%);">+ local:</span><br><span style="color: hsl(120, 100%, 40%);">+                *;</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span>diff --git a/res/res_geolocation/eprofile_to_pidf.xslt b/res/res_geolocation/eprofile_to_pidf.xslt</span><br><span>new file mode 100644</span><br><span>index 0000000..dbfe17b</span><br><span>--- /dev/null</span><br><span>+++ b/res/res_geolocation/eprofile_to_pidf.xslt</span><br><span>@@ -0,0 +1,237 @@</span><br><span style="color: hsl(120, 100%, 40%);">+<?xml version="1.0"?></span><br><span style="color: hsl(120, 100%, 40%);">+<xsl:stylesheet version="1.1"</span><br><span style="color: hsl(120, 100%, 40%);">+  xmlns:ca="urn:ietf:params:xml:ns:pidf:geopriv10:civicAddr"</span><br><span style="color: hsl(120, 100%, 40%);">+  xmlns:dm="urn:ietf:params:xml:ns:pidf:data-model"</span><br><span style="color: hsl(120, 100%, 40%);">+   xmlns:fn="http://www.w3.org/2005/xpath-functions"</span><br><span style="color: hsl(120, 100%, 40%);">+   xmlns:gbp="urn:ietf:params:xml:ns:pidf:geopriv10:basicPolicy"</span><br><span style="color: hsl(120, 100%, 40%);">+       xmlns:gml="http://www.opengis.net/gml"</span><br><span style="color: hsl(120, 100%, 40%);">+      xmlns:gp="urn:ietf:params:xml:ns:pidf:geopriv10"</span><br><span style="color: hsl(120, 100%, 40%);">+    xmlns:gs="http://www.opengis.net/pidflo/1.0"</span><br><span style="color: hsl(120, 100%, 40%);">+        xmlns:xsl="http://www.w3.org/1999/XSL/Transform"</span><br><span style="color: hsl(120, 100%, 40%);">+    xmlns:date="http://exslt.org/dates-and-times"></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ <xsl:output method="xml" indent="yes"/></span><br><span style="color: hsl(120, 100%, 40%);">+     <xsl:strip-space elements="*"/></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     <!-- REMINDER:  The "match" and "select" xpaths refer to the input document,</span><br><span style="color: hsl(120, 100%, 40%);">+           not the output document --></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      <xsl:template match="presence"></span><br><span style="color: hsl(120, 100%, 40%);">+               <!-- xslt will take care of adding all of the namespace declarations</span><br><span style="color: hsl(120, 100%, 40%);">+                       from the list above --></span><br><span style="color: hsl(120, 100%, 40%);">+            <presence xmlns="urn:ietf:params:xml:ns:pidf" entity="{@entity}"></span><br><span style="color: hsl(120, 100%, 40%);">+                   <xsl:apply-templates select="./device|tuple|person"/></span><br><span style="color: hsl(120, 100%, 40%);">+         </presence></span><br><span style="color: hsl(120, 100%, 40%);">+     </xsl:template></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       <xsl:template match="device"></span><br><span style="color: hsl(120, 100%, 40%);">+         <dm:device></span><br><span style="color: hsl(120, 100%, 40%);">+                     <gp:geopriv></span><br><span style="color: hsl(120, 100%, 40%);">+                            <xsl:apply-templates select="./location-info"/></span><br><span style="color: hsl(120, 100%, 40%);">+                               <xsl:apply-templates select="./usage-rules"/></span><br><span style="color: hsl(120, 100%, 40%);">+                         <xsl:apply-templates select="./method"/></span><br><span style="color: hsl(120, 100%, 40%);">+                              <xsl:apply-templates select="./note-well"/></span><br><span style="color: hsl(120, 100%, 40%);">+                   </gp:geopriv></span><br><span style="color: hsl(120, 100%, 40%);">+                   <xsl:if test="./timestamp"></span><br><span style="color: hsl(120, 100%, 40%);">+                           <dm:timestamp></span><br><span style="color: hsl(120, 100%, 40%);">+                                  <xsl:value-of select="./timestamp"/></span><br><span style="color: hsl(120, 100%, 40%);">+                          </dm:timestamp></span><br><span style="color: hsl(120, 100%, 40%);">+                 </xsl:if></span><br><span style="color: hsl(120, 100%, 40%);">+                       <xsl:if test="./deviceID"></span><br><span style="color: hsl(120, 100%, 40%);">+                            <dm:deviceID></span><br><span style="color: hsl(120, 100%, 40%);">+                                   <xsl:value-of select="./deviceID"/></span><br><span style="color: hsl(120, 100%, 40%);">+                           </dm:deviceID></span><br><span style="color: hsl(120, 100%, 40%);">+                  </xsl:if></span><br><span style="color: hsl(120, 100%, 40%);">+               </dm:device></span><br><span style="color: hsl(120, 100%, 40%);">+    </xsl:template></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       <xsl:template match="tuple"></span><br><span style="color: hsl(120, 100%, 40%);">+          <xsl:element name="tuple" namespace="urn:ietf:params:xml:ns:pidf"></span><br><span style="color: hsl(120, 100%, 40%);">+                  <xsl:element name="status" namespace="urn:ietf:params:xml:ns:pidf"></span><br><span style="color: hsl(120, 100%, 40%);">+                         <gp:geopriv></span><br><span style="color: hsl(120, 100%, 40%);">+                                    <xsl:apply-templates select="./location-info"/></span><br><span style="color: hsl(120, 100%, 40%);">+                                       <xsl:apply-templates select="./usage-rules"/></span><br><span style="color: hsl(120, 100%, 40%);">+                                 <xsl:apply-templates select="./method"/></span><br><span style="color: hsl(120, 100%, 40%);">+                                      <xsl:apply-templates select="./note-well"/></span><br><span style="color: hsl(120, 100%, 40%);">+                           </gp:geopriv></span><br><span style="color: hsl(120, 100%, 40%);">+                   </xsl:element></span><br><span style="color: hsl(120, 100%, 40%);">+                  <xsl:if test="./timestamp"></span><br><span style="color: hsl(120, 100%, 40%);">+                           <xsl:element name="timestamp" namespace="urn:ietf:params:xml:ns:pidf"></span><br><span style="color: hsl(120, 100%, 40%);">+                                      <xsl:value-of select="./timestamp"/></span><br><span style="color: hsl(120, 100%, 40%);">+                          </xsl:element></span><br><span style="color: hsl(120, 100%, 40%);">+                  </xsl:if></span><br><span style="color: hsl(120, 100%, 40%);">+               </xsl:element></span><br><span style="color: hsl(120, 100%, 40%);">+  </xsl:template></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       <xsl:template match="person"></span><br><span style="color: hsl(120, 100%, 40%);">+         <dm:person></span><br><span style="color: hsl(120, 100%, 40%);">+                     <gp:geopriv></span><br><span style="color: hsl(120, 100%, 40%);">+                            <xsl:apply-templates select="./location-info"/></span><br><span style="color: hsl(120, 100%, 40%);">+                               <xsl:apply-templates select="./usage-rules"/></span><br><span style="color: hsl(120, 100%, 40%);">+                         <xsl:apply-templates select="./method"/></span><br><span style="color: hsl(120, 100%, 40%);">+                              <xsl:apply-templates select="./note-well"/></span><br><span style="color: hsl(120, 100%, 40%);">+                   </gp:geopriv></span><br><span style="color: hsl(120, 100%, 40%);">+                   <xsl:if test="./timestamp"></span><br><span style="color: hsl(120, 100%, 40%);">+                           <dm:timestamp></span><br><span style="color: hsl(120, 100%, 40%);">+                                  <xsl:value-of select="./timestamp"/></span><br><span style="color: hsl(120, 100%, 40%);">+                          </dm:timestamp></span><br><span style="color: hsl(120, 100%, 40%);">+                 </xsl:if></span><br><span style="color: hsl(120, 100%, 40%);">+               </dm:person></span><br><span style="color: hsl(120, 100%, 40%);">+    </xsl:template></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       <xsl:template match="location-info"></span><br><span style="color: hsl(120, 100%, 40%);">+          <gp:location-info></span><br><span style="color: hsl(120, 100%, 40%);">+                      <xsl:apply-templates/></span><br><span style="color: hsl(120, 100%, 40%);">+          </gp:location-info></span><br><span style="color: hsl(120, 100%, 40%);">+     </xsl:template></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       <!-- When we're using the civicAddress format, the translation is simple.</span><br><span style="color: hsl(120, 100%, 40%);">+              We add gp:location-info and ca:civicAddress, then we just copy in</span><br><span style="color: hsl(120, 100%, 40%);">+             each element, adding the "ca" namespace --></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    <xsl:template match="civicAddress/*"></span><br><span style="color: hsl(120, 100%, 40%);">+         <xsl:element name="ca:{name()}"></span><br><span style="color: hsl(120, 100%, 40%);">+                      <xsl:value-of select="."/></span><br><span style="color: hsl(120, 100%, 40%);">+            </xsl:element></span><br><span style="color: hsl(120, 100%, 40%);">+  </xsl:template></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       <xsl:template match="location-info/civicAddress"></span><br><span style="color: hsl(120, 100%, 40%);">+             <ca:civicAddress xml:lang="{@lang}"></span><br><span style="color: hsl(120, 100%, 40%);">+                  <xsl:apply-templates/></span><br><span style="color: hsl(120, 100%, 40%);">+          </ca:civicAddress></span><br><span style="color: hsl(120, 100%, 40%);">+      </xsl:template></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       <!-- All GML shapes share common processing for the "srsName" attribute --></span><br><span style="color: hsl(120, 100%, 40%);">+   <xsl:template name="shape"></span><br><span style="color: hsl(120, 100%, 40%);">+           <xsl:choose></span><br><span style="color: hsl(120, 100%, 40%);">+                    <xsl:when test="@crs = '3d'"></span><br><span style="color: hsl(120, 100%, 40%);">+                         <xsl:attribute name="srsName">urn:ogc:def:crs:EPSG::4979</xsl:attribute></span><br><span style="color: hsl(120, 100%, 40%);">+                        </xsl:when></span><br><span style="color: hsl(120, 100%, 40%);">+                     <xsl:otherwise></span><br><span style="color: hsl(120, 100%, 40%);">+                         <xsl:attribute name="srsName">urn:ogc:def:crs:EPSG::4326</xsl:attribute></span><br><span style="color: hsl(120, 100%, 40%);">+                        </xsl:otherwise></span><br><span style="color: hsl(120, 100%, 40%);">+                </xsl:choose></span><br><span style="color: hsl(120, 100%, 40%);">+   </xsl:template></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       <!-- The GML shapes themselves.  They don't all have the same namespace unfortunately... --></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      <xsl:template match="Point|Circle|Ellipse|ArcBand|Sphere|Ellipsoid"></span><br><span style="color: hsl(120, 100%, 40%);">+          <xsl:variable name="namespace"></span><br><span style="color: hsl(120, 100%, 40%);">+                       <xsl:choose></span><br><span style="color: hsl(120, 100%, 40%);">+                            <xsl:when test="name() = 'Point'"></span><br><span style="color: hsl(120, 100%, 40%);">+                                    <xsl:value-of select="'gml'"/></span><br><span style="color: hsl(120, 100%, 40%);">+                                </xsl:when></span><br><span style="color: hsl(120, 100%, 40%);">+                             <xsl:otherwise></span><br><span style="color: hsl(120, 100%, 40%);">+                                 <xsl:value-of select="'gs'"/></span><br><span style="color: hsl(120, 100%, 40%);">+                         </xsl:otherwise></span><br><span style="color: hsl(120, 100%, 40%);">+                        </xsl:choose></span><br><span style="color: hsl(120, 100%, 40%);">+           </xsl:variable></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+               <xsl:element name="{$namespace}:{name()}"></span><br><span style="color: hsl(120, 100%, 40%);">+                    <xsl:call-template name="shape"/></span><br><span style="color: hsl(120, 100%, 40%);">+                     <xsl:apply-templates select="./*"/></span><br><span style="color: hsl(120, 100%, 40%);">+           </xsl:element></span><br><span style="color: hsl(120, 100%, 40%);">+  </xsl:template></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       <!-- ... and some are more complex than others. --></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   <xsl:template match="Polygon"></span><br><span style="color: hsl(120, 100%, 40%);">+                <gml:Polygon></span><br><span style="color: hsl(120, 100%, 40%);">+                   <xsl:call-template name="shape"/></span><br><span style="color: hsl(120, 100%, 40%);">+                     <gml:exterior></span><br><span style="color: hsl(120, 100%, 40%);">+                          <gml:LinearRing></span><br><span style="color: hsl(120, 100%, 40%);">+                                        <xsl:apply-templates select="./pos|posList"/></span><br><span style="color: hsl(120, 100%, 40%);">+                         </gml:LinearRing></span><br><span style="color: hsl(120, 100%, 40%);">+                       </gml:exterior></span><br><span style="color: hsl(120, 100%, 40%);">+         </gml:Polygon></span><br><span style="color: hsl(120, 100%, 40%);">+  </xsl:template></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       <!-- Prism with a Polygon and height --></span><br><span style="color: hsl(120, 100%, 40%);">+        <xsl:template match="Prism"></span><br><span style="color: hsl(120, 100%, 40%);">+          <gs:Prism></span><br><span style="color: hsl(120, 100%, 40%);">+                      <xsl:call-template name="shape"/></span><br><span style="color: hsl(120, 100%, 40%);">+                     <gs:base></span><br><span style="color: hsl(120, 100%, 40%);">+                               <gml:Polygon></span><br><span style="color: hsl(120, 100%, 40%);">+                                   <gml:exterior></span><br><span style="color: hsl(120, 100%, 40%);">+                                          <gml:LinearRing></span><br><span style="color: hsl(120, 100%, 40%);">+                                                        <xsl:apply-templates select="./pos|posList"/></span><br><span style="color: hsl(120, 100%, 40%);">+                                         </gml:LinearRing></span><br><span style="color: hsl(120, 100%, 40%);">+                                       </gml:exterior></span><br><span style="color: hsl(120, 100%, 40%);">+                         </gml:Polygon></span><br><span style="color: hsl(120, 100%, 40%);">+                  </gs:base></span><br><span style="color: hsl(120, 100%, 40%);">+                      <xsl:apply-templates select="./height"/></span><br><span style="color: hsl(120, 100%, 40%);">+              </gs:Prism></span><br><span style="color: hsl(120, 100%, 40%);">+     </xsl:template></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       <!-- method has no children so we add the "gp" namespace and copy in the value --></span><br><span style="color: hsl(120, 100%, 40%);">+    <xsl:template match="method"></span><br><span style="color: hsl(120, 100%, 40%);">+         <gp:method></span><br><span style="color: hsl(120, 100%, 40%);">+                      <xsl:value-of select="."/></span><br><span style="color: hsl(120, 100%, 40%);">+            </gp:method></span><br><span style="color: hsl(120, 100%, 40%);">+   </xsl:template></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       <!-- note-well has no children so we add the "gp" namespace and copy in the value --></span><br><span style="color: hsl(120, 100%, 40%);">+ <xsl:template match="note-well"></span><br><span style="color: hsl(120, 100%, 40%);">+              <gp:note-well></span><br><span style="color: hsl(120, 100%, 40%);">+                   <xsl:value-of select="."/></span><br><span style="color: hsl(120, 100%, 40%);">+            </gp:note-well></span><br><span style="color: hsl(120, 100%, 40%);">+        </xsl:template></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       <!-- usage-rules does have children so we add the "gp" namespace and copy in</span><br><span style="color: hsl(120, 100%, 40%);">+             the children, also adding the "gp" namespace --></span><br><span style="color: hsl(120, 100%, 40%);">+ <xsl:template match="usage-rules"></span><br><span style="color: hsl(120, 100%, 40%);">+            <gp:usage-rules></span><br><span style="color: hsl(120, 100%, 40%);">+                         <xsl:for-each select="*"></span><br><span style="color: hsl(120, 100%, 40%);">+                             <xsl:element name="gp:{local-name()}"></span><br><span style="color: hsl(120, 100%, 40%);">+                                        <xsl:value-of select="."/></span><br><span style="color: hsl(120, 100%, 40%);">+                            </xsl:element></span><br><span style="color: hsl(120, 100%, 40%);">+                  </xsl:for-each></span><br><span style="color: hsl(120, 100%, 40%);">+                </gp:usage-rules></span><br><span style="color: hsl(120, 100%, 40%);">+       </xsl:template></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       <!-- These are the GML format primitives --></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  <xsl:template name="name-value"></span><br><span style="color: hsl(120, 100%, 40%);">+              <xsl:element name="gml:{name()}"></span><br><span style="color: hsl(120, 100%, 40%);">+                     <xsl:value-of select="."/></span><br><span style="color: hsl(120, 100%, 40%);">+            </xsl:element></span><br><span style="color: hsl(120, 100%, 40%);">+  </xsl:template></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       <xsl:template name="length"></span><br><span style="color: hsl(120, 100%, 40%);">+          <xsl:element name="gs:{name()}"></span><br><span style="color: hsl(120, 100%, 40%);">+                      <xsl:attribute name="uom">urn:ogc:def:uom:EPSG::9001</xsl:attribute></span><br><span style="color: hsl(120, 100%, 40%);">+                    <xsl:value-of select="."/></span><br><span style="color: hsl(120, 100%, 40%);">+            </xsl:element></span><br><span style="color: hsl(120, 100%, 40%);">+  </xsl:template></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       <xsl:template name="angle"></span><br><span style="color: hsl(120, 100%, 40%);">+           <xsl:element name="gs:{name()}"></span><br><span style="color: hsl(120, 100%, 40%);">+                      <xsl:choose></span><br><span style="color: hsl(120, 100%, 40%);">+                            <xsl:when test="@uom = 'radians'"></span><br><span style="color: hsl(120, 100%, 40%);">+                                    <xsl:attribute name="uom">urn:ogc:def:uom:EPSG::9102</xsl:attribute></span><br><span style="color: hsl(120, 100%, 40%);">+                            </xsl:when></span><br><span style="color: hsl(120, 100%, 40%);">+                             <xsl:otherwise></span><br><span style="color: hsl(120, 100%, 40%);">+                                 <xsl:attribute name="uom">urn:ogc:def:uom:EPSG::9101</xsl:attribute></span><br><span style="color: hsl(120, 100%, 40%);">+                            </xsl:otherwise></span><br><span style="color: hsl(120, 100%, 40%);">+                        </xsl:choose></span><br><span style="color: hsl(120, 100%, 40%);">+                   <xsl:value-of select="."/></span><br><span style="color: hsl(120, 100%, 40%);">+            </xsl:element></span><br><span style="color: hsl(120, 100%, 40%);">+  </xsl:template></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       <!-- These are the GML shape parameters --></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   <xsl:template match="orientation"><xsl:call-template name="angle" /></xsl:template></span><br><span style="color: hsl(120, 100%, 40%);">+     <xsl:template match="radius"><xsl:call-template name="length" /></xsl:template></span><br><span style="color: hsl(120, 100%, 40%);">+ <xsl:template match="height"><xsl:call-template name="length" /></xsl:template></span><br><span style="color: hsl(120, 100%, 40%);">+ <xsl:template match="semiMajorAxis"><xsl:call-template name="length" /></xsl:template></span><br><span style="color: hsl(120, 100%, 40%);">+  <xsl:template match="semiMinorAxis"><xsl:call-template name="length" /></xsl:template></span><br><span style="color: hsl(120, 100%, 40%);">+  <xsl:template match="verticalAxis"><xsl:call-template name="length" /></xsl:template></span><br><span style="color: hsl(120, 100%, 40%);">+   <xsl:template match="innerRadius"><xsl:call-template name="length" /></xsl:template></span><br><span style="color: hsl(120, 100%, 40%);">+    <xsl:template match="outerRadius"><xsl:call-template name="length" /></xsl:template></span><br><span style="color: hsl(120, 100%, 40%);">+    <xsl:template match="startAngle"><xsl:call-template name="angle" /></xsl:template></span><br><span style="color: hsl(120, 100%, 40%);">+      <xsl:template match="openingAngle"><xsl:call-template name="angle" /></xsl:template></span><br><span style="color: hsl(120, 100%, 40%);">+    <xsl:template match="pos"><xsl:call-template name="name-value" /></xsl:template></span><br><span style="color: hsl(120, 100%, 40%);">+        <xsl:template match="posList"><xsl:call-template name="name-value" /></xsl:template></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+</xsl:stylesheet></span><br><span>diff --git a/res/res_geolocation/geoloc_civicaddr.c b/res/res_geolocation/geoloc_civicaddr.c</span><br><span>new file mode 100644</span><br><span>index 0000000..f5a7c22</span><br><span>--- /dev/null</span><br><span>+++ b/res/res_geolocation/geoloc_civicaddr.c</span><br><span>@@ -0,0 +1,151 @@</span><br><span style="color: hsl(120, 100%, 40%);">+/*</span><br><span style="color: hsl(120, 100%, 40%);">+ * Asterisk -- An open source telephony toolkit.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * Copyright (C) 2022, Sangoma Technologies Corporation</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * George Joseph <gjoseph@sangoma.com></span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * See http://www.asterisk.org for more information about</span><br><span style="color: hsl(120, 100%, 40%);">+ * the Asterisk project. Please do not directly contact</span><br><span style="color: hsl(120, 100%, 40%);">+ * any of the maintainers of this project for assistance;</span><br><span style="color: hsl(120, 100%, 40%);">+ * the project provides a web site, mailing lists and IRC</span><br><span style="color: hsl(120, 100%, 40%);">+ * channels for your use.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * This program is free software, distributed under the terms of</span><br><span style="color: hsl(120, 100%, 40%);">+ * the GNU General Public License Version 2. See the LICENSE file</span><br><span style="color: hsl(120, 100%, 40%);">+ * at the top of the source tree.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include "asterisk.h"</span><br><span style="color: hsl(120, 100%, 40%);">+#include "asterisk/config.h"</span><br><span style="color: hsl(120, 100%, 40%);">+#include "asterisk/cli.h"</span><br><span style="color: hsl(120, 100%, 40%);">+#include "asterisk/res_geolocation.h"</span><br><span style="color: hsl(120, 100%, 40%);">+#include "asterisk/xml.h"</span><br><span style="color: hsl(120, 100%, 40%);">+#include "geoloc_private.h"</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static const char *addr_code_name_entries[] = {</span><br><span style="color: hsl(120, 100%, 40%);">+      "country",</span><br><span style="color: hsl(120, 100%, 40%);">+  "A1",</span><br><span style="color: hsl(120, 100%, 40%);">+       "A2",</span><br><span style="color: hsl(120, 100%, 40%);">+       "A3",</span><br><span style="color: hsl(120, 100%, 40%);">+       "A4",</span><br><span style="color: hsl(120, 100%, 40%);">+       "A5",</span><br><span style="color: hsl(120, 100%, 40%);">+       "A6",</span><br><span style="color: hsl(120, 100%, 40%);">+       "ADDCODE",</span><br><span style="color: hsl(120, 100%, 40%);">+  "BLD",</span><br><span style="color: hsl(120, 100%, 40%);">+      "FLR",</span><br><span style="color: hsl(120, 100%, 40%);">+      "HNO",</span><br><span style="color: hsl(120, 100%, 40%);">+      "HNS",</span><br><span style="color: hsl(120, 100%, 40%);">+      "LMK",</span><br><span style="color: hsl(120, 100%, 40%);">+      "LOC",</span><br><span style="color: hsl(120, 100%, 40%);">+      "NAM",</span><br><span style="color: hsl(120, 100%, 40%);">+      "PC",</span><br><span style="color: hsl(120, 100%, 40%);">+       "PCN",</span><br><span style="color: hsl(120, 100%, 40%);">+      "PLC",</span><br><span style="color: hsl(120, 100%, 40%);">+      "POBOX",</span><br><span style="color: hsl(120, 100%, 40%);">+    "POD",</span><br><span style="color: hsl(120, 100%, 40%);">+      "POM",</span><br><span style="color: hsl(120, 100%, 40%);">+      "PRD",</span><br><span style="color: hsl(120, 100%, 40%);">+      "PRM",</span><br><span style="color: hsl(120, 100%, 40%);">+      "RD",</span><br><span style="color: hsl(120, 100%, 40%);">+       "RD",</span><br><span style="color: hsl(120, 100%, 40%);">+       "RDBR",</span><br><span style="color: hsl(120, 100%, 40%);">+     "RDSEC",</span><br><span style="color: hsl(120, 100%, 40%);">+    "RDSUBBR",</span><br><span style="color: hsl(120, 100%, 40%);">+  "ROOM",</span><br><span style="color: hsl(120, 100%, 40%);">+     "SEAT",</span><br><span style="color: hsl(120, 100%, 40%);">+     "STS",</span><br><span style="color: hsl(120, 100%, 40%);">+      "UNIT",</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static int compare_civicaddr_codes(const void *_a, const void *_b)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+        /* See the man page for qsort(3) for an explanation of the casts */</span><br><span style="color: hsl(120, 100%, 40%);">+   int rc = strcmp(*(const char **)_a, *(const char **)_b);</span><br><span style="color: hsl(120, 100%, 40%);">+      return rc;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+int ast_geoloc_civicaddr_is_code_valid(const char *code)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  const char **entry = bsearch(&code, addr_code_name_entries, ARRAY_LEN(addr_code_name_entries),</span><br><span style="color: hsl(120, 100%, 40%);">+            sizeof(const char *), compare_civicaddr_codes);</span><br><span style="color: hsl(120, 100%, 40%);">+       return (entry != NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+enum ast_geoloc_validate_result ast_geoloc_civicaddr_validate_varlist(</span><br><span style="color: hsl(120, 100%, 40%);">+  const struct ast_variable *varlist,     const char **result)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+       const struct ast_variable *var = varlist;</span><br><span style="color: hsl(120, 100%, 40%);">+     for (; var; var = var->next) {</span><br><span style="color: hsl(120, 100%, 40%);">+             int valid = ast_geoloc_civicaddr_is_code_valid(var->name);</span><br><span style="color: hsl(120, 100%, 40%);">+         if (!valid) {</span><br><span style="color: hsl(120, 100%, 40%);">+                 *result = var->name;</span><br><span style="color: hsl(120, 100%, 40%);">+                       return AST_GEOLOC_VALIDATE_INVALID_VARNAME;</span><br><span style="color: hsl(120, 100%, 40%);">+           }</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+     return AST_GEOLOC_VALIDATE_SUCCESS;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct ast_xml_node *geoloc_civicaddr_list_to_xml(const struct ast_variable *resolved_location,</span><br><span style="color: hsl(120, 100%, 40%);">+     const char *ref_string)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+    char *lang = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+    char *s = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+       struct ast_variable *var;</span><br><span style="color: hsl(120, 100%, 40%);">+     struct ast_xml_node *ca_node;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct ast_xml_node *child_node;</span><br><span style="color: hsl(120, 100%, 40%);">+      int rc = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+   SCOPE_ENTER(3, "%s", ref_string);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ lang = (char *)ast_variable_find_in_list(resolved_location, "lang");</span><br><span style="color: hsl(120, 100%, 40%);">+        if (ast_strlen_zero(lang)) {</span><br><span style="color: hsl(120, 100%, 40%);">+          lang = ast_strdupa(ast_defaultlanguage);</span><br><span style="color: hsl(120, 100%, 40%);">+              for (s = lang; *s; s++) {</span><br><span style="color: hsl(120, 100%, 40%);">+                     if (*s == '_') {</span><br><span style="color: hsl(120, 100%, 40%);">+                              *s = '-';</span><br><span style="color: hsl(120, 100%, 40%);">+                     }</span><br><span style="color: hsl(120, 100%, 40%);">+             }</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   ca_node = ast_xml_new_node("civicAddress");</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!ca_node) {</span><br><span style="color: hsl(120, 100%, 40%);">+               SCOPE_EXIT_LOG_RTN_VALUE(NULL, LOG_ERROR, "%s: Unable to create 'civicAddress' XML node\n", ref_string);</span><br><span style="color: hsl(120, 100%, 40%);">+    }</span><br><span style="color: hsl(120, 100%, 40%);">+     rc = ast_xml_set_attribute(ca_node, "lang", lang);</span><br><span style="color: hsl(120, 100%, 40%);">+  if (rc != 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+                ast_xml_free_node(ca_node);</span><br><span style="color: hsl(120, 100%, 40%);">+           SCOPE_EXIT_LOG_RTN_VALUE(NULL, LOG_ERROR, "%s: Unable to create 'lang' XML attribute\n", ref_string);</span><br><span style="color: hsl(120, 100%, 40%);">+       }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   for (var = (struct ast_variable *)resolved_location; var; var = var->next) {</span><br><span style="color: hsl(120, 100%, 40%);">+               if (ast_strings_equal(var->name, "lang")) {</span><br><span style="color: hsl(120, 100%, 40%);">+                      continue;</span><br><span style="color: hsl(120, 100%, 40%);">+             }</span><br><span style="color: hsl(120, 100%, 40%);">+             child_node = ast_xml_new_child(ca_node, var->name);</span><br><span style="color: hsl(120, 100%, 40%);">+                if (!child_node) {</span><br><span style="color: hsl(120, 100%, 40%);">+                    ast_xml_free_node(ca_node);</span><br><span style="color: hsl(120, 100%, 40%);">+                   SCOPE_EXIT_LOG_RTN_VALUE(NULL, LOG_ERROR, "%s: Unable to create '%s' XML node\n", var->name, ref_string);</span><br><span style="color: hsl(120, 100%, 40%);">+                }</span><br><span style="color: hsl(120, 100%, 40%);">+             ast_xml_set_text(child_node, var->value);</span><br><span style="color: hsl(120, 100%, 40%);">+  }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   SCOPE_EXIT_RTN_VALUE(ca_node, "%s: Done\n", ref_string);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+int geoloc_civicaddr_unload(void)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ return AST_MODULE_LOAD_SUCCESS;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+int geoloc_civicaddr_load(void)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+      qsort(addr_code_name_entries, ARRAY_LEN(addr_code_name_entries), sizeof(const char *),</span><br><span style="color: hsl(120, 100%, 40%);">+                compare_civicaddr_codes);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   return AST_MODULE_LOAD_SUCCESS;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+int geoloc_civicaddr_reload(void)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+    return AST_MODULE_LOAD_SUCCESS;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span>diff --git a/res/res_geolocation/geoloc_common.c b/res/res_geolocation/geoloc_common.c</span><br><span>new file mode 100644</span><br><span>index 0000000..bb24a31</span><br><span>--- /dev/null</span><br><span>+++ b/res/res_geolocation/geoloc_common.c</span><br><span>@@ -0,0 +1,36 @@</span><br><span style="color: hsl(120, 100%, 40%);">+/*</span><br><span style="color: hsl(120, 100%, 40%);">+ * Asterisk -- An open source telephony toolkit.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * Copyright (C) 2022, Sangoma Technologies Corporation</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * George Joseph <gjoseph@sangoma.com></span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * See http://www.asterisk.org for more information about</span><br><span style="color: hsl(120, 100%, 40%);">+ * the Asterisk project. Please do not directly contact</span><br><span style="color: hsl(120, 100%, 40%);">+ * any of the maintainers of this project for assistance;</span><br><span style="color: hsl(120, 100%, 40%);">+ * the project provides a web site, mailing lists and IRC</span><br><span style="color: hsl(120, 100%, 40%);">+ * channels for your use.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * This program is free software, distributed under the terms of</span><br><span style="color: hsl(120, 100%, 40%);">+ * the GNU General Public License Version 2. See the LICENSE file</span><br><span style="color: hsl(120, 100%, 40%);">+ * at the top of the source tree.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include "asterisk.h"</span><br><span style="color: hsl(120, 100%, 40%);">+#include "geoloc_private.h"</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static const char *result_names[] = {</span><br><span style="color: hsl(120, 100%, 40%);">+  "Success",</span><br><span style="color: hsl(120, 100%, 40%);">+  "Missing type",</span><br><span style="color: hsl(120, 100%, 40%);">+     "Invalid shape type",</span><br><span style="color: hsl(120, 100%, 40%);">+       "Invalid variable name",</span><br><span style="color: hsl(120, 100%, 40%);">+    "Not enough variables",</span><br><span style="color: hsl(120, 100%, 40%);">+     "Too many variables",</span><br><span style="color: hsl(120, 100%, 40%);">+       "Invalid variable value"</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+const char *ast_geoloc_validate_result_to_str(enum ast_geoloc_validate_result result)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+    return result_names[result];</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>diff --git a/res/res_geolocation/geoloc_config.c b/res/res_geolocation/geoloc_config.c</span><br><span>new file mode 100644</span><br><span>index 0000000..33cd333</span><br><span>--- /dev/null</span><br><span>+++ b/res/res_geolocation/geoloc_config.c</span><br><span>@@ -0,0 +1,641 @@</span><br><span style="color: hsl(120, 100%, 40%);">+/*</span><br><span style="color: hsl(120, 100%, 40%);">+ * Asterisk -- An open source telephony toolkit.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * Copyright (C) 2022, Sangoma Technologies Corporation</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * George Joseph <gjoseph@sangoma.com></span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * See http://www.asterisk.org for more information about</span><br><span style="color: hsl(120, 100%, 40%);">+ * the Asterisk project. Please do not directly contact</span><br><span style="color: hsl(120, 100%, 40%);">+ * any of the maintainers of this project for assistance;</span><br><span style="color: hsl(120, 100%, 40%);">+ * the project provides a web site, mailing lists and IRC</span><br><span style="color: hsl(120, 100%, 40%);">+ * channels for your use.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * This program is free software, distributed under the terms of</span><br><span style="color: hsl(120, 100%, 40%);">+ * the GNU General Public License Version 2. See the LICENSE file</span><br><span style="color: hsl(120, 100%, 40%);">+ * at the top of the source tree.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include "asterisk.h"</span><br><span style="color: hsl(120, 100%, 40%);">+#include "asterisk/module.h"</span><br><span style="color: hsl(120, 100%, 40%);">+#include "asterisk/cli.h"</span><br><span style="color: hsl(120, 100%, 40%);">+#define AST_API_MODULE</span><br><span style="color: hsl(120, 100%, 40%);">+#include "geoloc_private.h"</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static struct ast_sorcery *geoloc_sorcery;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static const char *pidf_element_names[] = {</span><br><span style="color: hsl(120, 100%, 40%);">+ "<none>",</span><br><span style="color: hsl(120, 100%, 40%);">+     "tuple",</span><br><span style="color: hsl(120, 100%, 40%);">+    "device",</span><br><span style="color: hsl(120, 100%, 40%);">+   "person"</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static const char *format_names[] = {</span><br><span style="color: hsl(120, 100%, 40%);">+       "<none>",</span><br><span style="color: hsl(120, 100%, 40%);">+     "civicAddress",</span><br><span style="color: hsl(120, 100%, 40%);">+     "GML",</span><br><span style="color: hsl(120, 100%, 40%);">+      "URI",</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static const char * action_names[] = {</span><br><span style="color: hsl(120, 100%, 40%);">+        "prefer_incoming",</span><br><span style="color: hsl(120, 100%, 40%);">+  "prefer_config",</span><br><span style="color: hsl(120, 100%, 40%);">+    "discard_incoming",</span><br><span style="color: hsl(120, 100%, 40%);">+ "discard_config",</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+CONFIG_ENUM(location, format)</span><br><span style="color: hsl(120, 100%, 40%);">+CONFIG_VAR_LIST(location, location_info)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static void geoloc_location_destructor(void *obj) {</span><br><span style="color: hsl(120, 100%, 40%);">+     struct ast_geoloc_location *location = obj;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_string_field_free_memory(location);</span><br><span style="color: hsl(120, 100%, 40%);">+       ast_variables_destroy(location->location_info);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static void *geoloc_location_alloc(const char *name)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+      struct ast_geoloc_location *location = ast_sorcery_generic_alloc(sizeof(struct ast_geoloc_location), geoloc_location_destructor);</span><br><span style="color: hsl(120, 100%, 40%);">+     if (location) {</span><br><span style="color: hsl(120, 100%, 40%);">+               ast_string_field_init(location, 128);</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   return location;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+CONFIG_ENUM(profile, pidf_element)</span><br><span style="color: hsl(120, 100%, 40%);">+CONFIG_ENUM(profile, action)</span><br><span style="color: hsl(120, 100%, 40%);">+CONFIG_VAR_LIST(profile, location_refinement)</span><br><span style="color: hsl(120, 100%, 40%);">+CONFIG_VAR_LIST(profile, location_variables)</span><br><span style="color: hsl(120, 100%, 40%);">+CONFIG_VAR_LIST(profile, usage_rules)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static void geoloc_profile_destructor(void *obj) {</span><br><span style="color: hsl(120, 100%, 40%);">+   struct ast_geoloc_profile *profile = obj;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   ast_string_field_free_memory(profile);</span><br><span style="color: hsl(120, 100%, 40%);">+        ast_variables_destroy(profile->location_refinement);</span><br><span style="color: hsl(120, 100%, 40%);">+       ast_variables_destroy(profile->location_variables);</span><br><span style="color: hsl(120, 100%, 40%);">+        ast_variables_destroy(profile->usage_rules);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static void *geoloc_profile_alloc(const char *name)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  struct ast_geoloc_profile *profile = ast_sorcery_generic_alloc(sizeof(*profile), geoloc_profile_destructor);</span><br><span style="color: hsl(120, 100%, 40%);">+  if (profile) {</span><br><span style="color: hsl(120, 100%, 40%);">+                ast_string_field_init(profile, 128);</span><br><span style="color: hsl(120, 100%, 40%);">+  }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   return profile;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static int geoloc_location_apply_handler(const struct ast_sorcery *sorcery, void *obj)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+       struct ast_geoloc_location *location = obj;</span><br><span style="color: hsl(120, 100%, 40%);">+   const char *location_id = ast_sorcery_object_get_id(location);</span><br><span style="color: hsl(120, 100%, 40%);">+        const char *failed;</span><br><span style="color: hsl(120, 100%, 40%);">+   const char *uri;</span><br><span style="color: hsl(120, 100%, 40%);">+      enum ast_geoloc_validate_result result;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     switch (location->format) {</span><br><span style="color: hsl(120, 100%, 40%);">+        case AST_GEOLOC_FORMAT_NONE:</span><br><span style="color: hsl(120, 100%, 40%);">+  case AST_GEOLOC_FORMAT_LAST:</span><br><span style="color: hsl(120, 100%, 40%);">+          ast_log(LOG_ERROR, "Location '%s' must have a format\n", location_id);</span><br><span style="color: hsl(120, 100%, 40%);">+              return -1;</span><br><span style="color: hsl(120, 100%, 40%);">+    case AST_GEOLOC_FORMAT_CIVIC_ADDRESS:</span><br><span style="color: hsl(120, 100%, 40%);">+         result = ast_geoloc_civicaddr_validate_varlist(location->location_info, &failed);</span><br><span style="color: hsl(120, 100%, 40%);">+              if (result != AST_GEOLOC_VALIDATE_SUCCESS) {</span><br><span style="color: hsl(120, 100%, 40%);">+                  ast_log(LOG_ERROR, "Location '%s' has invalid item '%s' in the location\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                         location_id, failed);</span><br><span style="color: hsl(120, 100%, 40%);">+                 return -1;</span><br><span style="color: hsl(120, 100%, 40%);">+            }</span><br><span style="color: hsl(120, 100%, 40%);">+             break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case AST_GEOLOC_FORMAT_GML:</span><br><span style="color: hsl(120, 100%, 40%);">+           result = ast_geoloc_gml_validate_varlist(location->location_info, &failed);</span><br><span style="color: hsl(120, 100%, 40%);">+            if (result != AST_GEOLOC_VALIDATE_SUCCESS) {</span><br><span style="color: hsl(120, 100%, 40%);">+                  ast_log(LOG_ERROR, "%s for item '%s' in location '%s'\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                           ast_geoloc_validate_result_to_str(result),      failed, location_id);</span><br><span style="color: hsl(120, 100%, 40%);">+                 return -1;</span><br><span style="color: hsl(120, 100%, 40%);">+            }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+           break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case AST_GEOLOC_FORMAT_URI:</span><br><span style="color: hsl(120, 100%, 40%);">+           uri = ast_variable_find_in_list(location->location_info, "URI");</span><br><span style="color: hsl(120, 100%, 40%);">+         if (!uri) {</span><br><span style="color: hsl(120, 100%, 40%);">+                   struct ast_str *str = ast_variable_list_join(location->location_info, ",", "=", "\"", NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+                  ast_log(LOG_ERROR, "Geolocation location '%s' format is set to '%s' but no 'URI' was found in location parameter '%s'\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                           location_id, format_names[AST_GEOLOC_FORMAT_URI], ast_str_buffer(str));</span><br><span style="color: hsl(120, 100%, 40%);">+                       ast_free(str);</span><br><span style="color: hsl(120, 100%, 40%);">+                        return -1;</span><br><span style="color: hsl(120, 100%, 40%);">+            }</span><br><span style="color: hsl(120, 100%, 40%);">+             break;</span><br><span style="color: hsl(120, 100%, 40%);">+        }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   if (!ast_strlen_zero(location->location_source)) {</span><br><span style="color: hsl(120, 100%, 40%);">+         struct ast_sockaddr loc_source_addr;</span><br><span style="color: hsl(120, 100%, 40%);">+          int rc = ast_sockaddr_parse(&loc_source_addr, location->location_source, PARSE_PORT_FORBID);</span><br><span style="color: hsl(120, 100%, 40%);">+           if (rc == 1) {</span><br><span style="color: hsl(120, 100%, 40%);">+                        ast_log(LOG_ERROR, "Geolocation location '%s' location_source '%s' must be a FQDN."</span><br><span style="color: hsl(120, 100%, 40%);">+                         " RFC8787 expressly forbids IP addresses.\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                               location_id, location->location_source);</span><br><span style="color: hsl(120, 100%, 40%);">+                   return -1;</span><br><span style="color: hsl(120, 100%, 40%);">+            }</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static int geoloc_profile_apply_handler(const struct ast_sorcery *sorcery, void *obj)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+      struct ast_geoloc_profile *profile = obj;</span><br><span style="color: hsl(120, 100%, 40%);">+     struct ast_geoloc_location *location;</span><br><span style="color: hsl(120, 100%, 40%);">+ const char *profile_id = ast_sorcery_object_get_id(profile);</span><br><span style="color: hsl(120, 100%, 40%);">+  const char *failed;</span><br><span style="color: hsl(120, 100%, 40%);">+   enum ast_geoloc_validate_result result;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     if (ast_strlen_zero(profile->location_reference)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                if (profile->location_refinement ||</span><br><span style="color: hsl(120, 100%, 40%);">+                        profile->location_variables) {</span><br><span style="color: hsl(120, 100%, 40%);">+                     ast_log(LOG_ERROR, "Profile '%s' can't have location_refinement or location_variables without a location_reference",</span><br><span style="color: hsl(120, 100%, 40%);">+                            profile_id);</span><br><span style="color: hsl(120, 100%, 40%);">+                  return -1;</span><br><span style="color: hsl(120, 100%, 40%);">+            }</span><br><span style="color: hsl(120, 100%, 40%);">+             return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   location = ast_sorcery_retrieve_by_id(geoloc_sorcery, "location", profile->location_reference);</span><br><span style="color: hsl(120, 100%, 40%);">+  if (!location) {</span><br><span style="color: hsl(120, 100%, 40%);">+              ast_log(LOG_ERROR, "Profile '%s' has a location_reference '%s' that doesn't exist",</span><br><span style="color: hsl(120, 100%, 40%);">+                     profile_id, profile->location_reference);</span><br><span style="color: hsl(120, 100%, 40%);">+          return -1;</span><br><span style="color: hsl(120, 100%, 40%);">+    }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   if (profile->location_refinement) {</span><br><span style="color: hsl(120, 100%, 40%);">+                switch (location->format) {</span><br><span style="color: hsl(120, 100%, 40%);">+                case AST_GEOLOC_FORMAT_NONE:</span><br><span style="color: hsl(120, 100%, 40%);">+          case AST_GEOLOC_FORMAT_LAST:</span><br><span style="color: hsl(120, 100%, 40%);">+                  break;</span><br><span style="color: hsl(120, 100%, 40%);">+                case AST_GEOLOC_FORMAT_CIVIC_ADDRESS:</span><br><span style="color: hsl(120, 100%, 40%);">+                 result = ast_geoloc_civicaddr_validate_varlist(profile->location_refinement, &failed);</span><br><span style="color: hsl(120, 100%, 40%);">+                 if (result != AST_GEOLOC_VALIDATE_SUCCESS) {</span><br><span style="color: hsl(120, 100%, 40%);">+                          ast_log(LOG_ERROR, "Profile '%s' error: %s: for item '%s' in the location_refinement\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                                    profile_id,     ast_geoloc_validate_result_to_str(result), failed);</span><br><span style="color: hsl(120, 100%, 40%);">+                           ao2_ref(location, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+                                return -1;</span><br><span style="color: hsl(120, 100%, 40%);">+                    }</span><br><span style="color: hsl(120, 100%, 40%);">+                     break;</span><br><span style="color: hsl(120, 100%, 40%);">+                case AST_GEOLOC_FORMAT_GML:</span><br><span style="color: hsl(120, 100%, 40%);">+                   break;</span><br><span style="color: hsl(120, 100%, 40%);">+                case AST_GEOLOC_FORMAT_URI:</span><br><span style="color: hsl(120, 100%, 40%);">+                   break;</span><br><span style="color: hsl(120, 100%, 40%);">+                }</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+     ao2_ref(location, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct ast_sorcery *geoloc_get_sorcery(void)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+       ast_sorcery_ref(geoloc_sorcery);</span><br><span style="color: hsl(120, 100%, 40%);">+      return geoloc_sorcery;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static char *geoloc_config_list_locations(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+   struct ao2_iterator iter;</span><br><span style="color: hsl(120, 100%, 40%);">+     struct ao2_container *sorted_container;</span><br><span style="color: hsl(120, 100%, 40%);">+       struct ao2_container *unsorted_container;</span><br><span style="color: hsl(120, 100%, 40%);">+     struct ast_geoloc_location *loc;</span><br><span style="color: hsl(120, 100%, 40%);">+      int using_regex = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+  char *result = CLI_SUCCESS;</span><br><span style="color: hsl(120, 100%, 40%);">+   int ret = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+  char *format_name;</span><br><span style="color: hsl(120, 100%, 40%);">+    int count = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      switch (cmd) {</span><br><span style="color: hsl(120, 100%, 40%);">+        case CLI_INIT:</span><br><span style="color: hsl(120, 100%, 40%);">+                e->command = "geoloc list locations";</span><br><span style="color: hsl(120, 100%, 40%);">+            e->usage = "Usage: geoloc list locations [ like <pattern> ]\n"</span><br><span style="color: hsl(120, 100%, 40%);">+                         "      List Geolocation Location Objects\n";</span><br><span style="color: hsl(120, 100%, 40%);">+            return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+  case CLI_GENERATE:</span><br><span style="color: hsl(120, 100%, 40%);">+            return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+  }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   if (a->argc != 3 && a->argc != 5) {</span><br><span style="color: hsl(120, 100%, 40%);">+             return CLI_SHOWUSAGE;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   if (a->argc == 5) {</span><br><span style="color: hsl(120, 100%, 40%);">+                if (strcasecmp(a->argv[3], "like")) {</span><br><span style="color: hsl(120, 100%, 40%);">+                    return CLI_SHOWUSAGE;</span><br><span style="color: hsl(120, 100%, 40%);">+         }</span><br><span style="color: hsl(120, 100%, 40%);">+             using_regex = 1;</span><br><span style="color: hsl(120, 100%, 40%);">+      }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   sorted_container = ao2_container_alloc_rbtree(AO2_ALLOC_OPT_LOCK_NOLOCK, 0,</span><br><span style="color: hsl(120, 100%, 40%);">+           ast_sorcery_object_id_sort, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+    if (!sorted_container) {</span><br><span style="color: hsl(120, 100%, 40%);">+              ast_cli(a->fd, "Geolocation Location Objects: Unable to allocate temporary container\n");</span><br><span style="color: hsl(120, 100%, 40%);">+                return CLI_FAILURE;</span><br><span style="color: hsl(120, 100%, 40%);">+   }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   /* Get a sorted snapshot of the scheduled tasks */</span><br><span style="color: hsl(120, 100%, 40%);">+    if (using_regex) {</span><br><span style="color: hsl(120, 100%, 40%);">+            unsorted_container = ast_sorcery_retrieve_by_regex(geoloc_sorcery, "location", a->argv[4]);</span><br><span style="color: hsl(120, 100%, 40%);">+      } else {</span><br><span style="color: hsl(120, 100%, 40%);">+              unsorted_container = ast_sorcery_retrieve_by_fields(geoloc_sorcery, "location",</span><br><span style="color: hsl(120, 100%, 40%);">+                     AST_RETRIEVE_FLAG_MULTIPLE | AST_RETRIEVE_FLAG_ALL, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+    }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   ret = ao2_container_dup(sorted_container, unsorted_container, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+     ao2_ref(unsorted_container, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+      if (ret != 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+               ao2_ref(sorted_container, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+                ast_cli(a->fd, "Geolocation Location Objects: Unable to sort temporary container\n");</span><br><span style="color: hsl(120, 100%, 40%);">+            return CLI_FAILURE;</span><br><span style="color: hsl(120, 100%, 40%);">+   }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   ast_cli(a->fd, "Geolocation Location Objects:\n\n");</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   ast_cli(a->fd,</span><br><span style="color: hsl(120, 100%, 40%);">+             "<Object ID...................................> <Format.....> <Details.............>\n"</span><br><span style="color: hsl(120, 100%, 40%);">+           "===================================================================================\n");</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ iter = ao2_iterator_init(sorted_container, AO2_ITERATOR_UNLINK);</span><br><span style="color: hsl(120, 100%, 40%);">+      for (; (loc = ao2_iterator_next(&iter)); ao2_ref(loc, -1)) {</span><br><span style="color: hsl(120, 100%, 40%);">+              struct ast_str *str;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+                ao2_lock(loc);</span><br><span style="color: hsl(120, 100%, 40%);">+                str = ast_variable_list_join(loc->location_info, ",", "=", "\"", NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+         if (!str) {</span><br><span style="color: hsl(120, 100%, 40%);">+                   ao2_unlock(loc);</span><br><span style="color: hsl(120, 100%, 40%);">+                      ao2_ref(loc, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+                     ast_cli(a->fd, "Geolocation Location Objects: Unable to allocate temp string for '%s'\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                                ast_sorcery_object_get_id(loc));</span><br><span style="color: hsl(120, 100%, 40%);">+                      result = CLI_FAILURE;</span><br><span style="color: hsl(120, 100%, 40%);">+                 break;</span><br><span style="color: hsl(120, 100%, 40%);">+                }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+           format_to_str(loc, NULL, &format_name);</span><br><span style="color: hsl(120, 100%, 40%);">+           ast_cli(a->fd, "%-46.46s %-13s %-s\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                   ast_sorcery_object_get_id(loc),</span><br><span style="color: hsl(120, 100%, 40%);">+                       format_name,</span><br><span style="color: hsl(120, 100%, 40%);">+                  ast_str_buffer(str));</span><br><span style="color: hsl(120, 100%, 40%);">+         ao2_unlock(loc);</span><br><span style="color: hsl(120, 100%, 40%);">+              ast_free(str);</span><br><span style="color: hsl(120, 100%, 40%);">+                ast_free(format_name);</span><br><span style="color: hsl(120, 100%, 40%);">+                count++;</span><br><span style="color: hsl(120, 100%, 40%);">+      }</span><br><span style="color: hsl(120, 100%, 40%);">+     ao2_iterator_destroy(&iter);</span><br><span style="color: hsl(120, 100%, 40%);">+      ao2_ref(sorted_container, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+        ast_cli(a->fd, "\nTotal Location Objects: %d\n\n", count);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     return result;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static char *geoloc_config_list_profiles(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+    struct ao2_iterator iter;</span><br><span style="color: hsl(120, 100%, 40%);">+     struct ao2_container *sorted_container;</span><br><span style="color: hsl(120, 100%, 40%);">+       struct ao2_container *unsorted_container;</span><br><span style="color: hsl(120, 100%, 40%);">+     struct ast_geoloc_profile *profile;</span><br><span style="color: hsl(120, 100%, 40%);">+   int using_regex = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+  char *result = CLI_SUCCESS;</span><br><span style="color: hsl(120, 100%, 40%);">+   int ret = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+  char *action;</span><br><span style="color: hsl(120, 100%, 40%);">+ int count = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      switch (cmd) {</span><br><span style="color: hsl(120, 100%, 40%);">+        case CLI_INIT:</span><br><span style="color: hsl(120, 100%, 40%);">+                e->command = "geoloc list profiles";</span><br><span style="color: hsl(120, 100%, 40%);">+             e->usage = "Usage: geoloc list profiles [ like <pattern> ]\n"</span><br><span style="color: hsl(120, 100%, 40%);">+                          "      List Geolocation Profile Objects\n";</span><br><span style="color: hsl(120, 100%, 40%);">+             return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+  case CLI_GENERATE:</span><br><span style="color: hsl(120, 100%, 40%);">+            return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+  }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   if (a->argc != 3 && a->argc != 5) {</span><br><span style="color: hsl(120, 100%, 40%);">+             return CLI_SHOWUSAGE;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   if (a->argc == 5) {</span><br><span style="color: hsl(120, 100%, 40%);">+                if (strcasecmp(a->argv[3], "like")) {</span><br><span style="color: hsl(120, 100%, 40%);">+                    return CLI_SHOWUSAGE;</span><br><span style="color: hsl(120, 100%, 40%);">+         }</span><br><span style="color: hsl(120, 100%, 40%);">+             using_regex = 1;</span><br><span style="color: hsl(120, 100%, 40%);">+      }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   sorted_container = ao2_container_alloc_rbtree(AO2_ALLOC_OPT_LOCK_NOLOCK, 0,</span><br><span style="color: hsl(120, 100%, 40%);">+           ast_sorcery_object_id_sort, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+    if (!sorted_container) {</span><br><span style="color: hsl(120, 100%, 40%);">+              ast_cli(a->fd, "Geolocation Profile Objects: Unable to allocate temporary container\n");</span><br><span style="color: hsl(120, 100%, 40%);">+         return CLI_FAILURE;</span><br><span style="color: hsl(120, 100%, 40%);">+   }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   /* Get a sorted snapshot of the scheduled tasks */</span><br><span style="color: hsl(120, 100%, 40%);">+    if (using_regex) {</span><br><span style="color: hsl(120, 100%, 40%);">+            unsorted_container = ast_sorcery_retrieve_by_regex(geoloc_sorcery, "profile", a->argv[4]);</span><br><span style="color: hsl(120, 100%, 40%);">+       } else {</span><br><span style="color: hsl(120, 100%, 40%);">+              unsorted_container = ast_sorcery_retrieve_by_fields(geoloc_sorcery, "profile",</span><br><span style="color: hsl(120, 100%, 40%);">+                      AST_RETRIEVE_FLAG_MULTIPLE | AST_RETRIEVE_FLAG_ALL, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+    }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   ret = ao2_container_dup(sorted_container, unsorted_container, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+     ao2_ref(unsorted_container, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+      if (ret != 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+               ao2_ref(sorted_container, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+                ast_cli(a->fd, "Geolocation Profile Objects: Unable to sort temporary container\n");</span><br><span style="color: hsl(120, 100%, 40%);">+             return CLI_FAILURE;</span><br><span style="color: hsl(120, 100%, 40%);">+   }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   ast_cli(a->fd, "Geolocation Profile Objects:\n\n");</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    ast_cli(a->fd,</span><br><span style="color: hsl(120, 100%, 40%);">+             "<Object ID...................................> <Profile Action> <Location Reference> \n"</span><br><span style="color: hsl(120, 100%, 40%);">+         "=====================================================================================\n");</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       iter = ao2_iterator_init(sorted_container, AO2_ITERATOR_UNLINK);</span><br><span style="color: hsl(120, 100%, 40%);">+      for (; (profile = ao2_iterator_next(&iter)); ao2_ref(profile, -1)) {</span><br><span style="color: hsl(120, 100%, 40%);">+              ao2_lock(profile);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+          action_to_str(profile, NULL, &action);</span><br><span style="color: hsl(120, 100%, 40%);">+            ast_cli(a->fd, "%-46.46s %-16s %-s\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                   ast_sorcery_object_get_id(profile),</span><br><span style="color: hsl(120, 100%, 40%);">+                   action,</span><br><span style="color: hsl(120, 100%, 40%);">+                       profile->location_reference);</span><br><span style="color: hsl(120, 100%, 40%);">+              ao2_unlock(profile);</span><br><span style="color: hsl(120, 100%, 40%);">+          ast_free(action);</span><br><span style="color: hsl(120, 100%, 40%);">+             count++;</span><br><span style="color: hsl(120, 100%, 40%);">+      }</span><br><span style="color: hsl(120, 100%, 40%);">+     ao2_iterator_destroy(&iter);</span><br><span style="color: hsl(120, 100%, 40%);">+      ao2_ref(sorted_container, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+        ast_cli(a->fd, "\nTotal Profile Objects: %d\n\n", count);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      return result;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static char *geoloc_config_show_profiles(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+    struct ao2_iterator iter;</span><br><span style="color: hsl(120, 100%, 40%);">+     struct ao2_container *sorted_container;</span><br><span style="color: hsl(120, 100%, 40%);">+       struct ao2_container *unsorted_container;</span><br><span style="color: hsl(120, 100%, 40%);">+     struct ast_geoloc_profile *profile;</span><br><span style="color: hsl(120, 100%, 40%);">+   int using_regex = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+  char *result = CLI_SUCCESS;</span><br><span style="color: hsl(120, 100%, 40%);">+   int ret = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+  int count = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      switch (cmd) {</span><br><span style="color: hsl(120, 100%, 40%);">+        case CLI_INIT:</span><br><span style="color: hsl(120, 100%, 40%);">+                e->command = "geoloc show profiles";</span><br><span style="color: hsl(120, 100%, 40%);">+             e->usage = "Usage: geoloc show profiles [ like <pattern> ]\n"</span><br><span style="color: hsl(120, 100%, 40%);">+                          "      List Geolocation Profile Objects\n";</span><br><span style="color: hsl(120, 100%, 40%);">+             return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+  case CLI_GENERATE:</span><br><span style="color: hsl(120, 100%, 40%);">+            return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+  }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   if (a->argc != 3 && a->argc != 5) {</span><br><span style="color: hsl(120, 100%, 40%);">+             return CLI_SHOWUSAGE;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   if (a->argc == 5) {</span><br><span style="color: hsl(120, 100%, 40%);">+                if (strcasecmp(a->argv[3], "like")) {</span><br><span style="color: hsl(120, 100%, 40%);">+                    return CLI_SHOWUSAGE;</span><br><span style="color: hsl(120, 100%, 40%);">+         }</span><br><span style="color: hsl(120, 100%, 40%);">+             using_regex = 1;</span><br><span style="color: hsl(120, 100%, 40%);">+      }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   /* Create an empty rb-tree container which always sorts its contents. */</span><br><span style="color: hsl(120, 100%, 40%);">+      sorted_container = ao2_container_alloc_rbtree(AO2_ALLOC_OPT_LOCK_NOLOCK, 0,</span><br><span style="color: hsl(120, 100%, 40%);">+           ast_sorcery_object_id_sort, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+    if (!sorted_container) {</span><br><span style="color: hsl(120, 100%, 40%);">+              ast_cli(a->fd, "Geolocation Profile Objects: Unable to allocate temporary container\n");</span><br><span style="color: hsl(120, 100%, 40%);">+         return CLI_FAILURE;</span><br><span style="color: hsl(120, 100%, 40%);">+   }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   /* Get an unsorted list of profile parameters */</span><br><span style="color: hsl(120, 100%, 40%);">+      if (using_regex) {</span><br><span style="color: hsl(120, 100%, 40%);">+            unsorted_container = ast_sorcery_retrieve_by_regex(geoloc_sorcery, "profile", a->argv[4]);</span><br><span style="color: hsl(120, 100%, 40%);">+       } else {</span><br><span style="color: hsl(120, 100%, 40%);">+              unsorted_container = ast_sorcery_retrieve_by_fields(geoloc_sorcery, "profile",</span><br><span style="color: hsl(120, 100%, 40%);">+                      AST_RETRIEVE_FLAG_MULTIPLE | AST_RETRIEVE_FLAG_ALL, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+    }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   /* Copy the unsorted parameters into the rb-tree container which will sort them automatically. */</span><br><span style="color: hsl(120, 100%, 40%);">+     ret = ao2_container_dup(sorted_container, unsorted_container, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+     ao2_ref(unsorted_container, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+      if (ret != 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+               ao2_ref(sorted_container, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+                ast_cli(a->fd, "Geolocation Profile Objects: Unable to sort temporary container\n");</span><br><span style="color: hsl(120, 100%, 40%);">+             return CLI_FAILURE;</span><br><span style="color: hsl(120, 100%, 40%);">+   }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   ast_cli(a->fd, "Geolocation Profile Objects:\n\n");</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    iter = ao2_iterator_init(sorted_container, AO2_ITERATOR_UNLINK);</span><br><span style="color: hsl(120, 100%, 40%);">+      for (; (profile = ao2_iterator_next(&iter)); ) {</span><br><span style="color: hsl(120, 100%, 40%);">+          char *action = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+          struct ast_str *loc_str = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+               struct ast_str *refinement_str = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+                struct ast_str *variables_str = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+         struct ast_str *resolved_str = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+          struct ast_str *usage_rules_str = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+               struct ast_geoloc_eprofile *eprofile = ast_geoloc_eprofile_create_from_profile(profile);</span><br><span style="color: hsl(120, 100%, 40%);">+              ao2_ref(profile, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+               if (!ast_strlen_zero(eprofile->location_reference)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                      loc_str = ast_variable_list_join(eprofile->location_info, ",", "=", "\"", NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+                        resolved_str = ast_variable_list_join(eprofile->effective_location, ",", "=", "\"", NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+              }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+           refinement_str = ast_variable_list_join(eprofile->location_refinement, ",", "=", "\"", NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+           variables_str = ast_variable_list_join(eprofile->location_variables, ",", "=", "\"", NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+             usage_rules_str = ast_variable_list_join(eprofile->usage_rules, ",", "=", "\"", NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+                action_to_str(eprofile, NULL, &action);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+         ast_cli(a->fd,</span><br><span style="color: hsl(120, 100%, 40%);">+                     "id:                   %-s\n"</span><br><span style="color: hsl(120, 100%, 40%);">+                       "profile_action:       %-s\n"</span><br><span style="color: hsl(120, 100%, 40%);">+                       "pidf_element:         %-s\n"</span><br><span style="color: hsl(120, 100%, 40%);">+                       "location_reference:   %-s\n"</span><br><span style="color: hsl(120, 100%, 40%);">+                       "Location_format:      %-s\n"</span><br><span style="color: hsl(120, 100%, 40%);">+                       "location_details:     %-s\n"</span><br><span style="color: hsl(120, 100%, 40%);">+                       "location_method:      %-s\n"</span><br><span style="color: hsl(120, 100%, 40%);">+                       "location_refinement:  %-s\n"</span><br><span style="color: hsl(120, 100%, 40%);">+                       "location_variables:   %-s\n"</span><br><span style="color: hsl(120, 100%, 40%);">+                       "effective_location:   %-s\n"</span><br><span style="color: hsl(120, 100%, 40%);">+                       "usage_rules:          %-s\n"</span><br><span style="color: hsl(120, 100%, 40%);">+                       "notes:                %-s\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                      eprofile->id,</span><br><span style="color: hsl(120, 100%, 40%);">+                      action,</span><br><span style="color: hsl(120, 100%, 40%);">+                       pidf_element_names[eprofile->pidf_element],</span><br><span style="color: hsl(120, 100%, 40%);">+                        S_OR(eprofile->location_reference, "<none>"),</span><br><span style="color: hsl(120, 100%, 40%);">+                      format_names[eprofile->format],</span><br><span style="color: hsl(120, 100%, 40%);">+                    S_COR(loc_str, ast_str_buffer(loc_str), "<none>"),</span><br><span style="color: hsl(120, 100%, 40%);">+                    S_OR(eprofile->method, "<none>"),</span><br><span style="color: hsl(120, 100%, 40%);">+                  S_COR(refinement_str, ast_str_buffer(refinement_str), "<none>"),</span><br><span style="color: hsl(120, 100%, 40%);">+                      S_COR(variables_str, ast_str_buffer(variables_str), "<none>"),</span><br><span style="color: hsl(120, 100%, 40%);">+                        S_COR(resolved_str, ast_str_buffer(resolved_str), "<none>"),</span><br><span style="color: hsl(120, 100%, 40%);">+                  S_COR(usage_rules_str, ast_str_buffer(usage_rules_str), "<none>"),</span><br><span style="color: hsl(120, 100%, 40%);">+                    S_OR(eprofile->notes, "<none>")</span><br><span style="color: hsl(120, 100%, 40%);">+                    );</span><br><span style="color: hsl(120, 100%, 40%);">+            ao2_ref(eprofile, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+              ast_free(action);</span><br><span style="color: hsl(120, 100%, 40%);">+             ast_free(loc_str);</span><br><span style="color: hsl(120, 100%, 40%);">+            ast_free(refinement_str);</span><br><span style="color: hsl(120, 100%, 40%);">+             ast_free(variables_str);</span><br><span style="color: hsl(120, 100%, 40%);">+              ast_free(resolved_str);</span><br><span style="color: hsl(120, 100%, 40%);">+               ast_free(usage_rules_str);</span><br><span style="color: hsl(120, 100%, 40%);">+            count++;</span><br><span style="color: hsl(120, 100%, 40%);">+      }</span><br><span style="color: hsl(120, 100%, 40%);">+     ao2_iterator_destroy(&iter);</span><br><span style="color: hsl(120, 100%, 40%);">+      ao2_ref(sorted_container, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+        ast_cli(a->fd, "\nTotal Profile Objects: %d\n\n", count);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      return result;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static char *geoloc_config_cli_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+       char *result = CLI_SUCCESS;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ switch (cmd) {</span><br><span style="color: hsl(120, 100%, 40%);">+        case CLI_INIT:</span><br><span style="color: hsl(120, 100%, 40%);">+                e->command = "geoloc reload";</span><br><span style="color: hsl(120, 100%, 40%);">+            e->usage = "Usage: geoloc reload\n"</span><br><span style="color: hsl(120, 100%, 40%);">+                          "      Reload Geolocation Configuration\n";</span><br><span style="color: hsl(120, 100%, 40%);">+             return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+  case CLI_GENERATE:</span><br><span style="color: hsl(120, 100%, 40%);">+            return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+  }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   if (a->argc != 2) {</span><br><span style="color: hsl(120, 100%, 40%);">+                return CLI_SHOWUSAGE;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   geoloc_config_reload();</span><br><span style="color: hsl(120, 100%, 40%);">+       ast_cli(a->fd, "Geolocation Configuration reloaded.\n");</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       return result;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static struct ast_cli_entry geoloc_location_cli_commands[] = {</span><br><span style="color: hsl(120, 100%, 40%);">+   AST_CLI_DEFINE(geoloc_config_list_locations, "List Geolocation Location Objects"),</span><br><span style="color: hsl(120, 100%, 40%);">+  AST_CLI_DEFINE(geoloc_config_list_profiles, "List Geolocation Profile Objects"),</span><br><span style="color: hsl(120, 100%, 40%);">+    AST_CLI_DEFINE(geoloc_config_show_profiles, "Show Geolocation Profile Objects"),</span><br><span style="color: hsl(120, 100%, 40%);">+    AST_CLI_DEFINE(geoloc_config_cli_reload, "Reload Geolocation Configuration"),</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct ast_geoloc_location * AST_OPTIONAL_API_NAME(ast_geoloc_get_location)(const char *id)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ if (ast_strlen_zero(id)) {</span><br><span style="color: hsl(120, 100%, 40%);">+            return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+  }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   return ast_sorcery_retrieve_by_id(geoloc_sorcery, "location", id);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct ast_geoloc_profile * AST_OPTIONAL_API_NAME(ast_geoloc_get_profile)(const char *id)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+       if (ast_strlen_zero(id)) {</span><br><span style="color: hsl(120, 100%, 40%);">+            return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+  }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   return ast_sorcery_retrieve_by_id(geoloc_sorcery, "profile", id);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+int geoloc_config_reload(void)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+   if (geoloc_sorcery) {</span><br><span style="color: hsl(120, 100%, 40%);">+         ast_sorcery_reload(geoloc_sorcery);</span><br><span style="color: hsl(120, 100%, 40%);">+   }</span><br><span style="color: hsl(120, 100%, 40%);">+     return AST_MODULE_LOAD_SUCCESS;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+int geoloc_config_unload(void)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+       ast_cli_unregister_multiple(geoloc_location_cli_commands, ARRAY_LEN(geoloc_location_cli_commands));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_sorcery_object_unregister(geoloc_sorcery, "profile");</span><br><span style="color: hsl(120, 100%, 40%);">+   ast_sorcery_object_unregister(geoloc_sorcery, "location");</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        if (geoloc_sorcery) {</span><br><span style="color: hsl(120, 100%, 40%);">+         ast_sorcery_unref(geoloc_sorcery);</span><br><span style="color: hsl(120, 100%, 40%);">+    }</span><br><span style="color: hsl(120, 100%, 40%);">+     geoloc_sorcery = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+int geoloc_config_load(void)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+       if (!(geoloc_sorcery = ast_sorcery_open())) {</span><br><span style="color: hsl(120, 100%, 40%);">+         ast_log(LOG_ERROR, "Failed to open geolocation sorcery\n");</span><br><span style="color: hsl(120, 100%, 40%);">+         return AST_MODULE_LOAD_DECLINE;</span><br><span style="color: hsl(120, 100%, 40%);">+       }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   ast_sorcery_apply_default(geoloc_sorcery, "location", "config", "geolocation.conf,criteria=type=location");</span><br><span style="color: hsl(120, 100%, 40%);">+     if (ast_sorcery_object_register(geoloc_sorcery, "location", geoloc_location_alloc, NULL, geoloc_location_apply_handler)) {</span><br><span style="color: hsl(120, 100%, 40%);">+          ast_log(LOG_ERROR, "Failed to register geoloc location object with sorcery\n");</span><br><span style="color: hsl(120, 100%, 40%);">+             ast_sorcery_unref(geoloc_sorcery);</span><br><span style="color: hsl(120, 100%, 40%);">+            geoloc_sorcery = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+                return AST_MODULE_LOAD_DECLINE;</span><br><span style="color: hsl(120, 100%, 40%);">+       }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   ast_sorcery_object_field_register(geoloc_sorcery, "location", "type", "", OPT_NOOP_T, 0, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+    ast_sorcery_object_field_register_custom(geoloc_sorcery, "location", "format", AST_GEOLOC_FORMAT_NONE,</span><br><span style="color: hsl(120, 100%, 40%);">+            format_handler, format_to_str, NULL, 0, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+   ast_sorcery_object_field_register_custom(geoloc_sorcery, "location", "location_info", NULL,</span><br><span style="color: hsl(120, 100%, 40%);">+               location_info_handler, location_info_to_str, location_info_dup, 0, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+        ast_sorcery_object_field_register(geoloc_sorcery, "location", "location_source", "", OPT_STRINGFIELD_T,</span><br><span style="color: hsl(120, 100%, 40%);">+         0, STRFLDSET(struct ast_geoloc_location, location_source));</span><br><span style="color: hsl(120, 100%, 40%);">+   ast_sorcery_object_field_register(geoloc_sorcery, "location", "method", "", OPT_STRINGFIELD_T,</span><br><span style="color: hsl(120, 100%, 40%);">+          0, STRFLDSET(struct ast_geoloc_location, method));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        ast_sorcery_apply_default(geoloc_sorcery, "profile", "config", "geolocation.conf,criteria=type=profile");</span><br><span style="color: hsl(120, 100%, 40%);">+       if (ast_sorcery_object_register(geoloc_sorcery, "profile", geoloc_profile_alloc, NULL, geoloc_profile_apply_handler)) {</span><br><span style="color: hsl(120, 100%, 40%);">+             ast_log(LOG_ERROR, "Failed to register geoloc profile object with sorcery\n");</span><br><span style="color: hsl(120, 100%, 40%);">+              ast_sorcery_unref(geoloc_sorcery);</span><br><span style="color: hsl(120, 100%, 40%);">+            geoloc_sorcery = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+                return AST_MODULE_LOAD_DECLINE;</span><br><span style="color: hsl(120, 100%, 40%);">+       }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   ast_sorcery_object_field_register(geoloc_sorcery, "profile", "type", "", OPT_NOOP_T, 0, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+     ast_sorcery_object_field_register_custom(geoloc_sorcery, "profile", "pidf_element",</span><br><span style="color: hsl(120, 100%, 40%);">+               pidf_element_names[AST_PIDF_ELEMENT_DEVICE], pidf_element_handler, pidf_element_to_str, NULL, 0, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+  ast_sorcery_object_field_register(geoloc_sorcery, "profile", "location_reference", "", OPT_STRINGFIELD_T,</span><br><span style="color: hsl(120, 100%, 40%);">+               0, STRFLDSET(struct ast_geoloc_profile, location_reference));</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_sorcery_object_field_register_custom(geoloc_sorcery, "profile", "profile_action", "discard_incoming",</span><br><span style="color: hsl(120, 100%, 40%);">+               action_handler, action_to_str, NULL, 0, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+   ast_sorcery_object_field_register_custom(geoloc_sorcery, "profile", "usage_rules", NULL,</span><br><span style="color: hsl(120, 100%, 40%);">+          usage_rules_handler, usage_rules_to_str, usage_rules_dup, 0, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+      ast_sorcery_object_field_register_custom(geoloc_sorcery, "profile", "location_info_refinement", NULL,</span><br><span style="color: hsl(120, 100%, 40%);">+             location_refinement_handler, location_refinement_to_str, location_refinement_dup, 0, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+      ast_sorcery_object_field_register_custom(geoloc_sorcery, "profile", "location_variables", NULL,</span><br><span style="color: hsl(120, 100%, 40%);">+           location_variables_handler, location_variables_to_str, location_variables_dup, 0, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_sorcery_object_field_register(geoloc_sorcery, "profile", "notes", "", OPT_STRINGFIELD_T,</span><br><span style="color: hsl(120, 100%, 40%);">+            0, STRFLDSET(struct ast_geoloc_profile, notes));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    ast_sorcery_load(geoloc_sorcery);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   ast_cli_register_multiple(geoloc_location_cli_commands, ARRAY_LEN(geoloc_location_cli_commands));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   return AST_MODULE_LOAD_SUCCESS;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+int AST_OPTIONAL_API_NAME(ast_geoloc_is_loaded)(void)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+        return 1;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>diff --git a/res/res_geolocation/geoloc_datastore.c b/res/res_geolocation/geoloc_datastore.c</span><br><span>new file mode 100644</span><br><span>index 0000000..040a9bd</span><br><span>--- /dev/null</span><br><span>+++ b/res/res_geolocation/geoloc_datastore.c</span><br><span>@@ -0,0 +1,325 @@</span><br><span style="color: hsl(120, 100%, 40%);">+/*</span><br><span style="color: hsl(120, 100%, 40%);">+ * Asterisk -- An open source telephony toolkit.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * Copyright (C) 2022, Sangoma Technologies Corporation</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * George Joseph <gjoseph@sangoma.com></span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * See http://www.asterisk.org for more information about</span><br><span style="color: hsl(120, 100%, 40%);">+ * the Asterisk project. Please do not directly contact</span><br><span style="color: hsl(120, 100%, 40%);">+ * any of the maintainers of this project for assistance;</span><br><span style="color: hsl(120, 100%, 40%);">+ * the project provides a web site, mailing lists and IRC</span><br><span style="color: hsl(120, 100%, 40%);">+ * channels for your use.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * This program is free software, distributed under the terms of</span><br><span style="color: hsl(120, 100%, 40%);">+ * the GNU General Public License Version 2. See the LICENSE file</span><br><span style="color: hsl(120, 100%, 40%);">+ * at the top of the source tree.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include "asterisk.h"</span><br><span style="color: hsl(120, 100%, 40%);">+#include "asterisk/astobj2.h"</span><br><span style="color: hsl(120, 100%, 40%);">+#include "asterisk/datastore.h"</span><br><span style="color: hsl(120, 100%, 40%);">+#include "asterisk/channel.h"</span><br><span style="color: hsl(120, 100%, 40%);">+#include "asterisk/res_geolocation.h"</span><br><span style="color: hsl(120, 100%, 40%);">+#include "asterisk/vector.h"</span><br><span style="color: hsl(120, 100%, 40%);">+#include "geoloc_private.h"</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#define GEOLOC_DS_TYPE "geoloc_eprofiles"</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct ast_sorcery *geoloc_sorcery;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct eprofiles_datastore {</span><br><span style="color: hsl(120, 100%, 40%);">+ const char *id;</span><br><span style="color: hsl(120, 100%, 40%);">+       AST_VECTOR(geoloc_eprofiles, struct ast_geoloc_eprofile *) eprofiles;</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static void geoloc_datastore_free(void *obj)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  struct eprofiles_datastore *eds = obj;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      AST_VECTOR_RESET(&eds->eprofiles, ao2_cleanup);</span><br><span style="color: hsl(120, 100%, 40%);">+        AST_VECTOR_FREE(&eds->eprofiles);</span><br><span style="color: hsl(120, 100%, 40%);">+      ast_free(eds);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static void *geoloc_datastore_duplicate(void *obj)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+    struct eprofiles_datastore *in_eds = obj;</span><br><span style="color: hsl(120, 100%, 40%);">+     struct eprofiles_datastore *out_eds;</span><br><span style="color: hsl(120, 100%, 40%);">+  int rc = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+   int i = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+    int eprofile_count = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     out_eds = ast_calloc(1, sizeof(*out_eds));</span><br><span style="color: hsl(120, 100%, 40%);">+    if (!out_eds) {</span><br><span style="color: hsl(120, 100%, 40%);">+               return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+  }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   rc = AST_VECTOR_INIT(&out_eds->eprofiles, 2);</span><br><span style="color: hsl(120, 100%, 40%);">+  if (rc != 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+                ast_free(out_eds);</span><br><span style="color: hsl(120, 100%, 40%);">+            return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+  }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   eprofile_count = AST_VECTOR_SIZE(&in_eds->eprofiles);</span><br><span style="color: hsl(120, 100%, 40%);">+  for (i = 0; i < eprofile_count; i++) {</span><br><span style="color: hsl(120, 100%, 40%);">+             struct ast_geoloc_eprofile *ep = AST_VECTOR_GET(&in_eds->eprofiles, i);</span><br><span style="color: hsl(120, 100%, 40%);">+                rc = AST_VECTOR_APPEND(&out_eds->eprofiles, ao2_bump(ep));</span><br><span style="color: hsl(120, 100%, 40%);">+             if (rc != 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+                        /* This will clean up the bumped reference to the eprofile */</span><br><span style="color: hsl(120, 100%, 40%);">+                 geoloc_datastore_free(out_eds);</span><br><span style="color: hsl(120, 100%, 40%);">+                       return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+          }</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   return out_eds;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static const struct ast_datastore_info geoloc_datastore_info = {</span><br><span style="color: hsl(120, 100%, 40%);">+        .type = GEOLOC_DS_TYPE,</span><br><span style="color: hsl(120, 100%, 40%);">+       .destroy = geoloc_datastore_free,</span><br><span style="color: hsl(120, 100%, 40%);">+     .duplicate = geoloc_datastore_duplicate,</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#define IS_GEOLOC_DS(_ds) (_ds && _ds->data && ast_strings_equal(_ds->info->type, GEOLOC_DS_TYPE))</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+const char *ast_geoloc_datastore_get_id(struct ast_datastore *ds)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+   struct eprofiles_datastore *eds = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     if (!IS_GEOLOC_DS(ds)) {</span><br><span style="color: hsl(120, 100%, 40%);">+              return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+  }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   eds = (struct eprofiles_datastore *)ds->data;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    return eds->id;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct ast_datastore *ast_geoloc_datastore_create(const char *id)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ struct ast_datastore *ds = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+      struct eprofiles_datastore *eds = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+       int rc = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (ast_strlen_zero(id)) {</span><br><span style="color: hsl(120, 100%, 40%);">+            ast_log(LOG_ERROR, "A geoloc datastore can't be allocated with a NULL or empty id\n");</span><br><span style="color: hsl(120, 100%, 40%);">+          return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+  }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   ds = ast_datastore_alloc(&geoloc_datastore_info, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+   if (!ds) {</span><br><span style="color: hsl(120, 100%, 40%);">+            ast_log(LOG_ERROR, "Geoloc datastore '%s' couldn't be allocated\n", id);</span><br><span style="color: hsl(120, 100%, 40%);">+                return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+  }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   eds = ast_calloc(1, sizeof(*eds));</span><br><span style="color: hsl(120, 100%, 40%);">+    if (!eds) {</span><br><span style="color: hsl(120, 100%, 40%);">+           ast_datastore_free(ds);</span><br><span style="color: hsl(120, 100%, 40%);">+               ast_log(LOG_ERROR, "Private structure for geoloc datastore '%s' couldn't be allocated\n", id);</span><br><span style="color: hsl(120, 100%, 40%);">+          return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+  }</span><br><span style="color: hsl(120, 100%, 40%);">+     ds->data = eds;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        rc = AST_VECTOR_INIT(&eds->eprofiles, 2);</span><br><span style="color: hsl(120, 100%, 40%);">+      if (rc != 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+                ast_datastore_free(ds);</span><br><span style="color: hsl(120, 100%, 40%);">+               ast_log(LOG_ERROR, "Vector for geoloc datastore '%s' couldn't be initialized\n", id);</span><br><span style="color: hsl(120, 100%, 40%);">+           return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+  }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   return ds;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+int ast_geoloc_datastore_add_eprofile(struct ast_datastore *ds,</span><br><span style="color: hsl(120, 100%, 40%);">+      struct ast_geoloc_eprofile *eprofile)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+      struct eprofiles_datastore *eds = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+       int rc = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!IS_GEOLOC_DS(ds) || !eprofile) {</span><br><span style="color: hsl(120, 100%, 40%);">+         return -1;</span><br><span style="color: hsl(120, 100%, 40%);">+    }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   eds = ds->data;</span><br><span style="color: hsl(120, 100%, 40%);">+    rc = AST_VECTOR_APPEND(&eds->eprofiles, ao2_bump(eprofile));</span><br><span style="color: hsl(120, 100%, 40%);">+   if (rc != 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+                ao2_ref(eprofile, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+                ast_log(LOG_ERROR, "Couldn't add eprofile '%s' to geoloc datastore '%s'\n", eprofile->id, eds->id);</span><br><span style="color: hsl(120, 100%, 40%);">+               return -1;</span><br><span style="color: hsl(120, 100%, 40%);">+    }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   return AST_VECTOR_SIZE(&eds->eprofiles);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+int ast_geoloc_datastore_insert_eprofile(struct ast_datastore *ds,</span><br><span style="color: hsl(120, 100%, 40%);">+      struct ast_geoloc_eprofile *eprofile, int index)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+   struct eprofiles_datastore *eds = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+       int rc = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!IS_GEOLOC_DS(ds) || !eprofile) {</span><br><span style="color: hsl(120, 100%, 40%);">+         return -1;</span><br><span style="color: hsl(120, 100%, 40%);">+    }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   eds = ds->data;</span><br><span style="color: hsl(120, 100%, 40%);">+    rc = AST_VECTOR_INSERT_AT(&eds->eprofiles, index, ao2_bump(eprofile));</span><br><span style="color: hsl(120, 100%, 40%);">+ if (rc != 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+                ao2_ref(eprofile, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+                ast_log(LOG_ERROR, "Couldn't add eprofile '%s' to geoloc datastore '%s' in position '%d'\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                    eprofile->id, eds->id, index);</span><br><span style="color: hsl(120, 100%, 40%);">+          return -1;</span><br><span style="color: hsl(120, 100%, 40%);">+    }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   return AST_VECTOR_SIZE(&eds->eprofiles);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+int ast_geoloc_datastore_size(struct ast_datastore *ds)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+      struct eprofiles_datastore *eds = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     if (!IS_GEOLOC_DS(ds)) {</span><br><span style="color: hsl(120, 100%, 40%);">+              return -1;</span><br><span style="color: hsl(120, 100%, 40%);">+    }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   eds = ds->data;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  return AST_VECTOR_SIZE(&eds->eprofiles);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+int ast_geoloc_datastore_set_inheritance(struct ast_datastore *ds, int inherit)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+      if (!IS_GEOLOC_DS(ds)) {</span><br><span style="color: hsl(120, 100%, 40%);">+              return -1;</span><br><span style="color: hsl(120, 100%, 40%);">+    }</span><br><span style="color: hsl(120, 100%, 40%);">+     ds->inheritance = inherit ? DATASTORE_INHERIT_FOREVER : 0;</span><br><span style="color: hsl(120, 100%, 40%);">+ return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct ast_geoloc_eprofile *ast_geoloc_datastore_get_eprofile(struct ast_datastore *ds, int ix)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+    struct eprofiles_datastore *eds = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+       struct ast_geoloc_eprofile *eprofile;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       if (!IS_GEOLOC_DS(ds)) {</span><br><span style="color: hsl(120, 100%, 40%);">+              return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+  }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   eds = ds->data;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  if (ix >= AST_VECTOR_SIZE(&eds->eprofiles)) {</span><br><span style="color: hsl(120, 100%, 40%);">+               return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+  }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   eprofile  = AST_VECTOR_GET(&eds->eprofiles, ix);</span><br><span style="color: hsl(120, 100%, 40%);">+       return ao2_bump(eprofile);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct ast_datastore *ast_geoloc_datastore_find(struct ast_channel *chan)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ return ast_channel_datastore_find(chan, &geoloc_datastore_info, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+int ast_geoloc_datastore_delete_eprofile(struct ast_datastore *ds, int ix)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+        struct eprofiles_datastore *eds = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     if (!IS_GEOLOC_DS(ds)) {</span><br><span style="color: hsl(120, 100%, 40%);">+              return -1;</span><br><span style="color: hsl(120, 100%, 40%);">+    }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   eds = ds->data;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  if (ix >= AST_VECTOR_SIZE(&eds->eprofiles)) {</span><br><span style="color: hsl(120, 100%, 40%);">+               return -1;</span><br><span style="color: hsl(120, 100%, 40%);">+    }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   ao2_ref(AST_VECTOR_REMOVE(&eds->eprofiles, ix, 1), -1);</span><br><span style="color: hsl(120, 100%, 40%);">+        return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct ast_datastore *ast_geoloc_datastore_create_from_eprofile(</span><br><span style="color: hsl(120, 100%, 40%);">+      struct ast_geoloc_eprofile *eprofile)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+      struct ast_datastore *ds;</span><br><span style="color: hsl(120, 100%, 40%);">+     int rc = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!eprofile) {</span><br><span style="color: hsl(120, 100%, 40%);">+              return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+  }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   ds = ast_geoloc_datastore_create(eprofile->id);</span><br><span style="color: hsl(120, 100%, 40%);">+    if (!ds) {</span><br><span style="color: hsl(120, 100%, 40%);">+            return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+  }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   rc = ast_geoloc_datastore_add_eprofile(ds, eprofile);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (rc != 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+                ast_datastore_free(ds);</span><br><span style="color: hsl(120, 100%, 40%);">+               ds = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+    }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   return ds;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct ast_datastore *ast_geoloc_datastore_create_from_profile_name(const char *profile_name)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+     struct ast_datastore *ds = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+      struct ast_geoloc_eprofile *eprofile = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+  struct ast_geoloc_profile *profile = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+    int rc = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (ast_strlen_zero(profile_name)) {</span><br><span style="color: hsl(120, 100%, 40%);">+          return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+  }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   profile = ast_sorcery_retrieve_by_id(geoloc_sorcery, "profile", profile_name);</span><br><span style="color: hsl(120, 100%, 40%);">+      if (!profile) {</span><br><span style="color: hsl(120, 100%, 40%);">+               ast_log(LOG_ERROR, "A profile with the name '%s' was not found\n", profile_name);</span><br><span style="color: hsl(120, 100%, 40%);">+           return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+  }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   ds = ast_geoloc_datastore_create(profile_name);</span><br><span style="color: hsl(120, 100%, 40%);">+       if (!ds) {</span><br><span style="color: hsl(120, 100%, 40%);">+            ast_log(LOG_ERROR, "A datastore couldn't be allocated for profile '%s'\n", profile_name);</span><br><span style="color: hsl(120, 100%, 40%);">+               ao2_ref(profile, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+         return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+  }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   eprofile = ast_geoloc_eprofile_create_from_profile(profile);</span><br><span style="color: hsl(120, 100%, 40%);">+  ao2_ref(profile, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!eprofile) {</span><br><span style="color: hsl(120, 100%, 40%);">+              ast_datastore_free(ds);</span><br><span style="color: hsl(120, 100%, 40%);">+               ast_log(LOG_ERROR, "An effective profile with the name '%s' couldn't be allocated\n", profile_name);</span><br><span style="color: hsl(120, 100%, 40%);">+            return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+  }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   rc = ast_geoloc_datastore_add_eprofile(ds, eprofile);</span><br><span style="color: hsl(120, 100%, 40%);">+ ao2_ref(eprofile, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+        if (rc != 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+                ast_datastore_free(ds);</span><br><span style="color: hsl(120, 100%, 40%);">+               ds = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+    }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   return ds;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+int geoloc_channel_unload(void)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+   if (geoloc_sorcery) {</span><br><span style="color: hsl(120, 100%, 40%);">+         ast_sorcery_unref(geoloc_sorcery);</span><br><span style="color: hsl(120, 100%, 40%);">+    }</span><br><span style="color: hsl(120, 100%, 40%);">+     return AST_MODULE_LOAD_SUCCESS;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+int geoloc_channel_load(void)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+        geoloc_sorcery = geoloc_get_sorcery();</span><br><span style="color: hsl(120, 100%, 40%);">+        return AST_MODULE_LOAD_SUCCESS;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+int geoloc_channel_reload(void)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+      return AST_MODULE_LOAD_SUCCESS;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span>diff --git a/res/res_geolocation/geoloc_dialplan.c b/res/res_geolocation/geoloc_dialplan.c</span><br><span>new file mode 100644</span><br><span>index 0000000..efa234a</span><br><span>--- /dev/null</span><br><span>+++ b/res/res_geolocation/geoloc_dialplan.c</span><br><span>@@ -0,0 +1,457 @@</span><br><span style="color: hsl(120, 100%, 40%);">+/*</span><br><span style="color: hsl(120, 100%, 40%);">+ * Asterisk -- An open source telephony toolkit.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * Copyright (C) 2022, Sangoma Technologies Corporation</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * George Joseph <gjoseph@sangoma.com></span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * See http://www.asterisk.org for more information about</span><br><span style="color: hsl(120, 100%, 40%);">+ * the Asterisk project. Please do not directly contact</span><br><span style="color: hsl(120, 100%, 40%);">+ * any of the maintainers of this project for assistance;</span><br><span style="color: hsl(120, 100%, 40%);">+ * the project provides a web site, mailing lists and IRC</span><br><span style="color: hsl(120, 100%, 40%);">+ * channels for your use.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * This program is free software, distributed under the terms of</span><br><span style="color: hsl(120, 100%, 40%);">+ * the GNU General Public License Version 2. See the LICENSE file</span><br><span style="color: hsl(120, 100%, 40%);">+ * at the top of the source tree.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include "asterisk.h"</span><br><span style="color: hsl(120, 100%, 40%);">+#include "asterisk/config.h"</span><br><span style="color: hsl(120, 100%, 40%);">+#include "asterisk/cli.h"</span><br><span style="color: hsl(120, 100%, 40%);">+#include "asterisk/module.h"</span><br><span style="color: hsl(120, 100%, 40%);">+#include "asterisk/channel.h"</span><br><span style="color: hsl(120, 100%, 40%);">+#include "asterisk/pbx.h"</span><br><span style="color: hsl(120, 100%, 40%);">+#include "asterisk/strings.h"</span><br><span style="color: hsl(120, 100%, 40%);">+#include "asterisk/utils.h"</span><br><span style="color: hsl(120, 100%, 40%);">+#include "asterisk/app.h"</span><br><span style="color: hsl(120, 100%, 40%);">+#include "asterisk/res_geolocation.h"</span><br><span style="color: hsl(120, 100%, 40%);">+#include "geoloc_private.h"</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static void varlist_to_str(struct ast_variable *list, struct ast_str** buf, size_t len)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+     struct ast_variable *var = list;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    for (; var; var = var->next) {</span><br><span style="color: hsl(120, 100%, 40%);">+             ast_str_append(buf, len, "%s=\"%s\"%s", var->name, var->value, var->next ? "," : "");</span><br><span style="color: hsl(120, 100%, 40%);">+        }</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static int geoloc_profile_read(struct ast_channel *chan,</span><br><span style="color: hsl(120, 100%, 40%);">+      const char *cmd, char *data, struct ast_str **buf, ssize_t len)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+    char *parsed_data = ast_strdupa(data);</span><br><span style="color: hsl(120, 100%, 40%);">+        int index = -1;</span><br><span style="color: hsl(120, 100%, 40%);">+       struct ast_datastore *ds;</span><br><span style="color: hsl(120, 100%, 40%);">+     struct ast_geoloc_eprofile *eprofile = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+  int profile_count = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      AST_DECLARE_APP_ARGS(args,</span><br><span style="color: hsl(120, 100%, 40%);">+            AST_APP_ARG(field);</span><br><span style="color: hsl(120, 100%, 40%);">+           AST_APP_ARG(index);</span><br><span style="color: hsl(120, 100%, 40%);">+   );</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  /* Check for zero arguments */</span><br><span style="color: hsl(120, 100%, 40%);">+        if (ast_strlen_zero(parsed_data)) {</span><br><span style="color: hsl(120, 100%, 40%);">+           ast_log(LOG_ERROR, "%s: Cannot call without arguments\n", cmd);</span><br><span style="color: hsl(120, 100%, 40%);">+             return -1;</span><br><span style="color: hsl(120, 100%, 40%);">+    }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   AST_STANDARD_APP_ARGS(args, parsed_data);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   if (ast_strlen_zero(args.field)) {</span><br><span style="color: hsl(120, 100%, 40%);">+            ast_log(LOG_ERROR, "%s: Cannot call without a field to query\n", cmd);</span><br><span style="color: hsl(120, 100%, 40%);">+              return -1;</span><br><span style="color: hsl(120, 100%, 40%);">+    }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   if (!ast_strlen_zero(args.index)) {</span><br><span style="color: hsl(120, 100%, 40%);">+           if (sscanf(args.index, "%30d", &index) != 1) {</span><br><span style="color: hsl(120, 100%, 40%);">+                  ast_log(LOG_ERROR, "%s: profile_index '%s' is invalid\n", cmd, args.index);</span><br><span style="color: hsl(120, 100%, 40%);">+                 return -1;</span><br><span style="color: hsl(120, 100%, 40%);">+            }</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   ds = ast_geoloc_datastore_find(chan);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!ds) {</span><br><span style="color: hsl(120, 100%, 40%);">+            ast_log(LOG_NOTICE, "%s: There are no geoloc profiles on this channel\n", cmd);</span><br><span style="color: hsl(120, 100%, 40%);">+             return -1;</span><br><span style="color: hsl(120, 100%, 40%);">+    }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   profile_count = ast_geoloc_datastore_size(ds);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      if (index < 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+           if (ast_strings_equal(args.field, "count")) {</span><br><span style="color: hsl(120, 100%, 40%);">+                       ast_str_append(buf, len, "%d", profile_count);</span><br><span style="color: hsl(120, 100%, 40%);">+              } else if (ast_strings_equal(args.field, "inheritable")) {</span><br><span style="color: hsl(120, 100%, 40%);">+                  ast_str_append(buf, len, "%d", ds->inheritance ? 1 : 0);</span><br><span style="color: hsl(120, 100%, 40%);">+         } else {</span><br><span style="color: hsl(120, 100%, 40%);">+                      ast_log(LOG_ERROR, "%s: Field '%s' is not valid\n", cmd, args.field);</span><br><span style="color: hsl(120, 100%, 40%);">+                       return -1;</span><br><span style="color: hsl(120, 100%, 40%);">+            }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+           return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   if (index >= profile_count) {</span><br><span style="color: hsl(120, 100%, 40%);">+              ast_log(LOG_ERROR, "%s: index %d is out of range 0 -> %d\n", cmd, index, profile_count);</span><br><span style="color: hsl(120, 100%, 40%);">+         return -1;</span><br><span style="color: hsl(120, 100%, 40%);">+    }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   eprofile = ast_geoloc_datastore_get_eprofile(ds, index);</span><br><span style="color: hsl(120, 100%, 40%);">+      if (!eprofile) {</span><br><span style="color: hsl(120, 100%, 40%);">+              ast_log(LOG_ERROR, "%s: Internal Error.  Profile at index %d couldn't be retrieved.\n", cmd, index);</span><br><span style="color: hsl(120, 100%, 40%);">+            return -1;</span><br><span style="color: hsl(120, 100%, 40%);">+    }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   if (ast_strings_equal(args.field, "id")) {</span><br><span style="color: hsl(120, 100%, 40%);">+          ast_str_append(buf, len, "%s", eprofile->id);</span><br><span style="color: hsl(120, 100%, 40%);">+    } else if (ast_strings_equal(args.field, "location_reference")) {</span><br><span style="color: hsl(120, 100%, 40%);">+           ast_str_append(buf, len, "%s", eprofile->location_reference);</span><br><span style="color: hsl(120, 100%, 40%);">+    } else if (ast_strings_equal(args.field, "method")) {</span><br><span style="color: hsl(120, 100%, 40%);">+               ast_str_append(buf, len, "%s", eprofile->method);</span><br><span style="color: hsl(120, 100%, 40%);">+        } else if (ast_strings_equal(args.field, "geolocation_routing")) {</span><br><span style="color: hsl(120, 100%, 40%);">+          ast_str_append(buf, len, "%s", eprofile->geolocation_routing ? "yes" : "no");</span><br><span style="color: hsl(120, 100%, 40%);">+        } else if (ast_strings_equal(args.field, "profile_action")) {</span><br><span style="color: hsl(120, 100%, 40%);">+               ast_str_append(buf, len, "%s", geoloc_action_to_name(eprofile->action));</span><br><span style="color: hsl(120, 100%, 40%);">+ } else if (ast_strings_equal(args.field, "format")) {</span><br><span style="color: hsl(120, 100%, 40%);">+               ast_str_append(buf, len, "%s", geoloc_format_to_name(eprofile->format));</span><br><span style="color: hsl(120, 100%, 40%);">+ } else if (ast_strings_equal(args.field, "pidf_element")) {</span><br><span style="color: hsl(120, 100%, 40%);">+         ast_str_append(buf, len, "%s", geoloc_pidf_element_to_name(eprofile->pidf_element));</span><br><span style="color: hsl(120, 100%, 40%);">+     } else if (ast_strings_equal(args.field, "location_source")) {</span><br><span style="color: hsl(120, 100%, 40%);">+              ast_str_append(buf, len, "%s", eprofile->location_source);</span><br><span style="color: hsl(120, 100%, 40%);">+       } else if (ast_strings_equal(args.field, "location_info")) {</span><br><span style="color: hsl(120, 100%, 40%);">+                varlist_to_str(eprofile->location_info, buf, len);</span><br><span style="color: hsl(120, 100%, 40%);">+ } else if (ast_strings_equal(args.field, "location_info_refinement")) {</span><br><span style="color: hsl(120, 100%, 40%);">+             varlist_to_str(eprofile->location_refinement, buf, len);</span><br><span style="color: hsl(120, 100%, 40%);">+   } else if (ast_strings_equal(args.field, "location_variables")) {</span><br><span style="color: hsl(120, 100%, 40%);">+           varlist_to_str(eprofile->location_variables, buf, len);</span><br><span style="color: hsl(120, 100%, 40%);">+    } else if (ast_strings_equal(args.field, "effective_location")) {</span><br><span style="color: hsl(120, 100%, 40%);">+           varlist_to_str(eprofile->effective_location, buf, len);</span><br><span style="color: hsl(120, 100%, 40%);">+    } else if (ast_strings_equal(args.field, "usage_rules")) {</span><br><span style="color: hsl(120, 100%, 40%);">+          varlist_to_str(eprofile->usage_rules, buf, len);</span><br><span style="color: hsl(120, 100%, 40%);">+   } else {</span><br><span style="color: hsl(120, 100%, 40%);">+              ast_log(LOG_ERROR, "%s: Field '%s' is not valid\n", cmd, args.field);</span><br><span style="color: hsl(120, 100%, 40%);">+               return -1;</span><br><span style="color: hsl(120, 100%, 40%);">+    }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   ao2_ref(eprofile, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+        return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#define TEST_ENUM_VALUE(_cmd, _ep, _field, _value) \</span><br><span style="color: hsl(120, 100%, 40%);">+({ \</span><br><span style="color: hsl(120, 100%, 40%);">+    enum ast_geoloc_ ## _field v; \</span><br><span style="color: hsl(120, 100%, 40%);">+       if (!_ep) { \</span><br><span style="color: hsl(120, 100%, 40%);">+         ast_log(LOG_ERROR, "%s: Field %s requires a valid index\n", _cmd, #_field); \</span><br><span style="color: hsl(120, 100%, 40%);">+               return -1; \</span><br><span style="color: hsl(120, 100%, 40%);">+  } \</span><br><span style="color: hsl(120, 100%, 40%);">+   v = geoloc_ ## _field ## _str_to_enum(_value); \</span><br><span style="color: hsl(120, 100%, 40%);">+      if (v == AST_GEOLOC_INVALID_VALUE) { \</span><br><span style="color: hsl(120, 100%, 40%);">+                ast_log(LOG_ERROR, "%s: %s '%s' is invalid\n", _cmd, #_field, value); \</span><br><span style="color: hsl(120, 100%, 40%);">+             return -1; \</span><br><span style="color: hsl(120, 100%, 40%);">+  } \</span><br><span style="color: hsl(120, 100%, 40%);">+   _ep->_field = v; \</span><br><span style="color: hsl(120, 100%, 40%);">+})</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#define TEST_VARLIST(_cmd, _ep, _field, _value) \</span><br><span style="color: hsl(120, 100%, 40%);">+({ \</span><br><span style="color: hsl(120, 100%, 40%);">+  struct ast_variable *_list; \</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!_ep) { \</span><br><span style="color: hsl(120, 100%, 40%);">+         ast_log(LOG_ERROR, "%s: Field %s requires a valid index\n", _cmd, #_field); \</span><br><span style="color: hsl(120, 100%, 40%);">+               return -1; \</span><br><span style="color: hsl(120, 100%, 40%);">+  } \</span><br><span style="color: hsl(120, 100%, 40%);">+   _list = ast_variable_list_from_quoted_string(_value, ",", "=", "\"" ); \</span><br><span style="color: hsl(120, 100%, 40%);">+   if (!_list) { \</span><br><span style="color: hsl(120, 100%, 40%);">+               ast_log(LOG_ERROR, "%s: %s '%s' is malformed or contains invalid values", _cmd, #_field, _value); \</span><br><span style="color: hsl(120, 100%, 40%);">+         return -1; \</span><br><span style="color: hsl(120, 100%, 40%);">+  } \</span><br><span style="color: hsl(120, 100%, 40%);">+   ast_variables_destroy(_ep->_field); \</span><br><span style="color: hsl(120, 100%, 40%);">+      _ep->_field = _list; \</span><br><span style="color: hsl(120, 100%, 40%);">+})</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static int geoloc_profile_write(struct ast_channel *chan, const char *cmd, char *data,</span><br><span style="color: hsl(120, 100%, 40%);">+        const char *value)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+        char *parsed_data = ast_strdupa(data);</span><br><span style="color: hsl(120, 100%, 40%);">+        struct ast_datastore *ds;</span><br><span style="color: hsl(120, 100%, 40%);">+     RAII_VAR(struct ast_geoloc_eprofile *, eprofile, NULL, ao2_cleanup);</span><br><span style="color: hsl(120, 100%, 40%);">+  int profile_count = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+        int index = -1;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     AST_DECLARE_APP_ARGS(args,</span><br><span style="color: hsl(120, 100%, 40%);">+            AST_APP_ARG(field);</span><br><span style="color: hsl(120, 100%, 40%);">+           AST_APP_ARG(index);</span><br><span style="color: hsl(120, 100%, 40%);">+   );</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  /* Check for zero arguments */</span><br><span style="color: hsl(120, 100%, 40%);">+        if (ast_strlen_zero(parsed_data)) {</span><br><span style="color: hsl(120, 100%, 40%);">+           ast_log(LOG_ERROR, "%s: Cannot call without arguments\n", cmd);</span><br><span style="color: hsl(120, 100%, 40%);">+             return -1;</span><br><span style="color: hsl(120, 100%, 40%);">+    }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   AST_STANDARD_APP_ARGS(args, parsed_data);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   if (ast_strlen_zero(args.field)) {</span><br><span style="color: hsl(120, 100%, 40%);">+            ast_log(LOG_ERROR, "%s: Cannot call without a field to set\n", cmd);</span><br><span style="color: hsl(120, 100%, 40%);">+                return -1;</span><br><span style="color: hsl(120, 100%, 40%);">+    }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   if (!ast_strlen_zero(args.index)) {</span><br><span style="color: hsl(120, 100%, 40%);">+           if (sscanf(args.index, "%30d", &index) != 1) {</span><br><span style="color: hsl(120, 100%, 40%);">+                  ast_log(LOG_ERROR, "%s: profile_index '%s' is invalid\n", cmd, args.index);</span><br><span style="color: hsl(120, 100%, 40%);">+                 return -1;</span><br><span style="color: hsl(120, 100%, 40%);">+            }</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   ds = ast_geoloc_datastore_find(chan);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!ds) {</span><br><span style="color: hsl(120, 100%, 40%);">+            ast_log(LOG_WARNING, "%s: There are no geoloc profiles on this channel\n", cmd);</span><br><span style="color: hsl(120, 100%, 40%);">+            return -1;</span><br><span style="color: hsl(120, 100%, 40%);">+    }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   profile_count = ast_geoloc_datastore_size(ds);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      if (index >= 0 && index < profile_count) {</span><br><span style="color: hsl(120, 100%, 40%);">+              eprofile = ast_geoloc_datastore_get_eprofile(ds, index);</span><br><span style="color: hsl(120, 100%, 40%);">+              if (!eprofile) {</span><br><span style="color: hsl(120, 100%, 40%);">+                      ast_log(LOG_ERROR, "%s: Internal Error.  Profile at index %d couldn't be retrieved.\n", cmd, index);</span><br><span style="color: hsl(120, 100%, 40%);">+                    return -1;</span><br><span style="color: hsl(120, 100%, 40%);">+            }</span><br><span style="color: hsl(120, 100%, 40%);">+     } else if (index >= profile_count) {</span><br><span style="color: hsl(120, 100%, 40%);">+               ast_log(LOG_ERROR, "%s: index %d is out of range 0 -> %d\n", cmd, index, profile_count);</span><br><span style="color: hsl(120, 100%, 40%);">+         return -1;</span><br><span style="color: hsl(120, 100%, 40%);">+    } else {</span><br><span style="color: hsl(120, 100%, 40%);">+              if (ast_strings_equal(args.field, "inheritable")) {</span><br><span style="color: hsl(120, 100%, 40%);">+                 ast_geoloc_datastore_set_inheritance(ds, ast_true(value));</span><br><span style="color: hsl(120, 100%, 40%);">+            } else {</span><br><span style="color: hsl(120, 100%, 40%);">+                      ast_log(LOG_ERROR, "%s: Field '%s' is not valid or requires a profile index\n", cmd, args.field);</span><br><span style="color: hsl(120, 100%, 40%);">+                   return -1;</span><br><span style="color: hsl(120, 100%, 40%);">+            }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+           return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   if (ast_strings_equal(args.field, "location_reference")) {</span><br><span style="color: hsl(120, 100%, 40%);">+          struct ast_geoloc_location *loc = ast_geoloc_get_location(value);</span><br><span style="color: hsl(120, 100%, 40%);">+             ao2_cleanup(loc);</span><br><span style="color: hsl(120, 100%, 40%);">+             if (!loc) {</span><br><span style="color: hsl(120, 100%, 40%);">+                   ast_log(LOG_ERROR, "%s: Location reference '%s' doesn't exist\n", cmd, value);</span><br><span style="color: hsl(120, 100%, 40%);">+                  return -1;</span><br><span style="color: hsl(120, 100%, 40%);">+            }</span><br><span style="color: hsl(120, 100%, 40%);">+             ast_string_field_set(eprofile, location_reference, value);</span><br><span style="color: hsl(120, 100%, 40%);">+    } else if (ast_strings_equal(args.field, "method")) {</span><br><span style="color: hsl(120, 100%, 40%);">+               ast_string_field_set(eprofile, method, value);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      } else if (ast_strings_equal(args.field, "geolocation_routing")) {</span><br><span style="color: hsl(120, 100%, 40%);">+          eprofile->geolocation_routing = ast_true(value);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ } else if (ast_strings_equal(args.field, "profile_action")) {</span><br><span style="color: hsl(120, 100%, 40%);">+               TEST_ENUM_VALUE(cmd, eprofile, action, value);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      } else if (ast_strings_equal(args.field, "format")) {</span><br><span style="color: hsl(120, 100%, 40%);">+               TEST_ENUM_VALUE(cmd, eprofile, format, value);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      } else if (ast_strings_equal(args.field, "pidf_element")) {</span><br><span style="color: hsl(120, 100%, 40%);">+         TEST_ENUM_VALUE(cmd, eprofile, pidf_element, value);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        } else if (ast_strings_equal(args.field, "location_info")) {</span><br><span style="color: hsl(120, 100%, 40%);">+                TEST_VARLIST(cmd, eprofile, location_info, value);</span><br><span style="color: hsl(120, 100%, 40%);">+    } else if (ast_strings_equal(args.field, "location_source")) {</span><br><span style="color: hsl(120, 100%, 40%);">+              ast_string_field_set(eprofile, location_source, value);</span><br><span style="color: hsl(120, 100%, 40%);">+       } else if (ast_strings_equal(args.field, "location_info_refinement")) {</span><br><span style="color: hsl(120, 100%, 40%);">+             TEST_VARLIST(cmd, eprofile, location_refinement, value);</span><br><span style="color: hsl(120, 100%, 40%);">+      } else if (ast_strings_equal(args.field, "location_variables")) {</span><br><span style="color: hsl(120, 100%, 40%);">+           TEST_VARLIST(cmd, eprofile, location_variables, value);</span><br><span style="color: hsl(120, 100%, 40%);">+       } else if (ast_strings_equal(args.field, "effective_location")) {</span><br><span style="color: hsl(120, 100%, 40%);">+           TEST_VARLIST(cmd, eprofile, effective_location, value);</span><br><span style="color: hsl(120, 100%, 40%);">+       } else if (ast_strings_equal(args.field, "usage_rules")) {</span><br><span style="color: hsl(120, 100%, 40%);">+          TEST_VARLIST(cmd, eprofile, usage_rules, value);</span><br><span style="color: hsl(120, 100%, 40%);">+      } else {</span><br><span style="color: hsl(120, 100%, 40%);">+              ast_log(LOG_ERROR, "%s: Field '%s' is not valid\n", cmd, args.field);</span><br><span style="color: hsl(120, 100%, 40%);">+               return -1;</span><br><span style="color: hsl(120, 100%, 40%);">+    }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   ast_geoloc_eprofile_refresh_location(eprofile);</span><br><span style="color: hsl(120, 100%, 40%);">+       return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static struct ast_custom_function geoloc_function = {</span><br><span style="color: hsl(120, 100%, 40%);">+ .name = "GEOLOC_PROFILE",</span><br><span style="color: hsl(120, 100%, 40%);">+   .read2 = geoloc_profile_read,</span><br><span style="color: hsl(120, 100%, 40%);">+ .write = geoloc_profile_write,</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#define profile_create "GeolocProfileCreate"</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static int geoloc_eprofile_create(struct ast_channel *chan, const char *data)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+      char *parsed_data = ast_strdupa(data);</span><br><span style="color: hsl(120, 100%, 40%);">+        struct ast_datastore *ds;</span><br><span style="color: hsl(120, 100%, 40%);">+     struct ast_geoloc_eprofile * eprofile;</span><br><span style="color: hsl(120, 100%, 40%);">+        int profile_count = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+        int index = -1;</span><br><span style="color: hsl(120, 100%, 40%);">+       int rc = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+   struct ast_str *new_size;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   AST_DECLARE_APP_ARGS(args,</span><br><span style="color: hsl(120, 100%, 40%);">+            AST_APP_ARG(id);</span><br><span style="color: hsl(120, 100%, 40%);">+              AST_APP_ARG(index);</span><br><span style="color: hsl(120, 100%, 40%);">+   );</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  /* Check for zero arguments */</span><br><span style="color: hsl(120, 100%, 40%);">+        if (ast_strlen_zero(parsed_data)) {</span><br><span style="color: hsl(120, 100%, 40%);">+           ast_log(LOG_ERROR, "%s: Cannot call without arguments\n", profile_create);</span><br><span style="color: hsl(120, 100%, 40%);">+          return -1;</span><br><span style="color: hsl(120, 100%, 40%);">+    }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   AST_STANDARD_APP_ARGS(args, parsed_data);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   if (ast_strlen_zero(args.id)) {</span><br><span style="color: hsl(120, 100%, 40%);">+               ast_log(LOG_ERROR, "%s: Cannot call without an id field\n", profile_create);</span><br><span style="color: hsl(120, 100%, 40%);">+                return -1;</span><br><span style="color: hsl(120, 100%, 40%);">+    }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   if (!ast_strlen_zero(args.index)) {</span><br><span style="color: hsl(120, 100%, 40%);">+           if (sscanf(args.index, "%30d", &index) != 1) {</span><br><span style="color: hsl(120, 100%, 40%);">+                  ast_log(LOG_ERROR, "%s: profile_index '%s' is invalid\n", profile_create, args.index);</span><br><span style="color: hsl(120, 100%, 40%);">+                      return -1;</span><br><span style="color: hsl(120, 100%, 40%);">+            }</span><br><span style="color: hsl(120, 100%, 40%);">+     } else {</span><br><span style="color: hsl(120, 100%, 40%);">+              index = -1;</span><br><span style="color: hsl(120, 100%, 40%);">+   }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   ds = ast_geoloc_datastore_find(chan);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!ds) {</span><br><span style="color: hsl(120, 100%, 40%);">+            ast_log(LOG_WARNING, "%s: There are no geoloc profiles on this channel\n", profile_create);</span><br><span style="color: hsl(120, 100%, 40%);">+         return -1;</span><br><span style="color: hsl(120, 100%, 40%);">+    }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   profile_count = ast_geoloc_datastore_size(ds);</span><br><span style="color: hsl(120, 100%, 40%);">+        if (index < -1 || index >= profile_count) {</span><br><span style="color: hsl(120, 100%, 40%);">+             ast_log(LOG_ERROR, "%s: Invalid insert_before index '%d'.  It must be 0 to insert at the beginning of the list or -1 to append to the end of the list\n", profile_create, index);</span><br><span style="color: hsl(120, 100%, 40%);">+           return -1;</span><br><span style="color: hsl(120, 100%, 40%);">+    }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   eprofile = ast_geoloc_eprofile_alloc(args.id);</span><br><span style="color: hsl(120, 100%, 40%);">+        if (!eprofile) {</span><br><span style="color: hsl(120, 100%, 40%);">+              ast_log(LOG_ERROR, "%s: Could not allocate eprofile '%s'\n", profile_create, args.id);</span><br><span style="color: hsl(120, 100%, 40%);">+              return -1;</span><br><span style="color: hsl(120, 100%, 40%);">+    }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   ds = ast_geoloc_datastore_find(chan);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!ds) {</span><br><span style="color: hsl(120, 100%, 40%);">+            ds = ast_geoloc_datastore_create_from_eprofile(eprofile);</span><br><span style="color: hsl(120, 100%, 40%);">+             if (!ds) {</span><br><span style="color: hsl(120, 100%, 40%);">+                    ao2_ref(eprofile, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+                        ast_log(LOG_ERROR, "%s: Could not create datastore for eprofile '%s'\n", profile_create, args.id);</span><br><span style="color: hsl(120, 100%, 40%);">+                  return -1;</span><br><span style="color: hsl(120, 100%, 40%);">+            }</span><br><span style="color: hsl(120, 100%, 40%);">+             rc = 1;</span><br><span style="color: hsl(120, 100%, 40%);">+               ast_channel_datastore_add(chan, ds);</span><br><span style="color: hsl(120, 100%, 40%);">+  } else if (index < 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+            rc = ast_geoloc_datastore_add_eprofile(ds, eprofile);</span><br><span style="color: hsl(120, 100%, 40%);">+         if (rc <= 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+                     ao2_ref(eprofile, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+                        ast_log(LOG_ERROR, "%s: Could not add eprofile '%s' to datastore\n", profile_create, args.id);</span><br><span style="color: hsl(120, 100%, 40%);">+                      return -1;</span><br><span style="color: hsl(120, 100%, 40%);">+            }</span><br><span style="color: hsl(120, 100%, 40%);">+     } else {</span><br><span style="color: hsl(120, 100%, 40%);">+              rc = ast_geoloc_datastore_insert_eprofile(ds, eprofile, index);</span><br><span style="color: hsl(120, 100%, 40%);">+               if (rc <= 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+                     ao2_ref(eprofile, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+                        ast_log(LOG_ERROR, "%s: Could not insert eprofile '%s' to datastore\n", profile_create, args.id);</span><br><span style="color: hsl(120, 100%, 40%);">+                   return -1;</span><br><span style="color: hsl(120, 100%, 40%);">+            }</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   new_size = ast_str_alloca(16);</span><br><span style="color: hsl(120, 100%, 40%);">+        ast_str_append(&new_size, 0, "%d", rc);</span><br><span style="color: hsl(120, 100%, 40%);">+ pbx_builtin_setvar_helper(chan, "GEOLOC_PROFILE_COUNT", ast_str_buffer(new_size));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#define profile_delete "GeolocProfileDelete"</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static int geoloc_eprofile_delete(struct ast_channel *chan, const char *data)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+    char *parsed_data = ast_strdupa(data);</span><br><span style="color: hsl(120, 100%, 40%);">+        struct ast_datastore *ds;</span><br><span style="color: hsl(120, 100%, 40%);">+     int profile_count = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+        int index = -1;</span><br><span style="color: hsl(120, 100%, 40%);">+       struct ast_str *new_size;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   AST_DECLARE_APP_ARGS(args,</span><br><span style="color: hsl(120, 100%, 40%);">+            AST_APP_ARG(index);</span><br><span style="color: hsl(120, 100%, 40%);">+   );</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  /* Check for zero arguments */</span><br><span style="color: hsl(120, 100%, 40%);">+        if (ast_strlen_zero(parsed_data)) {</span><br><span style="color: hsl(120, 100%, 40%);">+           ast_log(LOG_ERROR, "%s: Cannot call without arguments\n", profile_delete);</span><br><span style="color: hsl(120, 100%, 40%);">+          return -1;</span><br><span style="color: hsl(120, 100%, 40%);">+    }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   AST_STANDARD_APP_ARGS(args, parsed_data);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   if (!ast_strlen_zero(args.index)) {</span><br><span style="color: hsl(120, 100%, 40%);">+           if (sscanf(args.index, "%30d", &index) != 1) {</span><br><span style="color: hsl(120, 100%, 40%);">+                  ast_log(LOG_ERROR, "%s: profile_index '%s' is invalid\n", profile_delete, args.index);</span><br><span style="color: hsl(120, 100%, 40%);">+                      return -1;</span><br><span style="color: hsl(120, 100%, 40%);">+            }</span><br><span style="color: hsl(120, 100%, 40%);">+     } else {</span><br><span style="color: hsl(120, 100%, 40%);">+              ast_log(LOG_ERROR, "%s: A profile_index is required\n", profile_delete);</span><br><span style="color: hsl(120, 100%, 40%);">+            return -1;</span><br><span style="color: hsl(120, 100%, 40%);">+    }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   ds = ast_geoloc_datastore_find(chan);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!ds) {</span><br><span style="color: hsl(120, 100%, 40%);">+            ast_log(LOG_WARNING, "%s: There are no geoloc profiles on this channel\n", profile_delete);</span><br><span style="color: hsl(120, 100%, 40%);">+         return -1;</span><br><span style="color: hsl(120, 100%, 40%);">+    }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   profile_count = ast_geoloc_datastore_size(ds);</span><br><span style="color: hsl(120, 100%, 40%);">+        if (index < -1 || index >= profile_count) {</span><br><span style="color: hsl(120, 100%, 40%);">+             ast_log(LOG_ERROR, "%s: Invalid profile_index '%d'.  It must be between 0 and %d\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                        profile_create, index, profile_count - 1);</span><br><span style="color: hsl(120, 100%, 40%);">+            return -1;</span><br><span style="color: hsl(120, 100%, 40%);">+    }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   ast_geoloc_datastore_delete_eprofile(ds, index);</span><br><span style="color: hsl(120, 100%, 40%);">+      profile_count = ast_geoloc_datastore_size(ds);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      new_size = ast_str_alloca(16);</span><br><span style="color: hsl(120, 100%, 40%);">+        ast_str_append(&new_size, 0, "%d", profile_count);</span><br><span style="color: hsl(120, 100%, 40%);">+      pbx_builtin_setvar_helper(chan, "GEOLOC_PROFILE_COUNT", ast_str_buffer(new_size));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+int geoloc_dialplan_unload(void)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+   ast_unregister_application(profile_delete);</span><br><span style="color: hsl(120, 100%, 40%);">+   ast_unregister_application(profile_create);</span><br><span style="color: hsl(120, 100%, 40%);">+   ast_custom_function_unregister(&geoloc_function);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       return AST_MODULE_LOAD_SUCCESS;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+int geoloc_dialplan_load(void)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+       int res = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        res = ast_custom_function_register(&geoloc_function);</span><br><span style="color: hsl(120, 100%, 40%);">+     if (res == 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+               res = ast_register_application_xml(profile_create, geoloc_eprofile_create);</span><br><span style="color: hsl(120, 100%, 40%);">+   }</span><br><span style="color: hsl(120, 100%, 40%);">+     if (res == 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+               res = ast_register_application_xml(profile_delete, geoloc_eprofile_delete);</span><br><span style="color: hsl(120, 100%, 40%);">+   }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   return res == 0 ? AST_MODULE_LOAD_SUCCESS : AST_MODULE_LOAD_DECLINE;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+int geoloc_dialplan_reload(void)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+        return AST_MODULE_LOAD_SUCCESS;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>diff --git a/res/res_geolocation/geoloc_doc.xml b/res/res_geolocation/geoloc_doc.xml</span><br><span>new file mode 100644</span><br><span>index 0000000..5c8bf79</span><br><span>--- /dev/null</span><br><span>+++ b/res/res_geolocation/geoloc_doc.xml</span><br><span>@@ -0,0 +1,235 @@</span><br><span style="color: hsl(120, 100%, 40%);">+<?xml version="1.0" encoding="UTF-8"?></span><br><span style="color: hsl(120, 100%, 40%);">+<!DOCTYPE docs SYSTEM "appdocsxml.dtd"></span><br><span style="color: hsl(120, 100%, 40%);">+<docs></span><br><span style="color: hsl(120, 100%, 40%);">+   <configInfo name="res_geolocation" language="en_US"></span><br><span style="color: hsl(120, 100%, 40%);">+                <synopsis>Core Geolocation Support</synopsis></span><br><span style="color: hsl(120, 100%, 40%);">+             <configFile name="geolocation.conf"></span><br><span style="color: hsl(120, 100%, 40%);">+                  <configObject name="location"></span><br><span style="color: hsl(120, 100%, 40%);">+                                <synopsis>Location</synopsis></span><br><span style="color: hsl(120, 100%, 40%);">+                             <description></span><br><span style="color: hsl(120, 100%, 40%);">+                                   <para>cffdffff</para></span><br><span style="color: hsl(120, 100%, 40%);">+                             </description></span><br><span style="color: hsl(120, 100%, 40%);">+                          <configOption name="type"></span><br><span style="color: hsl(120, 100%, 40%);">+                                    <synopsis>Must be of type 'location'.</synopsis></span><br><span style="color: hsl(120, 100%, 40%);">+                          </configOption></span><br><span style="color: hsl(120, 100%, 40%);">+                         <configOption name="format" default=""></span><br><span style="color: hsl(120, 100%, 40%);">+                                     <synopsis>Location specification type</synopsis></span><br><span style="color: hsl(120, 100%, 40%);">+                                  <description></span><br><span style="color: hsl(120, 100%, 40%);">+                                           <enumlist></span><br><span style="color: hsl(120, 100%, 40%);">+                                                      <enum name="civicAddress"></span><br><span style="color: hsl(120, 100%, 40%);">+                                                            <para></span><br><span style="color: hsl(120, 100%, 40%);">+                                                                  The <literal>location_info</literal></span><br><span style="color: hsl(120, 100%, 40%);">+                                                                      parameter must contain a comma separated list of IANA codes</span><br><span style="color: hsl(120, 100%, 40%);">+                                                                   or synonyms describing the civicAddress of this location.</span><br><span style="color: hsl(120, 100%, 40%);">+                                                                     The IANA codes and synonyms can be obtained by executing</span><br><span style="color: hsl(120, 100%, 40%);">+                                                                      the CLI command <literal>geoloc show civicAddr_mapping</literal>.</span><br><span style="color: hsl(120, 100%, 40%);">+                                                         </para></span><br><span style="color: hsl(120, 100%, 40%);">+                                                 </enum></span><br><span style="color: hsl(120, 100%, 40%);">+                                                 <enum name="GML"></span><br><span style="color: hsl(120, 100%, 40%);">+                                                             <para></span><br><span style="color: hsl(120, 100%, 40%);">+                                                                  The</span><br><span style="color: hsl(120, 100%, 40%);">+                                                                   <literal>location_info</literal> parameter must contain a comma</span><br><span style="color: hsl(120, 100%, 40%);">+                                                                   separated list valid GML elements describing this location.</span><br><span style="color: hsl(120, 100%, 40%);">+                                                           </para></span><br><span style="color: hsl(120, 100%, 40%);">+                                                 </enum></span><br><span style="color: hsl(120, 100%, 40%);">+                                                 <enum name="URI"></span><br><span style="color: hsl(120, 100%, 40%);">+                                                             <para></span><br><span style="color: hsl(120, 100%, 40%);">+                                                                  The</span><br><span style="color: hsl(120, 100%, 40%);">+                                                                   <literal>location_info</literal> parameter must contain a single</span><br><span style="color: hsl(120, 100%, 40%);">+                                                                  URI parameter which contains an external URI describing this location.</span><br><span style="color: hsl(120, 100%, 40%);">+                                                                </para></span><br><span style="color: hsl(120, 100%, 40%);">+                                                 </enum></span><br><span style="color: hsl(120, 100%, 40%);">+                                         </enumlist></span><br><span style="color: hsl(120, 100%, 40%);">+                                     </description></span><br><span style="color: hsl(120, 100%, 40%);">+                          </configOption></span><br><span style="color: hsl(120, 100%, 40%);">+                         <configOption name="location_info" default=""></span><br><span style="color: hsl(120, 100%, 40%);">+                                      <synopsis>Location information</synopsis></span><br><span style="color: hsl(120, 100%, 40%);">+                                 <description></span><br><span style="color: hsl(120, 100%, 40%);">+                                           <para>The contents of this parameter are specific to the</span><br><span style="color: hsl(120, 100%, 40%);">+                                                        location <literal>format</literal>.</para></span><br><span style="color: hsl(120, 100%, 40%);">+                                          <enumlist></span><br><span style="color: hsl(120, 100%, 40%);">+                                              <enum name="civicAddress"></span><br><span style="color: hsl(120, 100%, 40%);">+                                            <para></span><br><span style="color: hsl(120, 100%, 40%);">+                                          location_info = country=US,A1="New York",city_district=Manhattan,</span><br><span style="color: hsl(120, 100%, 40%);">+                                           A3="New York", house_number=1633, street=46th, street_suffix = Street,</span><br><span style="color: hsl(120, 100%, 40%);">+                                              postal_code=10222,floor=20,room=20A2</span><br><span style="color: hsl(120, 100%, 40%);">+                                          </para></span><br><span style="color: hsl(120, 100%, 40%);">+                                         </enum></span><br><span style="color: hsl(120, 100%, 40%);">+                                         <enum name="GML"></span><br><span style="color: hsl(120, 100%, 40%);">+                                             <para></span><br><span style="color: hsl(120, 100%, 40%);">+                                          location_info = Shape=Sphere, pos3d="39.12345 -105.98766 1920", radius=200</span><br><span style="color: hsl(120, 100%, 40%);">+                                          </para></span><br><span style="color: hsl(120, 100%, 40%);">+                                         </enum></span><br><span style="color: hsl(120, 100%, 40%);">+                                         <enum name="URI"></span><br><span style="color: hsl(120, 100%, 40%);">+                                             <para></span><br><span style="color: hsl(120, 100%, 40%);">+                                          location_info = URI=https:/something.com?exten=${EXTEN}</span><br><span style="color: hsl(120, 100%, 40%);">+                                               </para></span><br><span style="color: hsl(120, 100%, 40%);">+                                         </enum></span><br><span style="color: hsl(120, 100%, 40%);">+                                         </enumlist></span><br><span style="color: hsl(120, 100%, 40%);">+                                     </description></span><br><span style="color: hsl(120, 100%, 40%);">+                          </configOption></span><br><span style="color: hsl(120, 100%, 40%);">+                         <configOption name="location_source" default=""></span><br><span style="color: hsl(120, 100%, 40%);">+                                    <synopsis>Fully qualified host name</synopsis></span><br><span style="color: hsl(120, 100%, 40%);">+                                    <description></span><br><span style="color: hsl(120, 100%, 40%);">+                                           <para>This parameter isn't required but if provided, RFC8787 says it MUST be a fully</span><br><span style="color: hsl(120, 100%, 40%);">+                                                qualified host name.  IP addresses are specifically NOT allowed.  The value will be placed</span><br><span style="color: hsl(120, 100%, 40%);">+                                            in a <literal>loc-src</literal> parameter appended to the URI in the <literal></span><br><span style="color: hsl(120, 100%, 40%);">+                                              Geolocation</literal> header.</para></span><br><span style="color: hsl(120, 100%, 40%);">+                                      </description></span><br><span style="color: hsl(120, 100%, 40%);">+                          </configOption></span><br><span style="color: hsl(120, 100%, 40%);">+                         <configOption name="method" default=""></span><br><span style="color: hsl(120, 100%, 40%);">+                                     <synopsis>Location determination method</synopsis></span><br><span style="color: hsl(120, 100%, 40%);">+                                        <description></span><br><span style="color: hsl(120, 100%, 40%);">+                                           <para>This is a rarely used field in the specification that would</span><br><span style="color: hsl(120, 100%, 40%);">+                                               indicate the method used to determine the location.  Its usage and values should be</span><br><span style="color: hsl(120, 100%, 40%);">+                                           pre-negotiated with any recipients.</para></span><br><span style="color: hsl(120, 100%, 40%);">+                                              <enumlist></span><br><span style="color: hsl(120, 100%, 40%);">+                                              <enum name="GPS"/></span><br><span style="color: hsl(120, 100%, 40%);">+                                            <enum name="A-GPS"/></span><br><span style="color: hsl(120, 100%, 40%);">+                                          <enum name="Manual"/></span><br><span style="color: hsl(120, 100%, 40%);">+                                         <enum name="DHCP"/></span><br><span style="color: hsl(120, 100%, 40%);">+                                           <enum name="Triangulation"/></span><br><span style="color: hsl(120, 100%, 40%);">+                                          <enum name="Cell"/></span><br><span style="color: hsl(120, 100%, 40%);">+                                           <enum name="802.11"/></span><br><span style="color: hsl(120, 100%, 40%);">+                                         </enumlist></span><br><span style="color: hsl(120, 100%, 40%);">+                                     </description></span><br><span style="color: hsl(120, 100%, 40%);">+                          </configOption></span><br><span style="color: hsl(120, 100%, 40%);">+                 </configObject></span><br><span style="color: hsl(120, 100%, 40%);">+                 <configObject name="profile"></span><br><span style="color: hsl(120, 100%, 40%);">+                         <synopsis>Profile</synopsis></span><br><span style="color: hsl(120, 100%, 40%);">+                              <description></span><br><span style="color: hsl(120, 100%, 40%);">+                                   <para>cffdffff</para></span><br><span style="color: hsl(120, 100%, 40%);">+                             </description></span><br><span style="color: hsl(120, 100%, 40%);">+                          <configOption name="type"></span><br><span style="color: hsl(120, 100%, 40%);">+                                    <synopsis>Must be of type 'profile'.</synopsis></span><br><span style="color: hsl(120, 100%, 40%);">+                           </configOption></span><br><span style="color: hsl(120, 100%, 40%);">+                         <configOption name="pidf_element" default="device"></span><br><span style="color: hsl(120, 100%, 40%);">+                                 <synopsis>PIDF-LO element to place this profile in</synopsis></span><br><span style="color: hsl(120, 100%, 40%);">+                                     <description></span><br><span style="color: hsl(120, 100%, 40%);">+                                           <enumlist></span><br><span style="color: hsl(120, 100%, 40%);">+                                                      <enum name="tuple" /></span><br><span style="color: hsl(120, 100%, 40%);">+                                                 <enum name="device" /></span><br><span style="color: hsl(120, 100%, 40%);">+                                                        <enum name="person" /></span><br><span style="color: hsl(120, 100%, 40%);">+                                                </enumlist></span><br><span style="color: hsl(120, 100%, 40%);">+                                             <para></span><br><span style="color: hsl(120, 100%, 40%);">+                                                  Based on RFC5491 (see below) the recommended and default element</span><br><span style="color: hsl(120, 100%, 40%);">+                                                      is <literal>device</literal>.</span><br><span style="color: hsl(120, 100%, 40%);">+                                             </para></span><br><span style="color: hsl(120, 100%, 40%);">+                                 </description></span><br><span style="color: hsl(120, 100%, 40%);">+                                  <see-also></span><br><span style="color: hsl(120, 100%, 40%);">+                                              <ref type="link">https://www.rfc-editor.org/rfc/rfc5491.html#section-3.4</ref></span><br><span style="color: hsl(120, 100%, 40%);">+                                  </see-also></span><br><span style="color: hsl(120, 100%, 40%);">+                             </configOption></span><br><span style="color: hsl(120, 100%, 40%);">+                         <configOption name="location_reference" default=""></span><br><span style="color: hsl(120, 100%, 40%);">+                                 <synopsis>Reference to a location object</synopsis></span><br><span style="color: hsl(120, 100%, 40%);">+                               </configOption></span><br><span style="color: hsl(120, 100%, 40%);">+                         <configOption name="location_info_refinement" default=""></span><br><span style="color: hsl(120, 100%, 40%);">+                                   <synopsis>Reference to a location object</synopsis></span><br><span style="color: hsl(120, 100%, 40%);">+                               </configOption></span><br><span style="color: hsl(120, 100%, 40%);">+                         <configOption name="location_variables" default=""></span><br><span style="color: hsl(120, 100%, 40%);">+                                 <synopsis>Reference to a location object</synopsis></span><br><span style="color: hsl(120, 100%, 40%);">+                               </configOption></span><br><span style="color: hsl(120, 100%, 40%);">+                         <configOption name="usage_rules" default="yes"></span><br><span style="color: hsl(120, 100%, 40%);">+                                     <synopsis>location specification type</synopsis></span><br><span style="color: hsl(120, 100%, 40%);">+                                  <description></span><br><span style="color: hsl(120, 100%, 40%);">+                                           <para>xxxx</para></span><br><span style="color: hsl(120, 100%, 40%);">+                                 </description></span><br><span style="color: hsl(120, 100%, 40%);">+                          </configOption></span><br><span style="color: hsl(120, 100%, 40%);">+                         <configOption name="notes" default=""></span><br><span style="color: hsl(120, 100%, 40%);">+                                      <synopsis>Notes to be added to the outgoing PIDF-LO document</synopsis></span><br><span style="color: hsl(120, 100%, 40%);">+                                   <description></span><br><span style="color: hsl(120, 100%, 40%);">+                                           <para>The specification of this parameter will cause a</span><br><span style="color: hsl(120, 100%, 40%);">+                                          <literal>&lt;note-well&gt;</literal> element to be added to the</span><br><span style="color: hsl(120, 100%, 40%);">+                                           outgoing PIDF-LO document.  Its usage should be pre-negotiated with</span><br><span style="color: hsl(120, 100%, 40%);">+                                           any recipients.</para></span><br><span style="color: hsl(120, 100%, 40%);">+                                  </description></span><br><span style="color: hsl(120, 100%, 40%);">+                          </configOption></span><br><span style="color: hsl(120, 100%, 40%);">+                         <configOption name="profile_action" default="discard_incoming"></span><br><span style="color: hsl(120, 100%, 40%);">+                                     <synopsis>Determine which profile on a channel should be used</synopsis></span><br><span style="color: hsl(120, 100%, 40%);">+                                  <description></span><br><span style="color: hsl(120, 100%, 40%);">+                                           <enumlist></span><br><span style="color: hsl(120, 100%, 40%);">+                                                      <enum name="prefer_incoming"></span><br><span style="color: hsl(120, 100%, 40%);">+                                                 <para>Use the incoming profile if it exists and has location information, otherwise use the</span><br><span style="color: hsl(120, 100%, 40%);">+                                                     configured profile if it exists and has location information. If neither profile has location</span><br><span style="color: hsl(120, 100%, 40%);">+                                                 information, nothing is sent.</span><br><span style="color: hsl(120, 100%, 40%);">+                                                 </para></enum></span><br><span style="color: hsl(120, 100%, 40%);">+                                                    <enum name="prefer_config"></span><br><span style="color: hsl(120, 100%, 40%);">+                                                   <para>Use the configured profile if it exists and has location information, otherwise use the</span><br><span style="color: hsl(120, 100%, 40%);">+                                                   incoming profile if it exists and has location information. If neither profile has location</span><br><span style="color: hsl(120, 100%, 40%);">+                                                   information, nothing is sent.</span><br><span style="color: hsl(120, 100%, 40%);">+                                                 </para></enum></span><br><span style="color: hsl(120, 100%, 40%);">+                                                    <enum name="discard_incoming"</span><br><span style="color: hsl(120, 100%, 40%);">+                                                    ><para>Discard any incoming profile and use the configured profile if it exists and</span><br><span style="color: hsl(120, 100%, 40%);">+                                                  it has location information.  If the configured profile doesn't exist or has no</span><br><span style="color: hsl(120, 100%, 40%);">+                                                   location information, nothing is sent.</span><br><span style="color: hsl(120, 100%, 40%);">+                                                        </para></enum></span><br><span style="color: hsl(120, 100%, 40%);">+                                                    <enum name="discard_config"></span><br><span style="color: hsl(120, 100%, 40%);">+                                                  <para>Discard any configured profile and use the incoming profile if it exists and</span><br><span style="color: hsl(120, 100%, 40%);">+                                                      it has location information.  If the incoming profile doesn't exist or has no</span><br><span style="color: hsl(120, 100%, 40%);">+                                                     location information, nothing is sent.</span><br><span style="color: hsl(120, 100%, 40%);">+                                                        </para></enum></span><br><span style="color: hsl(120, 100%, 40%);">+                                            </enumlist></span><br><span style="color: hsl(120, 100%, 40%);">+                                     </description></span><br><span style="color: hsl(120, 100%, 40%);">+                          </configOption></span><br><span style="color: hsl(120, 100%, 40%);">+                 </configObject></span><br><span style="color: hsl(120, 100%, 40%);">+         </configFile></span><br><span style="color: hsl(120, 100%, 40%);">+   </configInfo></span><br><span style="color: hsl(120, 100%, 40%);">+   <function name="GEOLOC_PROFILE" language="en_US"></span><br><span style="color: hsl(120, 100%, 40%);">+           <synopsis></span><br><span style="color: hsl(120, 100%, 40%);">+                      Get or Set a field in a geolocation profile</span><br><span style="color: hsl(120, 100%, 40%);">+           </synopsis></span><br><span style="color: hsl(120, 100%, 40%);">+             <syntax></span><br><span style="color: hsl(120, 100%, 40%);">+                        <parameter name="field" required="true"></span><br><span style="color: hsl(120, 100%, 40%);">+                            <para>The profile field to operate on.</para></span><br><span style="color: hsl(120, 100%, 40%);">+                     </parameter></span><br><span style="color: hsl(120, 100%, 40%);">+                    <parameter name="profile_index" required="false"></span><br><span style="color: hsl(120, 100%, 40%);">+                           <para>The index of the profile to operate on.  Not required for the special fields.</para></span><br><span style="color: hsl(120, 100%, 40%);">+                        </parameter></span><br><span style="color: hsl(120, 100%, 40%);">+            </syntax></span><br><span style="color: hsl(120, 100%, 40%);">+       </function></span><br><span style="color: hsl(120, 100%, 40%);">+     <application name="GeolocProfileCreate" language="en_US"></span><br><span style="color: hsl(120, 100%, 40%);">+           <synopsis></span><br><span style="color: hsl(120, 100%, 40%);">+                      Create a new, empty Geolocation Profile on a channel</span><br><span style="color: hsl(120, 100%, 40%);">+          </synopsis></span><br><span style="color: hsl(120, 100%, 40%);">+             <syntax></span><br><span style="color: hsl(120, 100%, 40%);">+                        <parameter name="id" required="true"><para></span><br><span style="color: hsl(120, 100%, 40%);">+                           The id of the new profile.</span><br><span style="color: hsl(120, 100%, 40%);">+                    </para></parameter></span><br><span style="color: hsl(120, 100%, 40%);">+                       <parameter name="profile_index" required="false"><para></span><br><span style="color: hsl(120, 100%, 40%);">+                        The position at which to insert the new eprofile.</span><br><span style="color: hsl(120, 100%, 40%);">+                     Existing profiles will be moved forward to make room.</span><br><span style="color: hsl(120, 100%, 40%);">+                         Leave empty to append to the end of the list.</span><br><span style="color: hsl(120, 100%, 40%);">+                        </para></parameter></span><br><span style="color: hsl(120, 100%, 40%);">+               </syntax></span><br><span style="color: hsl(120, 100%, 40%);">+               <description></span><br><span style="color: hsl(120, 100%, 40%);">+                   <para>This application adds a new, empty Geolocation Profile to a channel.</para></span><br><span style="color: hsl(120, 100%, 40%);">+                 <para>The following variable is set:</para></span><br><span style="color: hsl(120, 100%, 40%);">+                       <variablelist></span><br><span style="color: hsl(120, 100%, 40%);">+                          <variable name="GEOLOC_PROFILE_COUNT"></span><br><span style="color: hsl(120, 100%, 40%);">+                                        <para>The number of profiles on the channel after the new one is created</para></span><br><span style="color: hsl(120, 100%, 40%);">+                           </variable></span><br><span style="color: hsl(120, 100%, 40%);">+                     </variablelist></span><br><span style="color: hsl(120, 100%, 40%);">+         </description></span><br><span style="color: hsl(120, 100%, 40%);">+  </application></span><br><span style="color: hsl(120, 100%, 40%);">+  <application name="GeolocProfileDelete" language="en_US"></span><br><span style="color: hsl(120, 100%, 40%);">+           <synopsis></span><br><span style="color: hsl(120, 100%, 40%);">+                      Delete a Geolocation Profile from a channel</span><br><span style="color: hsl(120, 100%, 40%);">+           </synopsis></span><br><span style="color: hsl(120, 100%, 40%);">+             <syntax></span><br><span style="color: hsl(120, 100%, 40%);">+                        <parameter name="profile_index" required="true"><para></span><br><span style="color: hsl(120, 100%, 40%);">+                         The position of the profile to be deleted</span><br><span style="color: hsl(120, 100%, 40%);">+                     Existing profiles will be moved back.</span><br><span style="color: hsl(120, 100%, 40%);">+                        </para></parameter></span><br><span style="color: hsl(120, 100%, 40%);">+               </syntax></span><br><span style="color: hsl(120, 100%, 40%);">+               <description></span><br><span style="color: hsl(120, 100%, 40%);">+                   <para>This application deletes a Geolocation Profile from a channel.</para></span><br><span style="color: hsl(120, 100%, 40%);">+                       <para>The following variable is set:</para></span><br><span style="color: hsl(120, 100%, 40%);">+                       <variablelist></span><br><span style="color: hsl(120, 100%, 40%);">+                          <variable name="GEOLOC_PROFILE_COUNT"></span><br><span style="color: hsl(120, 100%, 40%);">+                                        <para>The number of profiles left on the channel after the delete.</para></span><br><span style="color: hsl(120, 100%, 40%);">+                         </variable></span><br><span style="color: hsl(120, 100%, 40%);">+                     </variablelist></span><br><span style="color: hsl(120, 100%, 40%);">+         </description></span><br><span style="color: hsl(120, 100%, 40%);">+  </application></span><br><span style="color: hsl(120, 100%, 40%);">+</docs></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>diff --git a/res/res_geolocation/geoloc_eprofile.c b/res/res_geolocation/geoloc_eprofile.c</span><br><span>new file mode 100644</span><br><span>index 0000000..64244f4</span><br><span>--- /dev/null</span><br><span>+++ b/res/res_geolocation/geoloc_eprofile.c</span><br><span>@@ -0,0 +1,1002 @@</span><br><span style="color: hsl(120, 100%, 40%);">+/*</span><br><span style="color: hsl(120, 100%, 40%);">+ * Asterisk -- An open source telephony toolkit.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * Copyright (C) 2022, Sangoma Technologies Corporation</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * George Joseph <gjoseph@sangoma.com></span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * See http://www.asterisk.org for more information about</span><br><span style="color: hsl(120, 100%, 40%);">+ * the Asterisk project. Please do not directly contact</span><br><span style="color: hsl(120, 100%, 40%);">+ * any of the maintainers of this project for assistance;</span><br><span style="color: hsl(120, 100%, 40%);">+ * the project provides a web site, mailing lists and IRC</span><br><span style="color: hsl(120, 100%, 40%);">+ * channels for your use.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * This program is free software, distributed under the terms of</span><br><span style="color: hsl(120, 100%, 40%);">+ * the GNU General Public License Version 2. See the LICENSE file</span><br><span style="color: hsl(120, 100%, 40%);">+ * at the top of the source tree.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include "asterisk.h"</span><br><span style="color: hsl(120, 100%, 40%);">+#include "asterisk/pbx.h"</span><br><span style="color: hsl(120, 100%, 40%);">+#include "asterisk/strings.h"</span><br><span style="color: hsl(120, 100%, 40%);">+#include "asterisk/xml.h"</span><br><span style="color: hsl(120, 100%, 40%);">+#include "geoloc_private.h"</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+extern const uint8_t _binary_res_geolocation_pidf_to_eprofile_xslt_start[];</span><br><span style="color: hsl(120, 100%, 40%);">+extern const uint8_t _binary_res_geolocation_pidf_to_eprofile_xslt_end[];</span><br><span style="color: hsl(120, 100%, 40%);">+static size_t pidf_to_eprofile_xslt_size;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+extern const uint8_t _binary_res_geolocation_pidf_lo_test_xml_start[];</span><br><span style="color: hsl(120, 100%, 40%);">+extern const uint8_t _binary_res_geolocation_pidf_lo_test_xml_end[];</span><br><span style="color: hsl(120, 100%, 40%);">+static size_t pidf_lo_test_xml_size;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+extern const uint8_t _binary_res_geolocation_eprofile_to_pidf_xslt_start[];</span><br><span style="color: hsl(120, 100%, 40%);">+extern const uint8_t _binary_res_geolocation_eprofile_to_pidf_xslt_end[];</span><br><span style="color: hsl(120, 100%, 40%);">+static size_t eprofile_to_pidf_xslt_size;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static struct ast_xslt_doc *eprofile_to_pidf_xslt;</span><br><span style="color: hsl(120, 100%, 40%);">+static struct ast_xslt_doc *pidf_to_eprofile_xslt;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static struct ast_sorcery *geoloc_sorcery;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#define DUP_VARS(_dest, _source) \</span><br><span style="color: hsl(120, 100%, 40%);">+({ \</span><br><span style="color: hsl(120, 100%, 40%);">+ int _rc = 0; \</span><br><span style="color: hsl(120, 100%, 40%);">+        if (_source) { \</span><br><span style="color: hsl(120, 100%, 40%);">+              struct ast_variable *_vars = ast_variables_dup(_source); \</span><br><span style="color: hsl(120, 100%, 40%);">+            if (!_vars) { \</span><br><span style="color: hsl(120, 100%, 40%);">+                       _rc = -1; \</span><br><span style="color: hsl(120, 100%, 40%);">+           } else { \</span><br><span style="color: hsl(120, 100%, 40%);">+                    _dest = _vars; \</span><br><span style="color: hsl(120, 100%, 40%);">+              } \</span><br><span style="color: hsl(120, 100%, 40%);">+   } \</span><br><span style="color: hsl(120, 100%, 40%);">+   (_rc); \</span><br><span style="color: hsl(120, 100%, 40%);">+})</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static void geoloc_eprofile_destructor(void *obj)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  struct ast_geoloc_eprofile *eprofile = obj;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_string_field_free_memory(eprofile);</span><br><span style="color: hsl(120, 100%, 40%);">+       ast_variables_destroy(eprofile->location_info);</span><br><span style="color: hsl(120, 100%, 40%);">+    ast_variables_destroy(eprofile->location_refinement);</span><br><span style="color: hsl(120, 100%, 40%);">+      ast_variables_destroy(eprofile->location_variables);</span><br><span style="color: hsl(120, 100%, 40%);">+       ast_variables_destroy(eprofile->effective_location);</span><br><span style="color: hsl(120, 100%, 40%);">+       ast_variables_destroy(eprofile->usage_rules);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct ast_geoloc_eprofile *ast_geoloc_eprofile_alloc(const char *name)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+     struct ast_geoloc_eprofile *eprofile = ao2_alloc_options(sizeof(*eprofile),</span><br><span style="color: hsl(120, 100%, 40%);">+           geoloc_eprofile_destructor, AO2_ALLOC_OPT_LOCK_NOLOCK);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     ast_string_field_init(eprofile, 256);</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_string_field_set(eprofile, id, name); /* SAFE string fields handle NULL */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      return eprofile;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+int ast_geoloc_eprofile_refresh_location(struct ast_geoloc_eprofile *eprofile)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+      struct ast_geoloc_location *loc = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+       struct ast_variable *temp_locinfo = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+     struct ast_variable *temp_effloc = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+      struct ast_variable *var;</span><br><span style="color: hsl(120, 100%, 40%);">+     int rc = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!eprofile) {</span><br><span style="color: hsl(120, 100%, 40%);">+              return -1;</span><br><span style="color: hsl(120, 100%, 40%);">+    }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   if (!ast_strlen_zero(eprofile->location_reference)) {</span><br><span style="color: hsl(120, 100%, 40%);">+              loc = ast_sorcery_retrieve_by_id(geoloc_sorcery, "location", eprofile->location_reference);</span><br><span style="color: hsl(120, 100%, 40%);">+              if (!loc) {</span><br><span style="color: hsl(120, 100%, 40%);">+                   ast_log(LOG_ERROR, "Profile '%s' referenced location '%s' does not exist!", eprofile->id,</span><br><span style="color: hsl(120, 100%, 40%);">+                                eprofile->location_reference);</span><br><span style="color: hsl(120, 100%, 40%);">+                     return -1;</span><br><span style="color: hsl(120, 100%, 40%);">+            }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+           eprofile->format = loc->format;</span><br><span style="color: hsl(120, 100%, 40%);">+         rc = DUP_VARS(temp_locinfo, loc->location_info);</span><br><span style="color: hsl(120, 100%, 40%);">+           ast_string_field_set(eprofile, method, loc->method);</span><br><span style="color: hsl(120, 100%, 40%);">+               ao2_ref(loc, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+             if (rc != 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+                        return -1;</span><br><span style="color: hsl(120, 100%, 40%);">+            }</span><br><span style="color: hsl(120, 100%, 40%);">+     } else {</span><br><span style="color: hsl(120, 100%, 40%);">+              temp_locinfo = eprofile->location_info;</span><br><span style="color: hsl(120, 100%, 40%);">+    }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   rc = DUP_VARS(temp_effloc, temp_locinfo);</span><br><span style="color: hsl(120, 100%, 40%);">+     if (rc != 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+                ast_variables_destroy(temp_locinfo);</span><br><span style="color: hsl(120, 100%, 40%);">+          return -1;</span><br><span style="color: hsl(120, 100%, 40%);">+    }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   if (eprofile->location_refinement) {</span><br><span style="color: hsl(120, 100%, 40%);">+               for (var = eprofile->location_refinement; var; var = var->next) {</span><br><span style="color: hsl(120, 100%, 40%);">+                       struct ast_variable *newvar = ast_variable_new(var->name, var->value, "");</span><br><span style="color: hsl(120, 100%, 40%);">+                    if (!newvar) {</span><br><span style="color: hsl(120, 100%, 40%);">+                                ast_variables_destroy(temp_locinfo);</span><br><span style="color: hsl(120, 100%, 40%);">+                          ast_variables_destroy(temp_effloc);</span><br><span style="color: hsl(120, 100%, 40%);">+                           return -1;</span><br><span style="color: hsl(120, 100%, 40%);">+                    }</span><br><span style="color: hsl(120, 100%, 40%);">+                     if (ast_variable_list_replace(&temp_effloc, newvar)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                            ast_variable_list_append(&temp_effloc, newvar);</span><br><span style="color: hsl(120, 100%, 40%);">+                   }</span><br><span style="color: hsl(120, 100%, 40%);">+             }</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   ast_variables_destroy(eprofile->location_info);</span><br><span style="color: hsl(120, 100%, 40%);">+    eprofile->location_info = temp_locinfo;</span><br><span style="color: hsl(120, 100%, 40%);">+    ast_variables_destroy(eprofile->effective_location);</span><br><span style="color: hsl(120, 100%, 40%);">+       eprofile->effective_location = temp_effloc;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct ast_geoloc_eprofile *ast_geoloc_eprofile_create_from_profile(struct ast_geoloc_profile *profile)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+    struct ast_geoloc_eprofile *eprofile;</span><br><span style="color: hsl(120, 100%, 40%);">+ const char *profile_id;</span><br><span style="color: hsl(120, 100%, 40%);">+       int rc = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!profile) {</span><br><span style="color: hsl(120, 100%, 40%);">+               return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+  }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   profile_id = ast_sorcery_object_get_id(profile);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    eprofile = ast_geoloc_eprofile_alloc(profile_id);</span><br><span style="color: hsl(120, 100%, 40%);">+     if (!eprofile) {</span><br><span style="color: hsl(120, 100%, 40%);">+              return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+  }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   ao2_lock(profile);</span><br><span style="color: hsl(120, 100%, 40%);">+    eprofile->geolocation_routing = profile->geolocation_routing;</span><br><span style="color: hsl(120, 100%, 40%);">+   eprofile->pidf_element = profile->pidf_element;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       rc = ast_string_field_set(eprofile, location_reference, profile->location_reference);</span><br><span style="color: hsl(120, 100%, 40%);">+      if (rc == 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+                ast_string_field_set(eprofile, notes, profile->notes);</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+     if (rc == 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+                rc = DUP_VARS(eprofile->location_refinement, profile->location_refinement);</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+     if (rc == 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+                rc = DUP_VARS(eprofile->location_variables, profile->location_variables);</span><br><span style="color: hsl(120, 100%, 40%);">+       }</span><br><span style="color: hsl(120, 100%, 40%);">+     if (rc == 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+                rc = DUP_VARS(eprofile->usage_rules, profile->usage_rules);</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+     if (rc != 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+                ao2_unlock(profile);</span><br><span style="color: hsl(120, 100%, 40%);">+          ao2_ref(eprofile, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+                return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+  }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   eprofile->action = profile->action;</span><br><span style="color: hsl(120, 100%, 40%);">+     ao2_unlock(profile);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        if (ast_geoloc_eprofile_refresh_location(eprofile) != 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+            ao2_ref(eprofile, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+                return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+  }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   return eprofile;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static int set_loc_src(struct ast_geoloc_eprofile *eprofile, const char *uri, const char *ref_str)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  char *local_uri = ast_strdupa(uri);</span><br><span style="color: hsl(120, 100%, 40%);">+   char *loc_src = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       loc_src = strchr(local_uri, ';');</span><br><span style="color: hsl(120, 100%, 40%);">+     if (loc_src) {</span><br><span style="color: hsl(120, 100%, 40%);">+                loc_src = '\0';</span><br><span style="color: hsl(120, 100%, 40%);">+               loc_src++;</span><br><span style="color: hsl(120, 100%, 40%);">+    }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   if (!ast_strlen_zero(loc_src)) {</span><br><span style="color: hsl(120, 100%, 40%);">+              if (ast_begins_with(loc_src, "loc-src=")) {</span><br><span style="color: hsl(120, 100%, 40%);">+                 struct ast_sockaddr loc_source_addr;</span><br><span style="color: hsl(120, 100%, 40%);">+                  int rc = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+                   loc_src += 8;</span><br><span style="color: hsl(120, 100%, 40%);">+                 rc = ast_sockaddr_parse(&loc_source_addr, loc_src, PARSE_PORT_FORBID);</span><br><span style="color: hsl(120, 100%, 40%);">+                    if (rc == 1) {</span><br><span style="color: hsl(120, 100%, 40%);">+                                ast_log(LOG_WARNING, "%s: URI '%s' has an invalid 'loc-src' parameter."</span><br><span style="color: hsl(120, 100%, 40%);">+                                     " RFC8787 states that IP addresses MUST be dropped.\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                                     ref_str, uri);</span><br><span style="color: hsl(120, 100%, 40%);">+                                return -1;</span><br><span style="color: hsl(120, 100%, 40%);">+                    } else {</span><br><span style="color: hsl(120, 100%, 40%);">+                              ast_string_field_set(eprofile, location_source, loc_src);</span><br><span style="color: hsl(120, 100%, 40%);">+                     }</span><br><span style="color: hsl(120, 100%, 40%);">+             }</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+     return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct ast_geoloc_eprofile *ast_geoloc_eprofile_create_from_uri(const char *uri,</span><br><span style="color: hsl(120, 100%, 40%);">+      const char *ref_str)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+       struct ast_geoloc_eprofile *eprofile = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+  char *ra = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+      char *local_uri;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    if (ast_strlen_zero(uri)) {</span><br><span style="color: hsl(120, 100%, 40%);">+           return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+  }</span><br><span style="color: hsl(120, 100%, 40%);">+     local_uri = ast_strdupa(uri);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       if (local_uri[0] == '<') {</span><br><span style="color: hsl(120, 100%, 40%);">+         local_uri++;</span><br><span style="color: hsl(120, 100%, 40%);">+  }</span><br><span style="color: hsl(120, 100%, 40%);">+     ra = strchr(local_uri, '>');</span><br><span style="color: hsl(120, 100%, 40%);">+       if (ra) {</span><br><span style="color: hsl(120, 100%, 40%);">+             *ra = '\0';</span><br><span style="color: hsl(120, 100%, 40%);">+   }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   ast_strip(local_uri);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       eprofile = ast_geoloc_eprofile_alloc(local_uri);</span><br><span style="color: hsl(120, 100%, 40%);">+      if (!eprofile) {</span><br><span style="color: hsl(120, 100%, 40%);">+              return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+  }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   set_loc_src(eprofile, uri, ref_str);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        eprofile->format = AST_GEOLOC_FORMAT_URI;</span><br><span style="color: hsl(120, 100%, 40%);">+  eprofile->location_info = ast_variable_new("URI", local_uri, "");</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    return eprofile;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static struct ast_variable *geoloc_eprofile_resolve_varlist(struct ast_variable *source,</span><br><span style="color: hsl(120, 100%, 40%);">+       struct ast_variable *variables, struct ast_channel *chan)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  struct ast_variable *dest = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+     struct ast_variable *var = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+      struct varshead *vh = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+   struct ast_str *buf = ast_str_alloca(256);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  if (!source || !chan) {</span><br><span style="color: hsl(120, 100%, 40%);">+               return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+  }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   /*</span><br><span style="color: hsl(120, 100%, 40%);">+     * ast_str_substitute_variables does only minimal recursive resolution so we need to</span><br><span style="color: hsl(120, 100%, 40%);">+   * pre-resolve each variable in the "variables" list, then use that result to</span><br><span style="color: hsl(120, 100%, 40%);">+        * do the final pass on the "source" variable list.</span><br><span style="color: hsl(120, 100%, 40%);">+  */</span><br><span style="color: hsl(120, 100%, 40%);">+   if (variables) {</span><br><span style="color: hsl(120, 100%, 40%);">+              var = variables;</span><br><span style="color: hsl(120, 100%, 40%);">+              vh = ast_var_list_create();</span><br><span style="color: hsl(120, 100%, 40%);">+           if (!vh) {</span><br><span style="color: hsl(120, 100%, 40%);">+                    return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+          }</span><br><span style="color: hsl(120, 100%, 40%);">+             for ( ; var; var = var->next) {</span><br><span style="color: hsl(120, 100%, 40%);">+                    ast_str_substitute_variables_full2(&buf, 0, chan, vh, var->value, NULL, 1);</span><br><span style="color: hsl(120, 100%, 40%);">+                    AST_VAR_LIST_INSERT_TAIL(vh, ast_var_assign(var->name, ast_str_buffer(buf)));</span><br><span style="color: hsl(120, 100%, 40%);">+                      ast_str_reset(buf);</span><br><span style="color: hsl(120, 100%, 40%);">+           }</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   var = source;</span><br><span style="color: hsl(120, 100%, 40%);">+ for ( ; var; var = var->next) {</span><br><span style="color: hsl(120, 100%, 40%);">+            struct ast_variable *newvar = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+           ast_str_substitute_variables_full2(&buf, 0, chan, vh, var->value, NULL, 1);</span><br><span style="color: hsl(120, 100%, 40%);">+            newvar = ast_variable_new(var->name, ast_str_buffer(buf), "");</span><br><span style="color: hsl(120, 100%, 40%);">+           if (!newvar) {</span><br><span style="color: hsl(120, 100%, 40%);">+                        ast_variables_destroy(dest);</span><br><span style="color: hsl(120, 100%, 40%);">+                  ast_var_list_destroy(vh);</span><br><span style="color: hsl(120, 100%, 40%);">+                     return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+          }</span><br><span style="color: hsl(120, 100%, 40%);">+             ast_variable_list_append(&dest, newvar);</span><br><span style="color: hsl(120, 100%, 40%);">+          ast_str_reset(buf);</span><br><span style="color: hsl(120, 100%, 40%);">+   }</span><br><span style="color: hsl(120, 100%, 40%);">+     ast_var_list_destroy(vh);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   return dest;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+const char *ast_geoloc_eprofile_to_uri(struct ast_geoloc_eprofile *eprofile,</span><br><span style="color: hsl(120, 100%, 40%);">+     struct ast_channel *chan, struct ast_str **buf, const char *ref_string)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+    const char *uri = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+       struct ast_variable *resolved = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+ char *result;</span><br><span style="color: hsl(120, 100%, 40%);">+ int we_created_buf = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     if (!eprofile || !buf) {</span><br><span style="color: hsl(120, 100%, 40%);">+              return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+  }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   if (eprofile->format != AST_GEOLOC_FORMAT_URI) {</span><br><span style="color: hsl(120, 100%, 40%);">+           ast_log(LOG_ERROR, "%s: '%s' is not a URI profile.  It's '%s'\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                       ref_string, eprofile->id, geoloc_format_to_name(eprofile->format));</span><br><span style="color: hsl(120, 100%, 40%);">+             return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+  }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   resolved = geoloc_eprofile_resolve_varlist(eprofile->effective_location,</span><br><span style="color: hsl(120, 100%, 40%);">+           eprofile->location_variables, chan);</span><br><span style="color: hsl(120, 100%, 40%);">+       if (!resolved) {</span><br><span style="color: hsl(120, 100%, 40%);">+              return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+  }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   uri = ast_variable_find_in_list(resolved, "URI");</span><br><span style="color: hsl(120, 100%, 40%);">+   result = uri ? ast_strdupa(uri) : NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+       ast_variables_destroy(resolved);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    if (ast_strlen_zero(result)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                ast_log(LOG_ERROR, "%s: '%s' is a URI profile but had no, or an empty, 'URI' entry in location_info\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                     ref_string, eprofile->id);</span><br><span style="color: hsl(120, 100%, 40%);">+         return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+  }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   if (!*buf) {</span><br><span style="color: hsl(120, 100%, 40%);">+          *buf = ast_str_create(256);</span><br><span style="color: hsl(120, 100%, 40%);">+           if (!*buf) {</span><br><span style="color: hsl(120, 100%, 40%);">+                  return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+          }</span><br><span style="color: hsl(120, 100%, 40%);">+             we_created_buf = 1;</span><br><span style="color: hsl(120, 100%, 40%);">+   }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   if (ast_str_append(buf, 0, "%s", result) <= 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+         if (we_created_buf) {</span><br><span style="color: hsl(120, 100%, 40%);">+                 ast_free(*buf);</span><br><span style="color: hsl(120, 100%, 40%);">+                       *buf = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+                  return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+          }</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   return ast_str_buffer(*buf);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static struct ast_variable *var_list_from_node(struct ast_xml_node *node, const char *reference_string)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ struct ast_variable *list = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+     struct ast_xml_node *container;</span><br><span style="color: hsl(120, 100%, 40%);">+       struct ast_xml_node *child;</span><br><span style="color: hsl(120, 100%, 40%);">+   struct ast_variable *var;</span><br><span style="color: hsl(120, 100%, 40%);">+     RAII_VAR(struct ast_str *, buf, NULL, ast_free);</span><br><span style="color: hsl(120, 100%, 40%);">+      SCOPE_ENTER(3, "%s\n", reference_string);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ container = ast_xml_node_get_children(node);</span><br><span style="color: hsl(120, 100%, 40%);">+  for (child = container; child; child = ast_xml_node_get_next(child)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                const char *name = ast_xml_node_get_name(child);</span><br><span style="color: hsl(120, 100%, 40%);">+              const char *value = ast_xml_get_text(child);</span><br><span style="color: hsl(120, 100%, 40%);">+          const char *uom = ast_xml_get_attribute(child, "uom");</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+            if (uom) {</span><br><span style="color: hsl(120, 100%, 40%);">+                    /* '20 radians\0' */</span><br><span style="color: hsl(120, 100%, 40%);">+                  char *newval = ast_malloc(strlen(value) + 1 + strlen(uom) + 1);</span><br><span style="color: hsl(120, 100%, 40%);">+                       sprintf(newval, "%s %s", value, uom);</span><br><span style="color: hsl(120, 100%, 40%);">+                       var = ast_variable_new(name, newval, "");</span><br><span style="color: hsl(120, 100%, 40%);">+                   ast_free(newval);</span><br><span style="color: hsl(120, 100%, 40%);">+             } else {</span><br><span style="color: hsl(120, 100%, 40%);">+                      var = ast_variable_new(name, value, "");</span><br><span style="color: hsl(120, 100%, 40%);">+            }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+           if (!var) {</span><br><span style="color: hsl(120, 100%, 40%);">+                   ast_variables_destroy(list);</span><br><span style="color: hsl(120, 100%, 40%);">+                  SCOPE_EXIT_RTN_VALUE(NULL, "%s: Allocation failure\n", reference_string);</span><br><span style="color: hsl(120, 100%, 40%);">+           }</span><br><span style="color: hsl(120, 100%, 40%);">+             ast_variable_list_append(&list, var);</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   ast_variable_list_join(list, ", ", "=", "\"", &buf);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ SCOPE_EXIT_RTN_VALUE(list, "%s: Done. %s\n", reference_string, ast_str_buffer(buf));</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static struct ast_variable *var_list_from_loc_info(struct ast_xml_node *locinfo,</span><br><span style="color: hsl(120, 100%, 40%);">+ enum ast_geoloc_format format, const char *reference_string)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+       struct ast_variable *list = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+     struct ast_xml_node *container;</span><br><span style="color: hsl(120, 100%, 40%);">+       struct ast_variable *var;</span><br><span style="color: hsl(120, 100%, 40%);">+     RAII_VAR(struct ast_str *, buf, NULL, ast_free);</span><br><span style="color: hsl(120, 100%, 40%);">+      SCOPE_ENTER(3, "%s\n", reference_string);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ container = ast_xml_node_get_children(locinfo);</span><br><span style="color: hsl(120, 100%, 40%);">+       if (format == AST_GEOLOC_FORMAT_CIVIC_ADDRESS) {</span><br><span style="color: hsl(120, 100%, 40%);">+              var = ast_variable_new("lang", ast_xml_get_attribute(container, "lang"), "");</span><br><span style="color: hsl(120, 100%, 40%);">+           if (!var) {</span><br><span style="color: hsl(120, 100%, 40%);">+                   SCOPE_EXIT_RTN_VALUE(NULL, "%s: Allocation failure\n", reference_string);</span><br><span style="color: hsl(120, 100%, 40%);">+           }</span><br><span style="color: hsl(120, 100%, 40%);">+             ast_variable_list_append(&list, var);</span><br><span style="color: hsl(120, 100%, 40%);">+     } else {</span><br><span style="color: hsl(120, 100%, 40%);">+              var = ast_variable_new("shape", ast_xml_node_get_name(container), "");</span><br><span style="color: hsl(120, 100%, 40%);">+            if (!var) {</span><br><span style="color: hsl(120, 100%, 40%);">+                   SCOPE_EXIT_RTN_VALUE(NULL, "%s: Allocation failure\n", reference_string);</span><br><span style="color: hsl(120, 100%, 40%);">+           }</span><br><span style="color: hsl(120, 100%, 40%);">+             ast_variable_list_append(&list, var);</span><br><span style="color: hsl(120, 100%, 40%);">+             var = ast_variable_new("crs", ast_xml_get_attribute(container, "srsName"), "");</span><br><span style="color: hsl(120, 100%, 40%);">+         if (!var) {</span><br><span style="color: hsl(120, 100%, 40%);">+                   ast_variables_destroy(list);</span><br><span style="color: hsl(120, 100%, 40%);">+                  SCOPE_EXIT_RTN_VALUE(NULL, "%s: Allocation failure\n", reference_string);</span><br><span style="color: hsl(120, 100%, 40%);">+           }</span><br><span style="color: hsl(120, 100%, 40%);">+             ast_variable_list_append(&list, var);</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   ast_variable_list_append(&list, var_list_from_node(container, reference_string));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       ast_variable_list_join(list, ", ", "=", "\"", &buf);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ SCOPE_EXIT_RTN_VALUE(list, "%s: Done. %s\n", reference_string, ast_str_buffer(buf));</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static struct ast_geoloc_eprofile *geoloc_eprofile_create_from_xslt_result(</span><br><span style="color: hsl(120, 100%, 40%);">+      struct ast_xml_doc *result_doc,</span><br><span style="color: hsl(120, 100%, 40%);">+       const char *reference_string)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+      struct ast_geoloc_eprofile *eprofile;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct ast_xml_node *presence = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct ast_xml_node *pidf_element = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+     struct ast_xml_node *location_info = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+    struct ast_xml_node *usage_rules = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+      struct ast_xml_node *method = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+   struct ast_xml_node *note_well = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+        char *doc_str;</span><br><span style="color: hsl(120, 100%, 40%);">+        int doc_len;</span><br><span style="color: hsl(120, 100%, 40%);">+  const char *id;</span><br><span style="color: hsl(120, 100%, 40%);">+       const char *format_str;</span><br><span style="color: hsl(120, 100%, 40%);">+       const char *pidf_element_str;</span><br><span style="color: hsl(120, 100%, 40%);">+ const char *method_str;</span><br><span style="color: hsl(120, 100%, 40%);">+       const char *note_well_str;</span><br><span style="color: hsl(120, 100%, 40%);">+    SCOPE_ENTER(3, "%s\n", reference_string);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_xml_doc_dump_memory(result_doc, &doc_str, &doc_len);</span><br><span style="color: hsl(120, 100%, 40%);">+      ast_trace(5, "xslt result doc:\n%s\n", doc_str);</span><br><span style="color: hsl(120, 100%, 40%);">+    ast_xml_free_text(doc_str);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ presence = ast_xml_get_root(result_doc);</span><br><span style="color: hsl(120, 100%, 40%);">+      pidf_element = ast_xml_node_get_children(presence);</span><br><span style="color: hsl(120, 100%, 40%);">+   location_info = ast_xml_find_child_element(pidf_element, "location-info", NULL, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+      usage_rules = ast_xml_find_child_element(pidf_element, "usage-rules", NULL, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+  method = ast_xml_find_child_element(pidf_element, "method", NULL, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+    note_well = ast_xml_find_child_element(pidf_element, "note-well", NULL, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    id = S_OR(ast_xml_get_attribute(pidf_element, "id"), ast_xml_get_attribute(presence, "entity"));</span><br><span style="color: hsl(120, 100%, 40%);">+  eprofile = ast_geoloc_eprofile_alloc(id);</span><br><span style="color: hsl(120, 100%, 40%);">+     if (!eprofile) {</span><br><span style="color: hsl(120, 100%, 40%);">+              SCOPE_EXIT_RTN_VALUE(NULL, "%s: Allocation failure\n", reference_string);</span><br><span style="color: hsl(120, 100%, 40%);">+   }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   format_str = ast_xml_get_attribute(location_info, "format");</span><br><span style="color: hsl(120, 100%, 40%);">+        if (strcasecmp(format_str, "gml") == 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+           eprofile->format = AST_GEOLOC_FORMAT_GML;</span><br><span style="color: hsl(120, 100%, 40%);">+  } else if (strcasecmp(format_str, "civicAddress") == 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+           eprofile->format = AST_GEOLOC_FORMAT_CIVIC_ADDRESS;</span><br><span style="color: hsl(120, 100%, 40%);">+        } else {</span><br><span style="color: hsl(120, 100%, 40%);">+              ao2_ref(eprofile, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+                SCOPE_EXIT_LOG_RTN_VALUE(NULL, LOG_ERROR, "%s: Unknown format '%s'\n", reference_string, format_str);</span><br><span style="color: hsl(120, 100%, 40%);">+       }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   pidf_element_str = ast_xml_node_get_name(pidf_element);</span><br><span style="color: hsl(120, 100%, 40%);">+       eprofile->pidf_element = geoloc_pidf_element_str_to_enum(pidf_element_str);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      eprofile->location_info = var_list_from_loc_info(location_info, eprofile->format, reference_string);</span><br><span style="color: hsl(120, 100%, 40%);">+    if (!eprofile->location_info) {</span><br><span style="color: hsl(120, 100%, 40%);">+            ao2_ref(eprofile, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+                SCOPE_EXIT_LOG_RTN_VALUE(NULL, LOG_ERROR,</span><br><span style="color: hsl(120, 100%, 40%);">+                     "%s: Unable to create location variables\n", reference_string);</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   eprofile->usage_rules = var_list_from_node(usage_rules, reference_string);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       method_str = ast_xml_get_text(method);</span><br><span style="color: hsl(120, 100%, 40%);">+        ast_string_field_set(eprofile, method, method_str);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ note_well_str = ast_xml_get_text(note_well);</span><br><span style="color: hsl(120, 100%, 40%);">+  ast_string_field_set(eprofile, notes, note_well_str);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       SCOPE_EXIT_RTN_VALUE(eprofile, "%s: Done.\n", reference_string);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct ast_geoloc_eprofile *ast_geoloc_eprofile_create_from_pidf(</span><br><span style="color: hsl(120, 100%, 40%);">+    struct ast_xml_doc *pidf_xmldoc, const char *geoloc_uri, const char *ref_str)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+      RAII_VAR(struct ast_xml_doc *, result_doc, NULL, ast_xml_close);</span><br><span style="color: hsl(120, 100%, 40%);">+      struct ast_geoloc_eprofile *eprofile;</span><br><span style="color: hsl(120, 100%, 40%);">+ /*</span><br><span style="color: hsl(120, 100%, 40%);">+     * The namespace prefixes used here (dm, def, gp, etc) don't have to match</span><br><span style="color: hsl(120, 100%, 40%);">+         * the ones used in the received PIDF-LO document but they MUST match the</span><br><span style="color: hsl(120, 100%, 40%);">+      * ones in the embedded pidf_to_eprofile stylesheet.</span><br><span style="color: hsl(120, 100%, 40%);">+   *</span><br><span style="color: hsl(120, 100%, 40%);">+     * RFC5491 Rule 8 states that...</span><br><span style="color: hsl(120, 100%, 40%);">+       * Where a PIDF document contains more than one <geopriv></span><br><span style="color: hsl(120, 100%, 40%);">+     * element, the priority of interpretation is given to the first</span><br><span style="color: hsl(120, 100%, 40%);">+     * <device> element in the document containing a location.  If no</span><br><span style="color: hsl(120, 100%, 40%);">+     * <device> element containing a location is present in the document,</span><br><span style="color: hsl(120, 100%, 40%);">+     * then priority is given to the first <tuple> element containing a</span><br><span style="color: hsl(120, 100%, 40%);">+     * location.  Locations contained in <person> tuples SHOULD only be</span><br><span style="color: hsl(120, 100%, 40%);">+     * used as a last resort.</span><br><span style="color: hsl(120, 100%, 40%);">+     *</span><br><span style="color: hsl(120, 100%, 40%);">+     * Reminder: xpath arrays are 1-based not 0-based.</span><br><span style="color: hsl(120, 100%, 40%);">+       */</span><br><span style="color: hsl(120, 100%, 40%);">+   const char *find_device[] = { "path", "/def:presence/dm:device[.//gp:location-info][1]", NULL};</span><br><span style="color: hsl(120, 100%, 40%);">+   const char *find_tuple[] = { "path", "/def:presence/def:tuple[.//gp:location-info][1]", NULL};</span><br><span style="color: hsl(120, 100%, 40%);">+    const char *find_person[] = { "path", "/def:presence/dm:person[.//gp:location-info][1]", NULL};</span><br><span style="color: hsl(120, 100%, 40%);">+   SCOPE_ENTER(3, "%s\n", ref_str);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        result_doc = ast_xslt_apply(pidf_to_eprofile_xslt, pidf_xmldoc, find_device);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!result_doc || !ast_xml_node_get_children((struct ast_xml_node *)result_doc)) {</span><br><span style="color: hsl(120, 100%, 40%);">+           ast_xml_close(result_doc);</span><br><span style="color: hsl(120, 100%, 40%);">+            result_doc = ast_xslt_apply(pidf_to_eprofile_xslt, pidf_xmldoc, find_tuple);</span><br><span style="color: hsl(120, 100%, 40%);">+  }</span><br><span style="color: hsl(120, 100%, 40%);">+     if (!result_doc || !ast_xml_node_get_children((struct ast_xml_node *)result_doc)) {</span><br><span style="color: hsl(120, 100%, 40%);">+           ast_xml_close(result_doc);</span><br><span style="color: hsl(120, 100%, 40%);">+            result_doc = ast_xslt_apply(pidf_to_eprofile_xslt, pidf_xmldoc, find_person);</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+     if (!result_doc || !ast_xml_node_get_children((struct ast_xml_node *)result_doc)) {</span><br><span style="color: hsl(120, 100%, 40%);">+           SCOPE_EXIT_RTN_VALUE(NULL, "%s: Not a PIDF-LO.  Skipping.\n", ref_str);</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   /*</span><br><span style="color: hsl(120, 100%, 40%);">+     * The document returned from the stylesheet application looks like this...</span><br><span style="color: hsl(120, 100%, 40%);">+    * <presence id="presence-entity"></span><br><span style="color: hsl(120, 100%, 40%);">+     *     <tuple id="element-id"></span><br><span style="color: hsl(120, 100%, 40%);">+         *         <location-info format="gml">shape="Ellipsoid", crs="3d", ...</location-info></span><br><span style="color: hsl(120, 100%, 40%);">+      *         <usage-rules>retransmission-allowed="no", retention-expiry="2010-11-14T20:00:00Z"</usage-rules></span><br><span style="color: hsl(120, 100%, 40%);">+     *         <method>Hybrid_A-GPS</method></span><br><span style="color: hsl(120, 100%, 40%);">+   *     </tuple></span><br><span style="color: hsl(120, 100%, 40%);">+  *  </presence></span><br><span style="color: hsl(120, 100%, 40%);">+  *</span><br><span style="color: hsl(120, 100%, 40%);">+     * Regardless of whether the pidf-element was tuple, device or person and whether</span><br><span style="color: hsl(120, 100%, 40%);">+      * the format is gml or civicAddress, the presence, pidf-element, location-info,</span><br><span style="color: hsl(120, 100%, 40%);">+       * usage-rules and method elements should be there although usage-rules and method</span><br><span style="color: hsl(120, 100%, 40%);">+     * may be empty.</span><br><span style="color: hsl(120, 100%, 40%);">+       *</span><br><span style="color: hsl(120, 100%, 40%);">+     * The contents of the location-info and usage-rules elements can be passed directly to</span><br><span style="color: hsl(120, 100%, 40%);">+        * ast_variable_list_from_string().</span><br><span style="color: hsl(120, 100%, 40%);">+    */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ eprofile = geoloc_eprofile_create_from_xslt_result(result_doc, ref_str);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    if (geoloc_uri) {</span><br><span style="color: hsl(120, 100%, 40%);">+             set_loc_src(eprofile, geoloc_uri, ref_str);</span><br><span style="color: hsl(120, 100%, 40%);">+   }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   SCOPE_EXIT_RTN_VALUE(eprofile, "%s: Done.\n", ref_str);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*!</span><br><span style="color: hsl(120, 100%, 40%);">+ * \internal</span><br><span style="color: hsl(120, 100%, 40%);">+ * \brief Create an common, intermediate XML document to pass to the outgoing XSLT process</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param eprofile    The eprofile</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param chan        The channel to resolve variables against</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param ref_string  A reference string for error messages</span><br><span style="color: hsl(120, 100%, 40%);">+ * \return            An XML doc</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \note Given that the document is simple and static, it was easier to just</span><br><span style="color: hsl(120, 100%, 40%);">+ * create the elements in a string buffer and call ast_xml_read_memory()</span><br><span style="color: hsl(120, 100%, 40%);">+ * at the end instead of creating</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+static struct ast_xml_node *geoloc_eprofile_to_intermediate(const char *element_name, struct ast_geoloc_eprofile *eprofile,</span><br><span style="color: hsl(120, 100%, 40%);">+     struct ast_channel *chan, const char *ref_string)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  struct ast_variable *resolved_location = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+        struct ast_variable *resolved_usage = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+   struct ast_variable *var = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+      RAII_VAR(struct ast_xml_node *, pidf_node, NULL, ast_xml_free_node);</span><br><span style="color: hsl(120, 100%, 40%);">+  struct ast_xml_node *rtn_pidf_node;</span><br><span style="color: hsl(120, 100%, 40%);">+   struct ast_xml_node *loc_node;</span><br><span style="color: hsl(120, 100%, 40%);">+        struct ast_xml_node *info_node;</span><br><span style="color: hsl(120, 100%, 40%);">+       struct ast_xml_node *rules_node;</span><br><span style="color: hsl(120, 100%, 40%);">+      struct ast_xml_node *method_node;</span><br><span style="color: hsl(120, 100%, 40%);">+     struct ast_xml_node *notes_node;</span><br><span style="color: hsl(120, 100%, 40%);">+      struct ast_xml_node *timestamp_node;</span><br><span style="color: hsl(120, 100%, 40%);">+  struct timeval tv = ast_tvnow();</span><br><span style="color: hsl(120, 100%, 40%);">+      struct tm tm = { 0, };</span><br><span style="color: hsl(120, 100%, 40%);">+        char timestr[32] = { 0, };</span><br><span style="color: hsl(120, 100%, 40%);">+    int rc = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ SCOPE_ENTER(3, "%s\n", ref_string);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       if (!eprofile || !chan) {</span><br><span style="color: hsl(120, 100%, 40%);">+             SCOPE_EXIT_RTN_VALUE(NULL, "%s: Either or both eprofile or chan were NULL\n", ref_string);</span><br><span style="color: hsl(120, 100%, 40%);">+  }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   pidf_node = ast_xml_new_node(element_name);</span><br><span style="color: hsl(120, 100%, 40%);">+   if (!pidf_node) {</span><br><span style="color: hsl(120, 100%, 40%);">+             SCOPE_EXIT_LOG_RTN_VALUE(NULL, LOG_ERROR, "%s: Unable to create 'pidf' XML node\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                 ref_string);</span><br><span style="color: hsl(120, 100%, 40%);">+  }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   loc_node = ast_xml_new_child(pidf_node, "location-info");</span><br><span style="color: hsl(120, 100%, 40%);">+   if (!loc_node) {</span><br><span style="color: hsl(120, 100%, 40%);">+              SCOPE_EXIT_LOG_RTN_VALUE(NULL, LOG_ERROR, "%s: Unable to create 'location-info' XML node\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                        ref_string);</span><br><span style="color: hsl(120, 100%, 40%);">+  }</span><br><span style="color: hsl(120, 100%, 40%);">+     rc = ast_xml_set_attribute(loc_node, "format", geoloc_format_to_name(eprofile->format));</span><br><span style="color: hsl(120, 100%, 40%);">+ if (rc != 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+                SCOPE_EXIT_LOG_RTN_VALUE(NULL, LOG_ERROR, "%s: Unable to set 'format' XML attribute\n", ref_string);</span><br><span style="color: hsl(120, 100%, 40%);">+        }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   resolved_location = geoloc_eprofile_resolve_varlist(eprofile->effective_location,</span><br><span style="color: hsl(120, 100%, 40%);">+          eprofile->location_variables, chan);</span><br><span style="color: hsl(120, 100%, 40%);">+       if (eprofile->format == AST_GEOLOC_FORMAT_CIVIC_ADDRESS) {</span><br><span style="color: hsl(120, 100%, 40%);">+         info_node = geoloc_civicaddr_list_to_xml(resolved_location, ref_string);</span><br><span style="color: hsl(120, 100%, 40%);">+      } else {</span><br><span style="color: hsl(120, 100%, 40%);">+              info_node = geoloc_gml_list_to_xml(resolved_location, ref_string);</span><br><span style="color: hsl(120, 100%, 40%);">+    }</span><br><span style="color: hsl(120, 100%, 40%);">+     if (!info_node) {</span><br><span style="color: hsl(120, 100%, 40%);">+             SCOPE_EXIT_LOG_RTN_VALUE(NULL, LOG_ERROR, "%s: Unable to create XML from '%s' list\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                      ref_string, geoloc_format_to_name(eprofile->format));</span><br><span style="color: hsl(120, 100%, 40%);">+      }</span><br><span style="color: hsl(120, 100%, 40%);">+     if (!ast_xml_add_child(loc_node, info_node)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                ast_xml_free_node(info_node);</span><br><span style="color: hsl(120, 100%, 40%);">+         SCOPE_EXIT_LOG_RTN_VALUE(NULL, LOG_ERROR, "%s: Unable add '%s' node to XML document\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                     ref_string, geoloc_format_to_name(eprofile->format));</span><br><span style="color: hsl(120, 100%, 40%);">+      }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   rules_node = ast_xml_new_child(pidf_node, "usage-rules");</span><br><span style="color: hsl(120, 100%, 40%);">+   if (!rules_node) {</span><br><span style="color: hsl(120, 100%, 40%);">+            SCOPE_EXIT_LOG_RTN_VALUE(NULL, LOG_ERROR, "%s: Unable to create 'usage-rules' XML node\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                  ref_string);</span><br><span style="color: hsl(120, 100%, 40%);">+  }</span><br><span style="color: hsl(120, 100%, 40%);">+     resolved_usage = geoloc_eprofile_resolve_varlist(eprofile->usage_rules,</span><br><span style="color: hsl(120, 100%, 40%);">+            eprofile->location_variables, chan);</span><br><span style="color: hsl(120, 100%, 40%);">+       for (var = resolved_usage; var; var = var->next) {</span><br><span style="color: hsl(120, 100%, 40%);">+         struct ast_xml_node *ur = ast_xml_new_child(rules_node, var->name);</span><br><span style="color: hsl(120, 100%, 40%);">+                ast_xml_set_text(ur, var->value);</span><br><span style="color: hsl(120, 100%, 40%);">+  }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   if (!ast_strlen_zero(eprofile->method)) {</span><br><span style="color: hsl(120, 100%, 40%);">+          method_node = ast_xml_new_child(pidf_node, "method");</span><br><span style="color: hsl(120, 100%, 40%);">+               if (!method_node) {</span><br><span style="color: hsl(120, 100%, 40%);">+                   SCOPE_EXIT_LOG_RTN_VALUE(NULL, LOG_ERROR, "%s: Unable to create 'method' XML node\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                               ref_string);</span><br><span style="color: hsl(120, 100%, 40%);">+          }</span><br><span style="color: hsl(120, 100%, 40%);">+             ast_xml_set_text(method_node, eprofile->method);</span><br><span style="color: hsl(120, 100%, 40%);">+   };</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  if (!ast_strlen_zero(eprofile->notes)) {</span><br><span style="color: hsl(120, 100%, 40%);">+           notes_node = ast_xml_new_child(pidf_node, "note-well");</span><br><span style="color: hsl(120, 100%, 40%);">+             if (!notes_node) {</span><br><span style="color: hsl(120, 100%, 40%);">+                    SCOPE_EXIT_LOG_RTN_VALUE(NULL, LOG_ERROR, "%s: Unable to create 'note-well' XML node\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                            ref_string);</span><br><span style="color: hsl(120, 100%, 40%);">+          }</span><br><span style="color: hsl(120, 100%, 40%);">+             ast_xml_set_text(notes_node, eprofile->notes);</span><br><span style="color: hsl(120, 100%, 40%);">+     };</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  gmtime_r(&tv.tv_sec, &tm);</span><br><span style="color: hsl(120, 100%, 40%);">+    strftime(timestr, sizeof(timestr), "%FT%TZ", &tm);</span><br><span style="color: hsl(120, 100%, 40%);">+      timestamp_node = ast_xml_new_child(pidf_node, "timestamp");</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!timestamp_node) {</span><br><span style="color: hsl(120, 100%, 40%);">+                SCOPE_EXIT_LOG_RTN_VALUE(NULL, LOG_ERROR, "%s: Unable to create 'timestamp' XML node\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                    ref_string);</span><br><span style="color: hsl(120, 100%, 40%);">+  }</span><br><span style="color: hsl(120, 100%, 40%);">+     ast_xml_set_text(timestamp_node, timestr);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  rtn_pidf_node = pidf_node;</span><br><span style="color: hsl(120, 100%, 40%);">+    pidf_node = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+     SCOPE_EXIT_RTN_VALUE(rtn_pidf_node, "%s: Done\n", ref_string);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#define CREATE_NODE_LIST(node) \</span><br><span style="color: hsl(120, 100%, 40%);">+       if (!node) { \</span><br><span style="color: hsl(120, 100%, 40%);">+                node = ast_xml_new_child(root_node, \</span><br><span style="color: hsl(120, 100%, 40%);">+                 geoloc_pidf_element_to_name(eprofile->pidf_element)); \</span><br><span style="color: hsl(120, 100%, 40%);">+            if (!pidfs[eprofile->pidf_element]) { \</span><br><span style="color: hsl(120, 100%, 40%);">+                    SCOPE_EXIT_LOG_RTN_VALUE(NULL, LOG_ERROR, "%s: Unable to create pidf '%s' XML node\n", \</span><br><span style="color: hsl(120, 100%, 40%);">+                            ref_string, geoloc_pidf_element_to_name(eprofile->pidf_element)); \</span><br><span style="color: hsl(120, 100%, 40%);">+                } \</span><br><span style="color: hsl(120, 100%, 40%);">+   }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+const char *ast_geoloc_eprofiles_to_pidf(struct ast_datastore *ds,</span><br><span style="color: hsl(120, 100%, 40%);">+       struct ast_channel *chan, struct ast_str **buf, const char * ref_string)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+   RAII_VAR(struct ast_xml_doc *, intermediate, NULL, ast_xml_close);</span><br><span style="color: hsl(120, 100%, 40%);">+    RAII_VAR(struct ast_xml_doc *, pidf_doc, NULL, ast_xml_close);</span><br><span style="color: hsl(120, 100%, 40%);">+        struct ast_xml_node *root_node;</span><br><span style="color: hsl(120, 100%, 40%);">+       struct ast_xml_node *pidfs[AST_PIDF_ELEMENT_LAST] = {NULL, };</span><br><span style="color: hsl(120, 100%, 40%);">+ struct ast_geoloc_eprofile *eprofile;</span><br><span style="color: hsl(120, 100%, 40%);">+ int eprofile_count = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+       int i;</span><br><span style="color: hsl(120, 100%, 40%);">+        RAII_VAR(char *, doc_str, NULL, ast_xml_free_text);</span><br><span style="color: hsl(120, 100%, 40%);">+   int doc_len;</span><br><span style="color: hsl(120, 100%, 40%);">+  int rc = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+   SCOPE_ENTER(3, "%s\n", ref_string);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       if (!ds || !chan || !buf || !*buf || ast_strlen_zero(ref_string)) {</span><br><span style="color: hsl(120, 100%, 40%);">+           SCOPE_EXIT_RTN_VALUE(NULL, "%s: Either or both datastore or chan were NULL\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                      ref_string);</span><br><span style="color: hsl(120, 100%, 40%);">+  }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   intermediate = ast_xml_new();</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!intermediate) {</span><br><span style="color: hsl(120, 100%, 40%);">+          SCOPE_EXIT_LOG_RTN_VALUE(NULL, LOG_ERROR, "%s: Unable to create XML document\n", ref_string);</span><br><span style="color: hsl(120, 100%, 40%);">+       }</span><br><span style="color: hsl(120, 100%, 40%);">+     root_node = ast_xml_new_node("presence");</span><br><span style="color: hsl(120, 100%, 40%);">+   if (!root_node) {</span><br><span style="color: hsl(120, 100%, 40%);">+             SCOPE_EXIT_LOG_RTN_VALUE(NULL, LOG_ERROR, "%s: Unable to create root XML node\n", ref_string);</span><br><span style="color: hsl(120, 100%, 40%);">+      }</span><br><span style="color: hsl(120, 100%, 40%);">+     ast_xml_set_root(intermediate, root_node);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  eprofile_count = ast_geoloc_datastore_size(ds);</span><br><span style="color: hsl(120, 100%, 40%);">+       for (i = 0; i < eprofile_count; i++) {</span><br><span style="color: hsl(120, 100%, 40%);">+             struct ast_xml_node *temp_node = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+                struct ast_xml_node *curr_loc = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+         struct ast_xml_node *new_loc = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+          struct ast_xml_node *new_loc_child = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+            struct ast_xml_node *new_loc_child_dup = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+                eprofile = ast_geoloc_datastore_get_eprofile(ds, i);</span><br><span style="color: hsl(120, 100%, 40%);">+          if (eprofile->format == AST_GEOLOC_FORMAT_URI) {</span><br><span style="color: hsl(120, 100%, 40%);">+                   continue;</span><br><span style="color: hsl(120, 100%, 40%);">+             }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+           if (ast_strlen_zero(ast_xml_get_attribute(root_node, "entity"))) {</span><br><span style="color: hsl(120, 100%, 40%);">+                  rc = ast_xml_set_attribute(root_node, "entity", eprofile->id);</span><br><span style="color: hsl(120, 100%, 40%);">+                   if (rc != 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+                                SCOPE_EXIT_LOG_RTN_VALUE(NULL, LOG_ERROR, "%s: Unable to set 'entity' XML attribute\n", ref_string);</span><br><span style="color: hsl(120, 100%, 40%);">+                        }</span><br><span style="color: hsl(120, 100%, 40%);">+             }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+           temp_node = geoloc_eprofile_to_intermediate(geoloc_pidf_element_to_name(eprofile->pidf_element),</span><br><span style="color: hsl(120, 100%, 40%);">+                   eprofile, chan, ref_string);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+                if (!pidfs[eprofile->pidf_element]) {</span><br><span style="color: hsl(120, 100%, 40%);">+                      pidfs[eprofile->pidf_element] = temp_node;</span><br><span style="color: hsl(120, 100%, 40%);">+                 ast_xml_add_child(root_node, temp_node);</span><br><span style="color: hsl(120, 100%, 40%);">+                      continue;</span><br><span style="color: hsl(120, 100%, 40%);">+             }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+           curr_loc = ast_xml_find_child_element(pidfs[eprofile->pidf_element], "location-info", NULL, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+               new_loc = ast_xml_find_child_element(temp_node, "location-info", NULL, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+               new_loc_child = ast_xml_node_get_children(new_loc);</span><br><span style="color: hsl(120, 100%, 40%);">+           new_loc_child_dup = ast_xml_copy_node_list(new_loc_child);</span><br><span style="color: hsl(120, 100%, 40%);">+            ast_xml_add_child_list(curr_loc, new_loc_child_dup);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+                ast_xml_free_node(temp_node);</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   ast_xml_doc_dump_memory(intermediate, &doc_str, &doc_len);</span><br><span style="color: hsl(120, 100%, 40%);">+    if (doc_len == 0 || !doc_str) {</span><br><span style="color: hsl(120, 100%, 40%);">+               SCOPE_EXIT_LOG_RTN_VALUE(NULL, LOG_ERROR, "%s: Unable to dump intermediate doc to string\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                        ref_string);</span><br><span style="color: hsl(120, 100%, 40%);">+  }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   ast_trace(5, "Intermediate doc:\n%s\n", doc_str);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ pidf_doc = ast_xslt_apply(eprofile_to_pidf_xslt, intermediate, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!pidf_doc) {</span><br><span style="color: hsl(120, 100%, 40%);">+              SCOPE_EXIT_LOG_RTN_VALUE(NULL, LOG_ERROR, "%s: Unable to create final PIDF-LO doc from intermediate doc:\n%s\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                    ref_string, doc_str);</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   ast_xml_doc_dump_memory(pidf_doc, &doc_str, &doc_len);</span><br><span style="color: hsl(120, 100%, 40%);">+        if (doc_len == 0 || !doc_str) {</span><br><span style="color: hsl(120, 100%, 40%);">+               SCOPE_EXIT_LOG_RTN_VALUE(NULL, LOG_ERROR, "%s: Unable to dump final PIDF-LO doc to string\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                       ref_string);</span><br><span style="color: hsl(120, 100%, 40%);">+  }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   rc = ast_str_set(buf, 0, "%s", doc_str);</span><br><span style="color: hsl(120, 100%, 40%);">+    if (rc <= 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+             SCOPE_EXIT_LOG_RTN_VALUE(NULL, LOG_ERROR, "%s: Unable to extend buffer (%d)\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                     ref_string, rc);</span><br><span style="color: hsl(120, 100%, 40%);">+      }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   ast_trace(5, "Final doc:\n%s\n", ast_str_buffer(*buf));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   SCOPE_EXIT_RTN_VALUE(ast_str_buffer(*buf), "%s: Done\n", ref_string);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#ifdef TEST_FRAMEWORK</span><br><span style="color: hsl(120, 100%, 40%);">+static void load_tests(void);</span><br><span style="color: hsl(120, 100%, 40%);">+static void unload_tests(void);</span><br><span style="color: hsl(120, 100%, 40%);">+#else</span><br><span style="color: hsl(120, 100%, 40%);">+static void load_tests(void) {}</span><br><span style="color: hsl(120, 100%, 40%);">+static void unload_tests(void) {}</span><br><span style="color: hsl(120, 100%, 40%);">+#endif</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+int geoloc_eprofile_unload(void)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+       unload_tests();</span><br><span style="color: hsl(120, 100%, 40%);">+       if (pidf_to_eprofile_xslt) {</span><br><span style="color: hsl(120, 100%, 40%);">+          ast_xslt_close(pidf_to_eprofile_xslt);</span><br><span style="color: hsl(120, 100%, 40%);">+        }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   if (eprofile_to_pidf_xslt) {</span><br><span style="color: hsl(120, 100%, 40%);">+          ast_xslt_close(eprofile_to_pidf_xslt);</span><br><span style="color: hsl(120, 100%, 40%);">+        }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   if (geoloc_sorcery) {</span><br><span style="color: hsl(120, 100%, 40%);">+         ast_sorcery_unref(geoloc_sorcery);</span><br><span style="color: hsl(120, 100%, 40%);">+    }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   return AST_MODULE_LOAD_SUCCESS;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+int geoloc_eprofile_load(void)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+       pidf_to_eprofile_xslt_size =</span><br><span style="color: hsl(120, 100%, 40%);">+          (_binary_res_geolocation_pidf_to_eprofile_xslt_end - _binary_res_geolocation_pidf_to_eprofile_xslt_start);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  pidf_lo_test_xml_size =</span><br><span style="color: hsl(120, 100%, 40%);">+               (_binary_res_geolocation_pidf_lo_test_xml_end - _binary_res_geolocation_pidf_lo_test_xml_start);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    pidf_to_eprofile_xslt = ast_xslt_read_memory(</span><br><span style="color: hsl(120, 100%, 40%);">+         (char *)_binary_res_geolocation_pidf_to_eprofile_xslt_start, pidf_to_eprofile_xslt_size);</span><br><span style="color: hsl(120, 100%, 40%);">+     if (!pidf_to_eprofile_xslt) {</span><br><span style="color: hsl(120, 100%, 40%);">+         ast_log(LOG_ERROR, "Unable to read pidf_to_eprofile_xslt from memory\n");</span><br><span style="color: hsl(120, 100%, 40%);">+           return AST_MODULE_LOAD_DECLINE;</span><br><span style="color: hsl(120, 100%, 40%);">+       }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   eprofile_to_pidf_xslt_size =</span><br><span style="color: hsl(120, 100%, 40%);">+          (_binary_res_geolocation_eprofile_to_pidf_xslt_end - _binary_res_geolocation_eprofile_to_pidf_xslt_start);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  eprofile_to_pidf_xslt = ast_xslt_read_memory(</span><br><span style="color: hsl(120, 100%, 40%);">+         (char *)_binary_res_geolocation_eprofile_to_pidf_xslt_start, eprofile_to_pidf_xslt_size);</span><br><span style="color: hsl(120, 100%, 40%);">+     if (!eprofile_to_pidf_xslt) {</span><br><span style="color: hsl(120, 100%, 40%);">+         ast_log(LOG_ERROR, "Unable to read eprofile_to_pidf_xslt from memory\n");</span><br><span style="color: hsl(120, 100%, 40%);">+//         geoloc_eprofile_unload();</span><br><span style="color: hsl(120, 100%, 40%);">+             return AST_MODULE_LOAD_DECLINE;</span><br><span style="color: hsl(120, 100%, 40%);">+       }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   geoloc_sorcery = geoloc_get_sorcery();</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      load_tests();</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       return AST_MODULE_LOAD_SUCCESS;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+int geoloc_eprofile_reload(void)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+     return AST_MODULE_LOAD_SUCCESS;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#ifdef TEST_FRAMEWORK</span><br><span style="color: hsl(120, 100%, 40%);">+#include "asterisk/test.h"</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+AST_TEST_DEFINE(test_create_from_uri)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     RAII_VAR(struct ast_geoloc_eprofile *, eprofile,  NULL, ao2_cleanup);</span><br><span style="color: hsl(120, 100%, 40%);">+ const char *uri = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+       int rc = AST_TEST_PASS;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     switch (cmd) {</span><br><span style="color: hsl(120, 100%, 40%);">+        case TEST_INIT:</span><br><span style="color: hsl(120, 100%, 40%);">+               info->name = "create_from_uri";</span><br><span style="color: hsl(120, 100%, 40%);">+          info->category = "/geoloc/";</span><br><span style="color: hsl(120, 100%, 40%);">+             info->summary = "Test create from uri";</span><br><span style="color: hsl(120, 100%, 40%);">+          info->description = info->summary;</span><br><span style="color: hsl(120, 100%, 40%);">+              return AST_TEST_NOT_RUN;</span><br><span style="color: hsl(120, 100%, 40%);">+      case TEST_EXECUTE:</span><br><span style="color: hsl(120, 100%, 40%);">+            break;</span><br><span style="color: hsl(120, 100%, 40%);">+        }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   eprofile = ast_geoloc_eprofile_create_from_uri("http://some_uri&a=b", __func__);</span><br><span style="color: hsl(120, 100%, 40%);">+        ast_test_validate(test, eprofile != NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+    ast_test_validate(test, eprofile->format == AST_GEOLOC_FORMAT_URI);</span><br><span style="color: hsl(120, 100%, 40%);">+        ast_test_validate(test, eprofile->location_info != NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+  uri = ast_variable_find_in_list(eprofile->location_info, "URI");</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_test_validate(test, uri != NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_test_validate(test, strcmp(uri, "http://some_uri&a=b") == 0);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     return rc;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static enum ast_test_result_state validate_eprofile(struct ast_test *test,</span><br><span style="color: hsl(120, 100%, 40%);">+   struct ast_xml_doc * pidf_xmldoc,</span><br><span style="color: hsl(120, 100%, 40%);">+     const char *path,</span><br><span style="color: hsl(120, 100%, 40%);">+     const char *id,</span><br><span style="color: hsl(120, 100%, 40%);">+       enum ast_geoloc_pidf_element pidf_element,</span><br><span style="color: hsl(120, 100%, 40%);">+    enum ast_geoloc_format format,</span><br><span style="color: hsl(120, 100%, 40%);">+        const char *method,</span><br><span style="color: hsl(120, 100%, 40%);">+   const char *location,</span><br><span style="color: hsl(120, 100%, 40%);">+ const char *usage</span><br><span style="color: hsl(120, 100%, 40%);">+     )</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  RAII_VAR(struct ast_str *, str, NULL, ast_free);</span><br><span style="color: hsl(120, 100%, 40%);">+      RAII_VAR(struct ast_geoloc_eprofile *, eprofile,  NULL, ao2_cleanup);</span><br><span style="color: hsl(120, 100%, 40%);">+ RAII_VAR(struct ast_xml_doc *, result_doc, NULL, ast_xml_close);</span><br><span style="color: hsl(120, 100%, 40%);">+      const char *search[] = { "path", path, NULL };</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    if (!ast_strlen_zero(path)) {</span><br><span style="color: hsl(120, 100%, 40%);">+         result_doc = ast_xslt_apply(pidf_to_eprofile_xslt, pidf_xmldoc, (const char **)search);</span><br><span style="color: hsl(120, 100%, 40%);">+               ast_test_validate(test, (result_doc && ast_xml_node_get_children((struct ast_xml_node *)result_doc)));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+              eprofile = geoloc_eprofile_create_from_xslt_result(result_doc, "test_create_from_xslt");</span><br><span style="color: hsl(120, 100%, 40%);">+    } else {</span><br><span style="color: hsl(120, 100%, 40%);">+              eprofile = ast_geoloc_eprofile_create_from_pidf(pidf_xmldoc, NULL, "test_create_from_pidf");</span><br><span style="color: hsl(120, 100%, 40%);">+        }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   ast_test_validate(test, eprofile != NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+    ast_test_status_update(test, "ID: '%s'  pidf_element: '%s'  format: '%s'  method: '%s'\n", eprofile->id,</span><br><span style="color: hsl(120, 100%, 40%);">+         geoloc_pidf_element_to_name(eprofile->pidf_element),</span><br><span style="color: hsl(120, 100%, 40%);">+               geoloc_format_to_name(eprofile->format),</span><br><span style="color: hsl(120, 100%, 40%);">+           eprofile->method);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       ast_test_validate(test, ast_strings_equal(eprofile->id, id));</span><br><span style="color: hsl(120, 100%, 40%);">+      ast_test_validate(test, eprofile->pidf_element == pidf_element);</span><br><span style="color: hsl(120, 100%, 40%);">+   ast_test_validate(test, eprofile->format == format);</span><br><span style="color: hsl(120, 100%, 40%);">+       ast_test_validate(test, ast_strings_equal(eprofile->method, method));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    str = ast_variable_list_join(eprofile->location_info, ",", "=", NULL, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+   ast_test_validate(test, str != NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_test_status_update(test, "location_vars expected: %s\n", location);</span><br><span style="color: hsl(120, 100%, 40%);">+     ast_test_status_update(test, "location_vars received: %s\n", ast_str_buffer(str));</span><br><span style="color: hsl(120, 100%, 40%);">+  ast_test_validate(test, ast_strings_equal(ast_str_buffer(str), location));</span><br><span style="color: hsl(120, 100%, 40%);">+    ast_free(str);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      str = ast_variable_list_join(eprofile->usage_rules, ",", "=", "'", NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+        ast_test_validate(test, str != NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_test_status_update(test, "usage_rules expected: %s\n", usage);</span><br><span style="color: hsl(120, 100%, 40%);">+  ast_test_status_update(test, "usage_rules received: %s\n", ast_str_buffer(str));</span><br><span style="color: hsl(120, 100%, 40%);">+    ast_test_validate(test, ast_strings_equal(ast_str_buffer(str), usage));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     return AST_TEST_PASS;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+AST_TEST_DEFINE(test_create_from_pidf)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       RAII_VAR(struct ast_xml_doc *, pidf_xmldoc, NULL, ast_xml_close);</span><br><span style="color: hsl(120, 100%, 40%);">+     enum ast_test_result_state res = AST_TEST_PASS;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     switch (cmd) {</span><br><span style="color: hsl(120, 100%, 40%);">+        case TEST_INIT:</span><br><span style="color: hsl(120, 100%, 40%);">+               info->name = "create_from_pidf";</span><br><span style="color: hsl(120, 100%, 40%);">+         info->category = "/geoloc/";</span><br><span style="color: hsl(120, 100%, 40%);">+             info->summary = "Test create from pidf scenarios";</span><br><span style="color: hsl(120, 100%, 40%);">+               info->description = info->summary;</span><br><span style="color: hsl(120, 100%, 40%);">+              return AST_TEST_NOT_RUN;</span><br><span style="color: hsl(120, 100%, 40%);">+      case TEST_EXECUTE:</span><br><span style="color: hsl(120, 100%, 40%);">+            break;</span><br><span style="color: hsl(120, 100%, 40%);">+        }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   pidf_xmldoc = ast_xml_read_memory((char *)_binary_res_geolocation_pidf_lo_test_xml_start, pidf_lo_test_xml_size);</span><br><span style="color: hsl(120, 100%, 40%);">+     ast_test_validate(test, pidf_xmldoc != NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       res = validate_eprofile(test, pidf_xmldoc,</span><br><span style="color: hsl(120, 100%, 40%);">+            NULL,</span><br><span style="color: hsl(120, 100%, 40%);">+         "arcband-2d",</span><br><span style="color: hsl(120, 100%, 40%);">+               AST_PIDF_ELEMENT_DEVICE,</span><br><span style="color: hsl(120, 100%, 40%);">+              AST_GEOLOC_FORMAT_GML,</span><br><span style="color: hsl(120, 100%, 40%);">+                "TA-NMR",</span><br><span style="color: hsl(120, 100%, 40%);">+           "shape=ArcBand,crs=2d,pos=-43.5723 153.21760,innerRadius=3594,"</span><br><span style="color: hsl(120, 100%, 40%);">+                             "outerRadius=4148,startAngle=20 radians,openingAngle=20 radians",</span><br><span style="color: hsl(120, 100%, 40%);">+           "retransmission-allowed='yes',ruleset-preference='https:/www/more.com',"</span><br><span style="color: hsl(120, 100%, 40%);">+                    "retention-expires='2007-06-22T20:57:29Z'"</span><br><span style="color: hsl(120, 100%, 40%);">+          );</span><br><span style="color: hsl(120, 100%, 40%);">+    ast_test_validate(test, res == AST_TEST_PASS);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    res = validate_eprofile(test, pidf_xmldoc,</span><br><span style="color: hsl(120, 100%, 40%);">+            "/def:presence/dm:device[.//ca:civicAddress][1]",</span><br><span style="color: hsl(120, 100%, 40%);">+           "pres:alice@asterisk.org",</span><br><span style="color: hsl(120, 100%, 40%);">+          AST_PIDF_ELEMENT_DEVICE,</span><br><span style="color: hsl(120, 100%, 40%);">+              AST_GEOLOC_FORMAT_CIVIC_ADDRESS,</span><br><span style="color: hsl(120, 100%, 40%);">+              "GPS",</span><br><span style="color: hsl(120, 100%, 40%);">+              "lang=en-AU,country=AU,A1=NSW,A3=Wollongong,A4=North Wollongong,"</span><br><span style="color: hsl(120, 100%, 40%);">+                   "RD=Flinders,STS=Street,RDBR=Campbell Street,LMK=Gilligan's Island,"</span><br><span style="color: hsl(120, 100%, 40%);">+                    "LOC=Corner,NAM=Video Rental Store,PC=2500,ROOM=Westerns and Classics,"</span><br><span style="color: hsl(120, 100%, 40%);">+                     "PLC=store,POBOX=Private Box 15",</span><br><span style="color: hsl(120, 100%, 40%);">+           "retransmission-allowed='yes',ruleset-preference='https:/www/more.com',"</span><br><span style="color: hsl(120, 100%, 40%);">+                    "retention-expires='2007-06-22T20:57:29Z'"</span><br><span style="color: hsl(120, 100%, 40%);">+          );</span><br><span style="color: hsl(120, 100%, 40%);">+    ast_test_validate(test, res == AST_TEST_PASS);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    return res;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static void load_tests(void) {</span><br><span style="color: hsl(120, 100%, 40%);">+      AST_TEST_REGISTER(test_create_from_uri);</span><br><span style="color: hsl(120, 100%, 40%);">+      AST_TEST_REGISTER(test_create_from_pidf);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+static void unload_tests(void) {</span><br><span style="color: hsl(120, 100%, 40%);">+        AST_TEST_UNREGISTER(test_create_from_uri);</span><br><span style="color: hsl(120, 100%, 40%);">+    AST_TEST_UNREGISTER(test_create_from_pidf);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#endif</span><br><span>diff --git a/res/res_geolocation/geoloc_gml.c b/res/res_geolocation/geoloc_gml.c</span><br><span>new file mode 100644</span><br><span>index 0000000..8a66162</span><br><span>--- /dev/null</span><br><span>+++ b/res/res_geolocation/geoloc_gml.c</span><br><span>@@ -0,0 +1,362 @@</span><br><span style="color: hsl(120, 100%, 40%);">+/*</span><br><span style="color: hsl(120, 100%, 40%);">+ * Copyright (C) 2022, Sangoma Technologies Corporation</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * George Joseph <gjoseph@sangoma.com></span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * See http://www.asterisk.org for more information about</span><br><span style="color: hsl(120, 100%, 40%);">+ * the Asterisk project. Please do not directly contact</span><br><span style="color: hsl(120, 100%, 40%);">+ * any of the maintainers of this project for assistance;</span><br><span style="color: hsl(120, 100%, 40%);">+ * the project provides a web site, mailing lists and IRC</span><br><span style="color: hsl(120, 100%, 40%);">+ * channels for your use.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * This program is free software, distributed under the terms of</span><br><span style="color: hsl(120, 100%, 40%);">+ * the GNU General Public License Version 2. See the LICENSE file</span><br><span style="color: hsl(120, 100%, 40%);">+ * at the top of the source tree.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include "asterisk.h"</span><br><span style="color: hsl(120, 100%, 40%);">+#include "asterisk/config.h"</span><br><span style="color: hsl(120, 100%, 40%);">+#include "asterisk/cli.h"</span><br><span style="color: hsl(120, 100%, 40%);">+#include "asterisk/res_geolocation.h"</span><br><span style="color: hsl(120, 100%, 40%);">+#include "geoloc_private.h"</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#if 1 //not used yet.</span><br><span style="color: hsl(120, 100%, 40%);">+enum geoloc_shape_attrs {</span><br><span style="color: hsl(120, 100%, 40%);">+       GEOLOC_SHAPE_ATTR_POS = 0,</span><br><span style="color: hsl(120, 100%, 40%);">+    GEOLOC_SHAPE_ATTR_POS3D,</span><br><span style="color: hsl(120, 100%, 40%);">+      GEOLOC_SHAPE_ATTR_RADIUS,</span><br><span style="color: hsl(120, 100%, 40%);">+     GEOLOC_SHAPE_ATTR_SEMI_MAJOR_AXIS,</span><br><span style="color: hsl(120, 100%, 40%);">+    GEOLOC_SHAPE_ATTR_SEMI_MINOR_AXIS,</span><br><span style="color: hsl(120, 100%, 40%);">+    GEOLOC_SHAPE_ATTR_VERTICAL_AXIS,</span><br><span style="color: hsl(120, 100%, 40%);">+      GEOLOC_SHAPE_ATTR_HEIGHT,</span><br><span style="color: hsl(120, 100%, 40%);">+     GEOLOC_SHAPE_ATTR_ORIENTATION,</span><br><span style="color: hsl(120, 100%, 40%);">+        GEOLOC_SHAPE_ATTR_ORIENTATION_UOM,</span><br><span style="color: hsl(120, 100%, 40%);">+    GEOLOC_SHAPE_ATTR_INNER_RADIUS,</span><br><span style="color: hsl(120, 100%, 40%);">+       GEOLOC_SHAPE_ATTR_OUTER_RADIUS,</span><br><span style="color: hsl(120, 100%, 40%);">+       GEOLOC_SHAPE_ATTR_STARTING_ANGLE,</span><br><span style="color: hsl(120, 100%, 40%);">+     GEOLOC_SHAPE_ATTR_OPENING_ANGLE,</span><br><span style="color: hsl(120, 100%, 40%);">+      GEOLOC_SHAPE_ATTR_ANGLE_UOM,</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct geoloc_gml_attr_def {</span><br><span style="color: hsl(120, 100%, 40%);">+      enum geoloc_shape_attrs attr;</span><br><span style="color: hsl(120, 100%, 40%);">+ const char *name;</span><br><span style="color: hsl(120, 100%, 40%);">+     int (*validator)(const char *value);</span><br><span style="color: hsl(120, 100%, 40%);">+  int (*transformer)(struct ast_variable *value);</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct geoloc_gml_attr_def gml_attr_defs[] = {</span><br><span style="color: hsl(120, 100%, 40%);">+ { GEOLOC_SHAPE_ATTR_POS, "pos", NULL, NULL},</span><br><span style="color: hsl(120, 100%, 40%);">+        { GEOLOC_SHAPE_ATTR_POS3D,"pos3d", NULL, NULL},</span><br><span style="color: hsl(120, 100%, 40%);">+     { GEOLOC_SHAPE_ATTR_RADIUS,"radius", NULL, NULL},</span><br><span style="color: hsl(120, 100%, 40%);">+   { GEOLOC_SHAPE_ATTR_SEMI_MAJOR_AXIS,"semiMajorAxis", NULL, NULL},</span><br><span style="color: hsl(120, 100%, 40%);">+   { GEOLOC_SHAPE_ATTR_SEMI_MINOR_AXIS,"semiMinorAxis", NULL, NULL},</span><br><span style="color: hsl(120, 100%, 40%);">+   { GEOLOC_SHAPE_ATTR_VERTICAL_AXIS,"verticalAxis", NULL, NULL},</span><br><span style="color: hsl(120, 100%, 40%);">+      { GEOLOC_SHAPE_ATTR_HEIGHT,"height", NULL, NULL},</span><br><span style="color: hsl(120, 100%, 40%);">+   { GEOLOC_SHAPE_ATTR_ORIENTATION,"orientation", NULL, NULL},</span><br><span style="color: hsl(120, 100%, 40%);">+ { GEOLOC_SHAPE_ATTR_ORIENTATION_UOM,"orientation_uom", NULL, NULL},</span><br><span style="color: hsl(120, 100%, 40%);">+ { GEOLOC_SHAPE_ATTR_INNER_RADIUS,"innerRadius", NULL, NULL},</span><br><span style="color: hsl(120, 100%, 40%);">+        { GEOLOC_SHAPE_ATTR_OUTER_RADIUS,"outerRadius", NULL, NULL},</span><br><span style="color: hsl(120, 100%, 40%);">+        { GEOLOC_SHAPE_ATTR_STARTING_ANGLE,"startingAngle", NULL, NULL},</span><br><span style="color: hsl(120, 100%, 40%);">+    { GEOLOC_SHAPE_ATTR_OPENING_ANGLE,"openingAngle", NULL, NULL},</span><br><span style="color: hsl(120, 100%, 40%);">+      { GEOLOC_SHAPE_ATTR_ANGLE_UOM,"angle_uom", NULL, NULL},</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+#endif  //not used yet.</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct geoloc_gml_attr {</span><br><span style="color: hsl(120, 100%, 40%);">+    const char *attribute;</span><br><span style="color: hsl(120, 100%, 40%);">+        int min_required;</span><br><span style="color: hsl(120, 100%, 40%);">+     int max_allowed;</span><br><span style="color: hsl(120, 100%, 40%);">+      int (*validator)(const char *value);</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct geoloc_gml_shape_def {</span><br><span style="color: hsl(120, 100%, 40%);">+     const char *shape_type;</span><br><span style="color: hsl(120, 100%, 40%);">+       struct geoloc_gml_attr required_attributes[8];</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static int pos_validator(const char *value)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  float lat;</span><br><span style="color: hsl(120, 100%, 40%);">+    float lon;</span><br><span style="color: hsl(120, 100%, 40%);">+    return (sscanf(value, "%f %f", &lat, &lon) == 2);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static int pos3d_validator(const char *value)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+    float lat;</span><br><span style="color: hsl(120, 100%, 40%);">+    float lon;</span><br><span style="color: hsl(120, 100%, 40%);">+    float alt;</span><br><span style="color: hsl(120, 100%, 40%);">+    return (sscanf(value, "%f %f %f", &lat, &lon, &alt) == 3);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static int float_validator(const char *value)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+       float val;</span><br><span style="color: hsl(120, 100%, 40%);">+    return (sscanf(value, "%f", &val) == 1);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static int uom_validator(const char *value)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+   return (ast_strings_equal(value, "degrees") || ast_strings_equal(value, "radians"));</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static struct geoloc_gml_shape_def gml_shape_defs[8] = {</span><br><span style="color: hsl(120, 100%, 40%);">+     { "Point", { {"pos", 1, 1, pos_validator}, {NULL, -1, -1} }},</span><br><span style="color: hsl(120, 100%, 40%);">+     { "Polygon", { {"pos", 3, -1, pos_validator}, {NULL, -1, -1} }},</span><br><span style="color: hsl(120, 100%, 40%);">+  { "Circle", { {"pos", 1, 1, pos_validator}, {"radius", 1, 1, float_validator},{NULL, -1, -1}}},</span><br><span style="color: hsl(120, 100%, 40%);">+ { "Ellipse", { {"pos", 1, 1, pos_validator}, {"semiMajorAxis", 1, 1, float_validator},</span><br><span style="color: hsl(120, 100%, 40%);">+          {"semiMinorAxis", 1, 1, float_validator}, {"orientation", 1, 1, float_validator},</span><br><span style="color: hsl(120, 100%, 40%);">+         {"orientation_uom", 1, 1, uom_validator}, {NULL, -1, -1} }},</span><br><span style="color: hsl(120, 100%, 40%);">+        { "ArcBand", { {"pos", 1, 1, pos_validator}, {"innerRadius", 1, 1, float_validator},</span><br><span style="color: hsl(120, 100%, 40%);">+            {"outerRadius", 1, 1, float_validator}, {"startAngle", 1, 1, float_validator},</span><br><span style="color: hsl(120, 100%, 40%);">+            {"startAngle_uom", 1, 1, uom_validator}, {"openingAngle", 1, 1, float_validator},</span><br><span style="color: hsl(120, 100%, 40%);">+         {"openingAngle_uom", 1, 1, uom_validator}, {NULL, -1, -1} }},</span><br><span style="color: hsl(120, 100%, 40%);">+       { "Sphere", { {"pos3d", 1, 1, pos3d_validator}, {"radius", 1, 1, float_validator}, {NULL, -1, -1} }},</span><br><span style="color: hsl(120, 100%, 40%);">+   { "Ellipse", { {"pos3d", 1, 1, pos3d_validator}, {"semiMajorAxis", 1, 1, float_validator},</span><br><span style="color: hsl(120, 100%, 40%);">+              {"semiMinorAxis", 1, 1, float_validator}, {"verticalAxis", 1, 1, float_validator},</span><br><span style="color: hsl(120, 100%, 40%);">+                {"orientation", 1, 1, float_validator}, {"orientation_uom", 1, 1, uom_validator}, {NULL, -1, -1} }},</span><br><span style="color: hsl(120, 100%, 40%);">+      { "Prism", { {"pos3d", 3, -1, pos_validator}, {"height", 1, 1, float_validator}, {NULL, -1, -1} }},</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+enum ast_geoloc_validate_result ast_geoloc_gml_validate_varlist(const struct ast_variable *varlist,</span><br><span style="color: hsl(120, 100%, 40%);">+  const char **result)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+       int def_index = -1;</span><br><span style="color: hsl(120, 100%, 40%);">+   const struct ast_variable *var;</span><br><span style="color: hsl(120, 100%, 40%);">+       int i;</span><br><span style="color: hsl(120, 100%, 40%);">+        const char *shape_type = ast_variable_find_in_list(varlist, "shape");</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     if (!shape_type) {</span><br><span style="color: hsl(120, 100%, 40%);">+            return AST_GEOLOC_VALIDATE_MISSING_SHAPE;</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   for (i = 0; i < ARRAY_LEN(gml_shape_defs); i++) {</span><br><span style="color: hsl(120, 100%, 40%);">+          if (ast_strings_equal(gml_shape_defs[i].shape_type, shape_type)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                    def_index = i;</span><br><span style="color: hsl(120, 100%, 40%);">+                }</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+     if (def_index < 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+               return AST_GEOLOC_VALIDATE_INVALID_SHAPE;</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   for (var = varlist; var; var = var->next) {</span><br><span style="color: hsl(120, 100%, 40%);">+                int vname_index = -1;</span><br><span style="color: hsl(120, 100%, 40%);">+         if (ast_strings_equal("shape", var->name)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                     continue;</span><br><span style="color: hsl(120, 100%, 40%);">+             }</span><br><span style="color: hsl(120, 100%, 40%);">+             for (i = 0; i < ARRAY_LEN(gml_shape_defs[def_index].required_attributes); i++) {</span><br><span style="color: hsl(120, 100%, 40%);">+                   if (gml_shape_defs[def_index].required_attributes[i].attribute == NULL) {</span><br><span style="color: hsl(120, 100%, 40%);">+                             break;</span><br><span style="color: hsl(120, 100%, 40%);">+                        }</span><br><span style="color: hsl(120, 100%, 40%);">+                     if (ast_strings_equal(gml_shape_defs[def_index].required_attributes[i].attribute, var->name)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                            vname_index = i;</span><br><span style="color: hsl(120, 100%, 40%);">+                              break;</span><br><span style="color: hsl(120, 100%, 40%);">+                        }</span><br><span style="color: hsl(120, 100%, 40%);">+             }</span><br><span style="color: hsl(120, 100%, 40%);">+             if (vname_index < 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+                     *result = var->name;</span><br><span style="color: hsl(120, 100%, 40%);">+                       return AST_GEOLOC_VALIDATE_INVALID_VARNAME;</span><br><span style="color: hsl(120, 100%, 40%);">+           }</span><br><span style="color: hsl(120, 100%, 40%);">+             if (!gml_shape_defs[def_index].required_attributes[vname_index].validator(var->value)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                   *result = var->name;</span><br><span style="color: hsl(120, 100%, 40%);">+                       return AST_GEOLOC_VALIDATE_INVALID_VALUE;</span><br><span style="color: hsl(120, 100%, 40%);">+             }</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   for (i = 0; i < ARRAY_LEN(gml_shape_defs[def_index].required_attributes); i++) {</span><br><span style="color: hsl(120, 100%, 40%);">+           int count = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+                if (gml_shape_defs[def_index].required_attributes[i].attribute == NULL) {</span><br><span style="color: hsl(120, 100%, 40%);">+                     break;</span><br><span style="color: hsl(120, 100%, 40%);">+                }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+           for (var = varlist; var; var = var->next) {</span><br><span style="color: hsl(120, 100%, 40%);">+                        if (ast_strings_equal(gml_shape_defs[def_index].required_attributes[i].attribute, var->name)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                            count++;</span><br><span style="color: hsl(120, 100%, 40%);">+                      }</span><br><span style="color: hsl(120, 100%, 40%);">+             }</span><br><span style="color: hsl(120, 100%, 40%);">+             if (count < gml_shape_defs[def_index].required_attributes[i].min_required) {</span><br><span style="color: hsl(120, 100%, 40%);">+                       *result = gml_shape_defs[def_index].required_attributes[i].attribute;</span><br><span style="color: hsl(120, 100%, 40%);">+                 return AST_GEOLOC_VALIDATE_NOT_ENOUGH_VARNAMES;</span><br><span style="color: hsl(120, 100%, 40%);">+               }</span><br><span style="color: hsl(120, 100%, 40%);">+             if (gml_shape_defs[def_index].required_attributes[i].max_allowed > 0 &&</span><br><span style="color: hsl(120, 100%, 40%);">+                    count > gml_shape_defs[def_index].required_attributes[i].max_allowed) {</span><br><span style="color: hsl(120, 100%, 40%);">+                    *result = gml_shape_defs[def_index].required_attributes[i].attribute;</span><br><span style="color: hsl(120, 100%, 40%);">+                 return AST_GEOLOC_VALIDATE_TOO_MANY_VARNAMES;</span><br><span style="color: hsl(120, 100%, 40%);">+         }</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+     return AST_GEOLOC_VALIDATE_SUCCESS;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static char *handle_gml_show(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+   int i;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      switch (cmd) {</span><br><span style="color: hsl(120, 100%, 40%);">+        case CLI_INIT:</span><br><span style="color: hsl(120, 100%, 40%);">+                e->command = "geoloc show gml_shape_defs";</span><br><span style="color: hsl(120, 100%, 40%);">+               e->usage =</span><br><span style="color: hsl(120, 100%, 40%);">+                 "Usage: geoloc show gml_shape_defs\n"</span><br><span style="color: hsl(120, 100%, 40%);">+                       "       Show the GML Shape definitions.\n";</span><br><span style="color: hsl(120, 100%, 40%);">+         return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+  case CLI_GENERATE:</span><br><span style="color: hsl(120, 100%, 40%);">+            return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+  }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   ast_cli(a->fd, "%-16s %-32s\n", "Shape", "Attributes name(min,max)");</span><br><span style="color: hsl(120, 100%, 40%);">+        ast_cli(a->fd, "================ ===============================\n");</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  for (i = 0; i < ARRAY_LEN(gml_shape_defs); i++) {</span><br><span style="color: hsl(120, 100%, 40%);">+          int j;</span><br><span style="color: hsl(120, 100%, 40%);">+                ast_cli(a->fd, "%-16s", gml_shape_defs[i].shape_type);</span><br><span style="color: hsl(120, 100%, 40%);">+           for (j = 0; j < ARRAY_LEN(gml_shape_defs[i].required_attributes); j++) {</span><br><span style="color: hsl(120, 100%, 40%);">+                   if (gml_shape_defs[i].required_attributes[j].attribute == NULL) {</span><br><span style="color: hsl(120, 100%, 40%);">+                             break;</span><br><span style="color: hsl(120, 100%, 40%);">+                        }</span><br><span style="color: hsl(120, 100%, 40%);">+                     if (gml_shape_defs[i].required_attributes[j].max_allowed >= 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+                           ast_cli(a->fd, " %s(%d,%d)", gml_shape_defs[i].required_attributes[j].attribute,</span><br><span style="color: hsl(120, 100%, 40%);">+                                 gml_shape_defs[i].required_attributes[j].min_required,</span><br><span style="color: hsl(120, 100%, 40%);">+                                        gml_shape_defs[i].required_attributes[j].max_allowed);</span><br><span style="color: hsl(120, 100%, 40%);">+                        } else {</span><br><span style="color: hsl(120, 100%, 40%);">+                              ast_cli(a->fd, " %s(%d,unl)", gml_shape_defs[i].required_attributes[j].attribute,</span><br><span style="color: hsl(120, 100%, 40%);">+                                        gml_shape_defs[i].required_attributes[j].min_required);</span><br><span style="color: hsl(120, 100%, 40%);">+                       }</span><br><span style="color: hsl(120, 100%, 40%);">+             }</span><br><span style="color: hsl(120, 100%, 40%);">+             ast_cli(a->fd, "\n");</span><br><span style="color: hsl(120, 100%, 40%);">+    }</span><br><span style="color: hsl(120, 100%, 40%);">+     ast_cli(a->fd, "\n");</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  return CLI_SUCCESS;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static struct ast_cli_entry geoloc_gml_cli[] = {</span><br><span style="color: hsl(120, 100%, 40%);">+    AST_CLI_DEFINE(handle_gml_show, "Show the GML Shape definitions"),</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct ast_xml_node *geoloc_gml_list_to_xml(const struct ast_variable *resolved_location,</span><br><span style="color: hsl(120, 100%, 40%);">+ const char *ref_string)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+    const char *shape;</span><br><span style="color: hsl(120, 100%, 40%);">+    char *crs;</span><br><span style="color: hsl(120, 100%, 40%);">+    struct ast_variable *var;</span><br><span style="color: hsl(120, 100%, 40%);">+     struct ast_xml_node *gml_node;</span><br><span style="color: hsl(120, 100%, 40%);">+        struct ast_xml_node *child_node;</span><br><span style="color: hsl(120, 100%, 40%);">+      int rc = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ SCOPE_ENTER(3, "%s", ref_string);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ shape = ast_variable_find_in_list(resolved_location, "shape");</span><br><span style="color: hsl(120, 100%, 40%);">+      if (ast_strlen_zero(shape)) {</span><br><span style="color: hsl(120, 100%, 40%);">+         SCOPE_EXIT_LOG_RTN_VALUE(NULL, LOG_ERROR, "%s: There's no 'shape' parameter\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                 ref_string);</span><br><span style="color: hsl(120, 100%, 40%);">+  }</span><br><span style="color: hsl(120, 100%, 40%);">+     crs = (char *)ast_variable_find_in_list(resolved_location, "crs");</span><br><span style="color: hsl(120, 100%, 40%);">+  if (ast_strlen_zero(crs)) {</span><br><span style="color: hsl(120, 100%, 40%);">+           crs = "2d";</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   gml_node = ast_xml_new_node(shape);</span><br><span style="color: hsl(120, 100%, 40%);">+   if (!gml_node) {</span><br><span style="color: hsl(120, 100%, 40%);">+              SCOPE_EXIT_LOG_RTN_VALUE(NULL, LOG_ERROR, "%s: Unable to create '%s' XML node\n", shape, ref_string);</span><br><span style="color: hsl(120, 100%, 40%);">+       }</span><br><span style="color: hsl(120, 100%, 40%);">+     rc = ast_xml_set_attribute(gml_node, "crs", crs);</span><br><span style="color: hsl(120, 100%, 40%);">+   if (rc != 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+                ast_xml_free_node(gml_node);</span><br><span style="color: hsl(120, 100%, 40%);">+          SCOPE_EXIT_LOG_RTN_VALUE(NULL, LOG_ERROR, "%s: Unable to create 'crs' XML attribute\n", ref_string);</span><br><span style="color: hsl(120, 100%, 40%);">+        }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   for (var = (struct ast_variable *)resolved_location; var; var = var->next) {</span><br><span style="color: hsl(120, 100%, 40%);">+               RAII_VAR(char *, value, NULL, ast_free);</span><br><span style="color: hsl(120, 100%, 40%);">+              char *uom = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+           if (ast_strings_equal(var->name, "shape") || ast_strings_equal(var->name, "crs")) {</span><br><span style="color: hsl(120, 100%, 40%);">+                 continue;</span><br><span style="color: hsl(120, 100%, 40%);">+             }</span><br><span style="color: hsl(120, 100%, 40%);">+             value = ast_strdup(var->value);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+          if (ast_strings_equal(var->name, "orientation") || ast_strings_equal(var->name, "startAngle")</span><br><span style="color: hsl(120, 100%, 40%);">+                       || ast_strings_equal(var->name, "openingAngle")) {</span><br><span style="color: hsl(120, 100%, 40%);">+                       char *a = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+                       char *junk = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+                    float angle;</span><br><span style="color: hsl(120, 100%, 40%);">+                  uom = value;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+                        /* 'a' should now be the angle and 'uom' should be the uom */</span><br><span style="color: hsl(120, 100%, 40%);">+                 a = strsep(&uom, " ");</span><br><span style="color: hsl(120, 100%, 40%);">+                  angle = strtof(a, &junk);</span><br><span style="color: hsl(120, 100%, 40%);">+                 /*</span><br><span style="color: hsl(120, 100%, 40%);">+                     * strtof sets junk to the first non-valid character so if it's</span><br><span style="color: hsl(120, 100%, 40%);">+                    * not empty after the conversion, there were unrecognized</span><br><span style="color: hsl(120, 100%, 40%);">+                     * characters in the angle.  It'll point to the NULL terminator</span><br><span style="color: hsl(120, 100%, 40%);">+                    * if angle was completely converted.</span><br><span style="color: hsl(120, 100%, 40%);">+                  */</span><br><span style="color: hsl(120, 100%, 40%);">+                   if (!ast_strlen_zero(junk)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                         ast_xml_free_node(gml_node);</span><br><span style="color: hsl(120, 100%, 40%);">+                          SCOPE_EXIT_LOG_RTN_VALUE(NULL, LOG_ERROR, "%s: The angle portion of parameter '%s' ('%s') is malformed\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                                  ref_string, var->name, var->value);</span><br><span style="color: hsl(120, 100%, 40%);">+                     }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+                   if (ast_strlen_zero(uom)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                           uom = "degrees";</span><br><span style="color: hsl(120, 100%, 40%);">+                    }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+                   if (ast_begins_with(uom, "deg")) {</span><br><span style="color: hsl(120, 100%, 40%);">+                          if (angle > 360.0) {</span><br><span style="color: hsl(120, 100%, 40%);">+                                       ast_xml_free_node(gml_node);</span><br><span style="color: hsl(120, 100%, 40%);">+                                  SCOPE_EXIT_LOG_RTN_VALUE(NULL, LOG_ERROR, "%s: Parameter '%s': '%s' is malformed. "</span><br><span style="color: hsl(120, 100%, 40%);">+                                         "Degrees can't be > 360.0\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                                                ref_string, var->name, var->value);</span><br><span style="color: hsl(120, 100%, 40%);">+                             }</span><br><span style="color: hsl(120, 100%, 40%);">+                     } else if (ast_begins_with(uom, "rad")) {</span><br><span style="color: hsl(120, 100%, 40%);">+                           if(angle > 100.0) {</span><br><span style="color: hsl(120, 100%, 40%);">+                                        ast_xml_free_node(gml_node);</span><br><span style="color: hsl(120, 100%, 40%);">+                                  SCOPE_EXIT_LOG_RTN_VALUE(NULL, LOG_ERROR, "%s: Parameter '%s': '%s' is malformed. "</span><br><span style="color: hsl(120, 100%, 40%);">+                                         "Radians can't be  > 100.0\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                                               ref_string, var->name, var->value);</span><br><span style="color: hsl(120, 100%, 40%);">+                             }</span><br><span style="color: hsl(120, 100%, 40%);">+                     } else {</span><br><span style="color: hsl(120, 100%, 40%);">+                              ast_xml_free_node(gml_node);</span><br><span style="color: hsl(120, 100%, 40%);">+                          SCOPE_EXIT_LOG_RTN_VALUE(NULL, LOG_ERROR, "%s: Parameter '%s': '%s' is malformed. "</span><br><span style="color: hsl(120, 100%, 40%);">+                                 "The unit of measure must be 'deg[rees]' or 'rad[ians]'\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                                 ref_string, var->name, var->value);</span><br><span style="color: hsl(120, 100%, 40%);">+                     }</span><br><span style="color: hsl(120, 100%, 40%);">+             }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+           child_node = ast_xml_new_child(gml_node, var->name);</span><br><span style="color: hsl(120, 100%, 40%);">+               if (!child_node) {</span><br><span style="color: hsl(120, 100%, 40%);">+                    ast_xml_free_node(gml_node);</span><br><span style="color: hsl(120, 100%, 40%);">+                  SCOPE_EXIT_LOG_RTN_VALUE(NULL, LOG_ERROR, "%s: Unable to create '%s' XML node\n", var->name, ref_string);</span><br><span style="color: hsl(120, 100%, 40%);">+                }</span><br><span style="color: hsl(120, 100%, 40%);">+             if (!ast_strlen_zero(uom)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                  rc = ast_xml_set_attribute(child_node, "uom", uom);</span><br><span style="color: hsl(120, 100%, 40%);">+                 if (rc != 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+                                ast_xml_free_node(gml_node);</span><br><span style="color: hsl(120, 100%, 40%);">+                          SCOPE_EXIT_LOG_RTN_VALUE(NULL, LOG_ERROR, "%s: Unable to create 'uom' XML attribute\n", ref_string);</span><br><span style="color: hsl(120, 100%, 40%);">+                        }</span><br><span style="color: hsl(120, 100%, 40%);">+             }</span><br><span style="color: hsl(120, 100%, 40%);">+             ast_xml_set_text(child_node, value);</span><br><span style="color: hsl(120, 100%, 40%);">+  }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   SCOPE_EXIT_RTN_VALUE(gml_node, "%s: Done\n", ref_string);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+int geoloc_gml_unload(void)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+      ast_cli_unregister_multiple(geoloc_gml_cli, ARRAY_LEN(geoloc_gml_cli));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     return AST_MODULE_LOAD_SUCCESS;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+int geoloc_gml_load(void)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+    ast_cli_register_multiple(geoloc_gml_cli, ARRAY_LEN(geoloc_gml_cli));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       return AST_MODULE_LOAD_SUCCESS;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+int geoloc_gml_reload(void)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  return AST_MODULE_LOAD_SUCCESS;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span>diff --git a/res/res_geolocation/geoloc_private.h b/res/res_geolocation/geoloc_private.h</span><br><span>new file mode 100644</span><br><span>index 0000000..860f3b5</span><br><span>--- /dev/null</span><br><span>+++ b/res/res_geolocation/geoloc_private.h</span><br><span>@@ -0,0 +1,168 @@</span><br><span style="color: hsl(120, 100%, 40%);">+/*</span><br><span style="color: hsl(120, 100%, 40%);">+ * Asterisk -- An open source telephony toolkit.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * Copyright (C) 2022, Sangoma Technologies Corporation</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * George Joseph <gjoseph@sangoma.com></span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * See http://www.asterisk.org for more information about</span><br><span style="color: hsl(120, 100%, 40%);">+ * the Asterisk project. Please do not directly contact</span><br><span style="color: hsl(120, 100%, 40%);">+ * any of the maintainers of this project for assistance;</span><br><span style="color: hsl(120, 100%, 40%);">+ * the project provides a web site, mailing lists and IRC</span><br><span style="color: hsl(120, 100%, 40%);">+ * channels for your use.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * This program is free software, distributed under the terms of</span><br><span style="color: hsl(120, 100%, 40%);">+ * the GNU General Public License Version 2. See the LICENSE file</span><br><span style="color: hsl(120, 100%, 40%);">+ * at the top of the source tree.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#ifndef GEOLOC_PRIVATE_H_</span><br><span style="color: hsl(120, 100%, 40%);">+#define GEOLOC_PRIVATE_H_</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include "asterisk/module.h"</span><br><span style="color: hsl(120, 100%, 40%);">+#include "asterisk/config.h"</span><br><span style="color: hsl(120, 100%, 40%);">+#include "asterisk/sorcery.h"</span><br><span style="color: hsl(120, 100%, 40%);">+#include "asterisk/lock.h"</span><br><span style="color: hsl(120, 100%, 40%);">+#include "asterisk/res_geolocation.h"</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#define CONFIG_STR_TO_ENUM_DECL(_stem) int geoloc_ ## _stem ## _str_to_enum(const char *str);</span><br><span style="color: hsl(120, 100%, 40%);">+CONFIG_STR_TO_ENUM_DECL(pidf_element)</span><br><span style="color: hsl(120, 100%, 40%);">+CONFIG_STR_TO_ENUM_DECL(format);</span><br><span style="color: hsl(120, 100%, 40%);">+CONFIG_STR_TO_ENUM_DECL(action);</span><br><span style="color: hsl(120, 100%, 40%);">+#define GEOLOC_ENUM_TO_NAME_DECL(_stem) const char * geoloc_ ## _stem ## _to_name(int ix);</span><br><span style="color: hsl(120, 100%, 40%);">+GEOLOC_ENUM_TO_NAME_DECL(pidf_element)</span><br><span style="color: hsl(120, 100%, 40%);">+GEOLOC_ENUM_TO_NAME_DECL(format);</span><br><span style="color: hsl(120, 100%, 40%);">+GEOLOC_ENUM_TO_NAME_DECL(action);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#define CONFIG_STR_TO_ENUM(_stem) \</span><br><span style="color: hsl(120, 100%, 40%);">+int geoloc_ ## _stem ## _str_to_enum(const char *str) \</span><br><span style="color: hsl(120, 100%, 40%);">+{ \</span><br><span style="color: hsl(120, 100%, 40%);">+  int i; \</span><br><span style="color: hsl(120, 100%, 40%);">+      for (i = 0; i < ARRAY_LEN(_stem ## _names); i++) { \</span><br><span style="color: hsl(120, 100%, 40%);">+               if (ast_strings_equal(str, _stem ## _names[i])) { \</span><br><span style="color: hsl(120, 100%, 40%);">+                   return i; \</span><br><span style="color: hsl(120, 100%, 40%);">+           } \</span><br><span style="color: hsl(120, 100%, 40%);">+   } \</span><br><span style="color: hsl(120, 100%, 40%);">+   return -1; \</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#define CONFIG_ENUM_HANDLER(_object, _stem) \</span><br><span style="color: hsl(120, 100%, 40%);">+static int _stem ## _handler(const struct aco_option *opt, struct ast_variable *var, void *obj) \</span><br><span style="color: hsl(120, 100%, 40%);">+{ \</span><br><span style="color: hsl(120, 100%, 40%);">+      struct ast_geoloc_ ## _object *_thisobject = obj; \</span><br><span style="color: hsl(120, 100%, 40%);">+   int enumval = geoloc_ ## _stem ## _str_to_enum(var->value); \</span><br><span style="color: hsl(120, 100%, 40%);">+      if (enumval == -1) { \</span><br><span style="color: hsl(120, 100%, 40%);">+                return -1; \</span><br><span style="color: hsl(120, 100%, 40%);">+  } \</span><br><span style="color: hsl(120, 100%, 40%);">+   _thisobject->_stem = enumval; \</span><br><span style="color: hsl(120, 100%, 40%);">+    return 0; \</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#define GEOLOC_ENUM_TO_NAME(_stem) \</span><br><span style="color: hsl(120, 100%, 40%);">+const char * geoloc_ ## _stem ## _to_name(int ix) \</span><br><span style="color: hsl(120, 100%, 40%);">+{ \</span><br><span style="color: hsl(120, 100%, 40%);">+    if (!ARRAY_IN_BOUNDS(ix, _stem ## _names)) { \</span><br><span style="color: hsl(120, 100%, 40%);">+                return "none"; \</span><br><span style="color: hsl(120, 100%, 40%);">+    } else { \</span><br><span style="color: hsl(120, 100%, 40%);">+            return _stem ## _names[ix]; \</span><br><span style="color: hsl(120, 100%, 40%);">+ } \</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#define CONFIG_ENUM_TO_STR(_object, _stem) \</span><br><span style="color: hsl(120, 100%, 40%);">+static int _stem ## _to_str(const void *obj, const intptr_t *args, char **buf) \</span><br><span style="color: hsl(120, 100%, 40%);">+{ \</span><br><span style="color: hsl(120, 100%, 40%);">+ const struct ast_geoloc_ ## _object *_thisobject = obj; \</span><br><span style="color: hsl(120, 100%, 40%);">+     if (!ARRAY_IN_BOUNDS(_thisobject->_stem, _stem ## _names)) { \</span><br><span style="color: hsl(120, 100%, 40%);">+             *buf = ast_strdup("none"); \</span><br><span style="color: hsl(120, 100%, 40%);">+        } else { \</span><br><span style="color: hsl(120, 100%, 40%);">+            *buf = ast_strdup(_stem ## _names[_thisobject->_stem]); \</span><br><span style="color: hsl(120, 100%, 40%);">+  } \</span><br><span style="color: hsl(120, 100%, 40%);">+   return 0; \</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#define CONFIG_ENUM(_object, _stem) \</span><br><span style="color: hsl(120, 100%, 40%);">+CONFIG_STR_TO_ENUM(_stem) \</span><br><span style="color: hsl(120, 100%, 40%);">+GEOLOC_ENUM_TO_NAME(_stem) \</span><br><span style="color: hsl(120, 100%, 40%);">+CONFIG_ENUM_HANDLER(_object, _stem) \</span><br><span style="color: hsl(120, 100%, 40%);">+CONFIG_ENUM_TO_STR(_object, _stem)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#define CONFIG_VAR_LIST_HANDLER(_object, _stem) \</span><br><span style="color: hsl(120, 100%, 40%);">+static int _stem ## _handler(const struct aco_option *opt, struct ast_variable *var, void *obj) \</span><br><span style="color: hsl(120, 100%, 40%);">+{ \</span><br><span style="color: hsl(120, 100%, 40%);">+    struct ast_geoloc_ ## _object *_thisobject = obj; \</span><br><span style="color: hsl(120, 100%, 40%);">+   struct ast_variable *new_var; \</span><br><span style="color: hsl(120, 100%, 40%);">+       char *item_string, *item, *item_name, *item_value; \</span><br><span style="color: hsl(120, 100%, 40%);">+  int rc = 0;\</span><br><span style="color: hsl(120, 100%, 40%);">+  if (ast_strlen_zero(var->value)) { return 0; } \</span><br><span style="color: hsl(120, 100%, 40%);">+   item_string = ast_strdupa(var->value); \</span><br><span style="color: hsl(120, 100%, 40%);">+   while ((item = ast_strsep(&item_string, ',', AST_STRSEP_ALL))) { \</span><br><span style="color: hsl(120, 100%, 40%);">+                item_name = ast_strsep(&item, '=', AST_STRSEP_ALL); \</span><br><span style="color: hsl(120, 100%, 40%);">+             item_value = ast_strsep(&item, '=', AST_STRSEP_ALL); \</span><br><span style="color: hsl(120, 100%, 40%);">+            new_var = ast_variable_new(item_name, item_value, ""); \</span><br><span style="color: hsl(120, 100%, 40%);">+            if (!new_var) { \</span><br><span style="color: hsl(120, 100%, 40%);">+                     rc = -1; \</span><br><span style="color: hsl(120, 100%, 40%);">+                    break; \</span><br><span style="color: hsl(120, 100%, 40%);">+              } \</span><br><span style="color: hsl(120, 100%, 40%);">+           ast_variable_list_append(&_thisobject->_stem, new_var); \</span><br><span style="color: hsl(120, 100%, 40%);">+      } \</span><br><span style="color: hsl(120, 100%, 40%);">+   return rc; \</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#define CONFIG_VAR_LIST_DUP(_object, _stem) \</span><br><span style="color: hsl(120, 100%, 40%);">+static int _stem ## _dup(const void *obj, struct ast_variable **fields) \</span><br><span style="color: hsl(120, 100%, 40%);">+{ \</span><br><span style="color: hsl(120, 100%, 40%);">+      const struct ast_geoloc_ ## _object *_thisobject = obj; \</span><br><span style="color: hsl(120, 100%, 40%);">+     if (_thisobject->_stem) { \</span><br><span style="color: hsl(120, 100%, 40%);">+                *fields = ast_variables_dup(_thisobject->_stem); \</span><br><span style="color: hsl(120, 100%, 40%);">+ } \</span><br><span style="color: hsl(120, 100%, 40%);">+   return 0; \</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#define CONFIG_VAR_LIST_TO_STR(_object, _stem) \</span><br><span style="color: hsl(120, 100%, 40%);">+static int _stem ## _to_str(const void *obj, const intptr_t *args, char **buf) \</span><br><span style="color: hsl(120, 100%, 40%);">+{ \</span><br><span style="color: hsl(120, 100%, 40%);">+     const struct ast_geoloc_ ## _object *_thisobject = obj; \</span><br><span style="color: hsl(120, 100%, 40%);">+     struct ast_str *str = ast_variable_list_join(_thisobject->_stem, ",", "=", "\"", NULL); \</span><br><span style="color: hsl(120, 100%, 40%);">+       *buf = ast_strdup(ast_str_buffer(str)); \</span><br><span style="color: hsl(120, 100%, 40%);">+     ast_free(str); \</span><br><span style="color: hsl(120, 100%, 40%);">+      return 0; \</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#define CONFIG_VAR_LIST(_object, _stem) \</span><br><span style="color: hsl(120, 100%, 40%);">+CONFIG_VAR_LIST_HANDLER(_object, _stem) \</span><br><span style="color: hsl(120, 100%, 40%);">+CONFIG_VAR_LIST_DUP(_object, _stem) \</span><br><span style="color: hsl(120, 100%, 40%);">+CONFIG_VAR_LIST_TO_STR(_object, _stem)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+int geoloc_config_load(void);</span><br><span style="color: hsl(120, 100%, 40%);">+int geoloc_config_reload(void);</span><br><span style="color: hsl(120, 100%, 40%);">+int geoloc_config_unload(void);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct ast_xml_node *geoloc_civicaddr_list_to_xml(const struct ast_variable *resolved_location,</span><br><span style="color: hsl(120, 100%, 40%);">+   const char *ref_string);</span><br><span style="color: hsl(120, 100%, 40%);">+int geoloc_civicaddr_load(void);</span><br><span style="color: hsl(120, 100%, 40%);">+int geoloc_civicaddr_unload(void);</span><br><span style="color: hsl(120, 100%, 40%);">+int geoloc_civicaddr_reload(void);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct ast_xml_node *geoloc_gml_list_to_xml(const struct ast_variable *resolved_location,</span><br><span style="color: hsl(120, 100%, 40%);">+       const char *ref_string);</span><br><span style="color: hsl(120, 100%, 40%);">+int geoloc_gml_unload(void);</span><br><span style="color: hsl(120, 100%, 40%);">+int geoloc_gml_load(void);</span><br><span style="color: hsl(120, 100%, 40%);">+int geoloc_gml_reload(void);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+int geoloc_dialplan_unload(void);</span><br><span style="color: hsl(120, 100%, 40%);">+int geoloc_dialplan_load(void);</span><br><span style="color: hsl(120, 100%, 40%);">+int geoloc_dialplan_reload(void);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+int geoloc_channel_unload(void);</span><br><span style="color: hsl(120, 100%, 40%);">+int geoloc_channel_load(void);</span><br><span style="color: hsl(120, 100%, 40%);">+int geoloc_channel_reload(void);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+int geoloc_eprofile_unload(void);</span><br><span style="color: hsl(120, 100%, 40%);">+int geoloc_eprofile_load(void);</span><br><span style="color: hsl(120, 100%, 40%);">+int geoloc_eprofile_reload(void);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct ast_sorcery *geoloc_get_sorcery(void);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#endif /* GEOLOC_PRIVATE_H_ */</span><br><span>diff --git a/res/res_geolocation/pidf_lo_test.xml b/res/res_geolocation/pidf_lo_test.xml</span><br><span>new file mode 100644</span><br><span>index 0000000..3948063</span><br><span>--- /dev/null</span><br><span>+++ b/res/res_geolocation/pidf_lo_test.xml</span><br><span>@@ -0,0 +1,312 @@</span><br><span style="color: hsl(120, 100%, 40%);">+<?xml version="1.0" encoding="UTF-8"?></span><br><span style="color: hsl(120, 100%, 40%);">+<presence entity="pres:alice@asterisk.org"</span><br><span style="color: hsl(120, 100%, 40%);">+    xmlns="urn:ietf:params:xml:ns:pidf"</span><br><span style="color: hsl(120, 100%, 40%);">+ xmlns:ca="urn:ietf:params:xml:ns:pidf:geopriv10:civicAddr"</span><br><span style="color: hsl(120, 100%, 40%);">+  xmlns:dm="urn:ietf:params:xml:ns:pidf:data-model"</span><br><span style="color: hsl(120, 100%, 40%);">+   xmlns:gbp="urn:ietf:params:xml:ns:pidf:geopriv10:basicPolicy"</span><br><span style="color: hsl(120, 100%, 40%);">+       xmlns:gml="http://www.opengis.net/gml"</span><br><span style="color: hsl(120, 100%, 40%);">+      xmlns:gp="urn:ietf:params:xml:ns:pidf:geopriv10"</span><br><span style="color: hsl(120, 100%, 40%);">+    xmlns:gs="http://www.opengis.net/pidflo/1.0"></span><br><span style="color: hsl(120, 100%, 40%);">+    <tuple id="point-2d"></span><br><span style="color: hsl(120, 100%, 40%);">+         <status></span><br><span style="color: hsl(120, 100%, 40%);">+                        <gp:geopriv></span><br><span style="color: hsl(120, 100%, 40%);">+                            <gp:location-info></span><br><span style="color: hsl(120, 100%, 40%);">+                                      <gml:Point srsName="urn:ogc:def:crs:EPSG::4326"></span><br><span style="color: hsl(120, 100%, 40%);">+                                              <gml:pos>-34.410649 150.87651</gml:pos></span><br><span style="color: hsl(120, 100%, 40%);">+                                   </gml:Point></span><br><span style="color: hsl(120, 100%, 40%);">+                            </gp:location-info></span><br><span style="color: hsl(120, 100%, 40%);">+                             <gp:usage-rules></span><br><span style="color: hsl(120, 100%, 40%);">+                                        <gbp:retransmission-allowed>no</gbp:retransmission-allowed></span><br><span style="color: hsl(120, 100%, 40%);">+                                       <gbp:retention-expiry>2010-11-14T20:00:00Z</gbp:retention-expiry></span><br><span style="color: hsl(120, 100%, 40%);">+                         </gp:usage-rules></span><br><span style="color: hsl(120, 100%, 40%);">+                               <gp:method>Manual</gp:method></span><br><span style="color: hsl(120, 100%, 40%);">+                     </gp:geopriv></span><br><span style="color: hsl(120, 100%, 40%);">+           </status></span><br><span style="color: hsl(120, 100%, 40%);">+               <timestamp>2007-06-22T20:57:29Z</timestamp></span><br><span style="color: hsl(120, 100%, 40%);">+       </tuple></span><br><span style="color: hsl(120, 100%, 40%);">+        <dm:person id="point-3d"></span><br><span style="color: hsl(120, 100%, 40%);">+             <gp:geopriv></span><br><span style="color: hsl(120, 100%, 40%);">+                    <gp:location-info></span><br><span style="color: hsl(120, 100%, 40%);">+                              <gml:Point srsName="urn:ogc:def:crs:EPSG::4979"></span><br><span style="color: hsl(120, 100%, 40%);">+                                      <gml:pos>-34.410649 150.87651 1800</gml:pos></span><br><span style="color: hsl(120, 100%, 40%);">+                              </gml:Point></span><br><span style="color: hsl(120, 100%, 40%);">+                    </gp:location-info></span><br><span style="color: hsl(120, 100%, 40%);">+                     <gp:usage-rules></span><br><span style="color: hsl(120, 100%, 40%);">+                                <gbp:retransmission-allowed>no</gbp:retransmission-allowed></span><br><span style="color: hsl(120, 100%, 40%);">+                               <gbp:retention-expiry>2010-11-14T20:00:00Z</gbp:retention-expiry></span><br><span style="color: hsl(120, 100%, 40%);">+                 </gp:usage-rules></span><br><span style="color: hsl(120, 100%, 40%);">+                       <gp:method>802.11</gp:method></span><br><span style="color: hsl(120, 100%, 40%);">+             </gp:geopriv></span><br><span style="color: hsl(120, 100%, 40%);">+           <dm:timestamp>2007-06-24T12:28:04Z</dm:timestamp></span><br><span style="color: hsl(120, 100%, 40%);">+ </dm:person></span><br><span style="color: hsl(120, 100%, 40%);">+    <tuple id="circle-2d"></span><br><span style="color: hsl(120, 100%, 40%);">+                <status></span><br><span style="color: hsl(120, 100%, 40%);">+                        <gp:geopriv></span><br><span style="color: hsl(120, 100%, 40%);">+                            <gp:location-info></span><br><span style="color: hsl(120, 100%, 40%);">+                                      <gs:Circle srsName="urn:ogc:def:crs:EPSG::4326"></span><br><span style="color: hsl(120, 100%, 40%);">+                                              <gml:pos>-34.410649 150.87651</gml:pos></span><br><span style="color: hsl(120, 100%, 40%);">+                                           <gs:radius uom="urn:ogc:def:uom:EPSG::9001">30</gs:radius></span><br><span style="color: hsl(120, 100%, 40%);">+                                      </gs:Circle></span><br><span style="color: hsl(120, 100%, 40%);">+                            </gp:location-info></span><br><span style="color: hsl(120, 100%, 40%);">+                             <gp:usage-rules></span><br><span style="color: hsl(120, 100%, 40%);">+                                        <gbp:retransmission-allowed>no</gbp:retransmission-allowed></span><br><span style="color: hsl(120, 100%, 40%);">+                                       <gbp:retention-expiry>2010-11-14T20:00:00Z</gbp:retention-expiry></span><br><span style="color: hsl(120, 100%, 40%);">+                         </gp:usage-rules></span><br><span style="color: hsl(120, 100%, 40%);">+                               <gp:method>802.11</gp:method></span><br><span style="color: hsl(120, 100%, 40%);">+                     </gp:geopriv></span><br><span style="color: hsl(120, 100%, 40%);">+           </status></span><br><span style="color: hsl(120, 100%, 40%);">+               <timestamp>2007-06-22T20:57:29Z</timestamp></span><br><span style="color: hsl(120, 100%, 40%);">+       </tuple></span><br><span style="color: hsl(120, 100%, 40%);">+        <tuple id="circle-3d"></span><br><span style="color: hsl(120, 100%, 40%);">+                <status></span><br><span style="color: hsl(120, 100%, 40%);">+                        <gp:geopriv></span><br><span style="color: hsl(120, 100%, 40%);">+                            <gp:location-info></span><br><span style="color: hsl(120, 100%, 40%);">+                                      <gs:Circle srsName="urn:ogc:def:crs:EPSG::4979"></span><br><span style="color: hsl(120, 100%, 40%);">+                                              <gml:pos>-34.410649 150.87651 1800</gml:pos></span><br><span style="color: hsl(120, 100%, 40%);">+                                              <gs:radius uom="urn:ogc:def:uom:EPSG::9001">30</gs:radius></span><br><span style="color: hsl(120, 100%, 40%);">+                                      </gs:Circle></span><br><span style="color: hsl(120, 100%, 40%);">+                            </gp:location-info></span><br><span style="color: hsl(120, 100%, 40%);">+                             <gp:usage-rules></span><br><span style="color: hsl(120, 100%, 40%);">+                                        <gbp:retransmission-allowed>no</gbp:retransmission-allowed></span><br><span style="color: hsl(120, 100%, 40%);">+                                       <gbp:retention-expiry>2010-11-14T20:00:00Z</gbp:retention-expiry></span><br><span style="color: hsl(120, 100%, 40%);">+                         </gp:usage-rules></span><br><span style="color: hsl(120, 100%, 40%);">+                               <gp:method>802.11</gp:method></span><br><span style="color: hsl(120, 100%, 40%);">+                     </gp:geopriv></span><br><span style="color: hsl(120, 100%, 40%);">+           </status></span><br><span style="color: hsl(120, 100%, 40%);">+               <timestamp>2007-06-22T20:57:29Z</timestamp></span><br><span style="color: hsl(120, 100%, 40%);">+       </tuple></span><br><span style="color: hsl(120, 100%, 40%);">+        <dm:person id="polygon-2d"></span><br><span style="color: hsl(120, 100%, 40%);">+           <gp:geopriv></span><br><span style="color: hsl(120, 100%, 40%);">+                    <gp:location-info></span><br><span style="color: hsl(120, 100%, 40%);">+                              <gml:Polygon srsName="urn:ogc:def:crs:EPSG::4326"></span><br><span style="color: hsl(120, 100%, 40%);">+                                    <gml:exterior></span><br><span style="color: hsl(120, 100%, 40%);">+                                          <gml:LinearRing></span><br><span style="color: hsl(120, 100%, 40%);">+                                                        <gml:pos>43.311 -73.422</gml:pos></span><br><span style="color: hsl(120, 100%, 40%);">+                                                 <gml:pos>43.111 -73.322</gml:pos></span><br><span style="color: hsl(120, 100%, 40%);">+                                                 <gml:pos>43.111 -73.222</gml:pos></span><br><span style="color: hsl(120, 100%, 40%);">+                                                 <gml:pos>43.311 -73.122</gml:pos></span><br><span style="color: hsl(120, 100%, 40%);">+                                                 <gml:pos>43.411 -73.222</gml:pos></span><br><span style="color: hsl(120, 100%, 40%);">+                                                 <gml:pos>43.411 -73.322</gml:pos></span><br><span style="color: hsl(120, 100%, 40%);">+                                                 <gml:pos>43.311 -73.422</gml:pos></span><br><span style="color: hsl(120, 100%, 40%);">+                                         </gml:LinearRing></span><br><span style="color: hsl(120, 100%, 40%);">+                                       </gml:exterior></span><br><span style="color: hsl(120, 100%, 40%);">+                         </gml:Polygon></span><br><span style="color: hsl(120, 100%, 40%);">+                  </gp:location-info></span><br><span style="color: hsl(120, 100%, 40%);">+                     <gp:usage-rules></span><br><span style="color: hsl(120, 100%, 40%);">+                                <gbp:retransmission-allowed>no</gbp:retransmission-allowed></span><br><span style="color: hsl(120, 100%, 40%);">+                               <gbp:retention-expiry>2010-11-14T20:00:00Z</gbp:retention-expiry></span><br><span style="color: hsl(120, 100%, 40%);">+                 </gp:usage-rules></span><br><span style="color: hsl(120, 100%, 40%);">+                       <gp:method>802.11</gp:method></span><br><span style="color: hsl(120, 100%, 40%);">+             </gp:geopriv></span><br><span style="color: hsl(120, 100%, 40%);">+           <dm:timestamp>2007-06-24T12:28:04Z</dm:timestamp></span><br><span style="color: hsl(120, 100%, 40%);">+ </dm:person></span><br><span style="color: hsl(120, 100%, 40%);">+    <dm:person id="polygon-3d"></span><br><span style="color: hsl(120, 100%, 40%);">+           <gp:geopriv></span><br><span style="color: hsl(120, 100%, 40%);">+                    <gp:location-info></span><br><span style="color: hsl(120, 100%, 40%);">+                              <gml:Polygon srsName="urn:ogc:def:crs:EPSG::4979"></span><br><span style="color: hsl(120, 100%, 40%);">+                                    <gml:exterior></span><br><span style="color: hsl(120, 100%, 40%);">+                                          <gml:LinearRing></span><br><span style="color: hsl(120, 100%, 40%);">+                                                        <gml:pos>43.311 -73.422 1800</gml:pos></span><br><span style="color: hsl(120, 100%, 40%);">+                                                    <gml:pos>43.111 -73.322 1800</gml:pos></span><br><span style="color: hsl(120, 100%, 40%);">+                                                    <gml:pos>43.111 -73.222 1800</gml:pos></span><br><span style="color: hsl(120, 100%, 40%);">+                                                    <gml:pos>43.311 -73.122 1800</gml:pos></span><br><span style="color: hsl(120, 100%, 40%);">+                                                    <gml:pos>43.411 -73.222 1800</gml:pos></span><br><span style="color: hsl(120, 100%, 40%);">+                                                    <gml:pos>43.411 -73.322 1800</gml:pos></span><br><span style="color: hsl(120, 100%, 40%);">+                                                    <gml:pos>43.311 -73.422 1800</gml:pos></span><br><span style="color: hsl(120, 100%, 40%);">+                                            </gml:LinearRing></span><br><span style="color: hsl(120, 100%, 40%);">+                                       </gml:exterior></span><br><span style="color: hsl(120, 100%, 40%);">+                         </gml:Polygon></span><br><span style="color: hsl(120, 100%, 40%);">+                  </gp:location-info></span><br><span style="color: hsl(120, 100%, 40%);">+                     <gp:usage-rules></span><br><span style="color: hsl(120, 100%, 40%);">+                                <gbp:retransmission-allowed>no</gbp:retransmission-allowed></span><br><span style="color: hsl(120, 100%, 40%);">+                               <gbp:retention-expiry>2010-11-14T20:00:00Z</gbp:retention-expiry></span><br><span style="color: hsl(120, 100%, 40%);">+                 </gp:usage-rules></span><br><span style="color: hsl(120, 100%, 40%);">+                       <gp:method>802.11</gp:method></span><br><span style="color: hsl(120, 100%, 40%);">+             </gp:geopriv></span><br><span style="color: hsl(120, 100%, 40%);">+           <dm:timestamp>2007-06-24T12:28:04Z</dm:timestamp></span><br><span style="color: hsl(120, 100%, 40%);">+ </dm:person></span><br><span style="color: hsl(120, 100%, 40%);">+    <tuple id="polygon-poslist-2d"></span><br><span style="color: hsl(120, 100%, 40%);">+               <status></span><br><span style="color: hsl(120, 100%, 40%);">+                        <gp:geopriv></span><br><span style="color: hsl(120, 100%, 40%);">+                            <gp:location-info></span><br><span style="color: hsl(120, 100%, 40%);">+                                      <gml:Polygon srsName="urn:ogc:def:crs:EPSG::4326"></span><br><span style="color: hsl(120, 100%, 40%);">+                                            <gml:exterior></span><br><span style="color: hsl(120, 100%, 40%);">+                                                  <gml:LinearRing></span><br><span style="color: hsl(120, 100%, 40%);">+                                                                <gml:posList></span><br><span style="color: hsl(120, 100%, 40%);">+                                                                   43.311 -73.422 43.111 -73.322</span><br><span style="color: hsl(120, 100%, 40%);">+                                                                 43.111 -73.222 43.311 -73.122</span><br><span style="color: hsl(120, 100%, 40%);">+                                                                 43.411 -73.222 43.411 -73.322</span><br><span style="color: hsl(120, 100%, 40%);">+                                                                 43.311 -73.422</span><br><span style="color: hsl(120, 100%, 40%);">+                                                                </gml:posList></span><br><span style="color: hsl(120, 100%, 40%);">+                                                  </gml:LinearRing></span><br><span style="color: hsl(120, 100%, 40%);">+                                               </gml:exterior></span><br><span style="color: hsl(120, 100%, 40%);">+                                 </gml:Polygon></span><br><span style="color: hsl(120, 100%, 40%);">+                          </gp:location-info></span><br><span style="color: hsl(120, 100%, 40%);">+                             <gp:usage-rules></span><br><span style="color: hsl(120, 100%, 40%);">+                                        <gbp:retransmission-allowed>no</gbp:retransmission-allowed></span><br><span style="color: hsl(120, 100%, 40%);">+                                       <gbp:retention-expiry>2010-11-14T20:00:00Z</gbp:retention-expiry></span><br><span style="color: hsl(120, 100%, 40%);">+                         </gp:usage-rules></span><br><span style="color: hsl(120, 100%, 40%);">+                               <gp:method>Wiremap</gp:method></span><br><span style="color: hsl(120, 100%, 40%);">+                    </gp:geopriv></span><br><span style="color: hsl(120, 100%, 40%);">+           </status></span><br><span style="color: hsl(120, 100%, 40%);">+               <timestamp>2007-06-22T20:57:29Z</timestamp></span><br><span style="color: hsl(120, 100%, 40%);">+       </tuple></span><br><span style="color: hsl(120, 100%, 40%);">+        <tuple id="polygon-poslist-3d"></span><br><span style="color: hsl(120, 100%, 40%);">+               <status></span><br><span style="color: hsl(120, 100%, 40%);">+                        <gp:geopriv></span><br><span style="color: hsl(120, 100%, 40%);">+                            <gp:location-info></span><br><span style="color: hsl(120, 100%, 40%);">+                                      <gml:Polygon srsName="urn:ogc:def:crs:EPSG::4979"></span><br><span style="color: hsl(120, 100%, 40%);">+                                            <gml:exterior></span><br><span style="color: hsl(120, 100%, 40%);">+                                                  <gml:LinearRing></span><br><span style="color: hsl(120, 100%, 40%);">+                                                                <gml:posList></span><br><span style="color: hsl(120, 100%, 40%);">+                                                                   43.311 -73.422 1800 43.111 -73.322 1800</span><br><span style="color: hsl(120, 100%, 40%);">+                                                                       43.111 -73.222 1800 43.311 -73.122 1800</span><br><span style="color: hsl(120, 100%, 40%);">+                                                                       43.411 -73.222 1800 43.411 -73.322 1800</span><br><span style="color: hsl(120, 100%, 40%);">+                                                                       43.311 -73.422 1800</span><br><span style="color: hsl(120, 100%, 40%);">+                                                           </gml:posList></span><br><span style="color: hsl(120, 100%, 40%);">+                                                  </gml:LinearRing></span><br><span style="color: hsl(120, 100%, 40%);">+                                               </gml:exterior></span><br><span style="color: hsl(120, 100%, 40%);">+                                 </gml:Polygon></span><br><span style="color: hsl(120, 100%, 40%);">+                          </gp:location-info></span><br><span style="color: hsl(120, 100%, 40%);">+                             <gp:usage-rules></span><br><span style="color: hsl(120, 100%, 40%);">+                                        <gbp:retransmission-allowed>no</gbp:retransmission-allowed></span><br><span style="color: hsl(120, 100%, 40%);">+                                       <gbp:retention-expiry>2010-11-14T20:00:00Z</gbp:retention-expiry></span><br><span style="color: hsl(120, 100%, 40%);">+                         </gp:usage-rules></span><br><span style="color: hsl(120, 100%, 40%);">+                               <gp:method>Wiremap</gp:method></span><br><span style="color: hsl(120, 100%, 40%);">+                    </gp:geopriv></span><br><span style="color: hsl(120, 100%, 40%);">+           </status></span><br><span style="color: hsl(120, 100%, 40%);">+               <timestamp>2007-06-22T20:57:29Z</timestamp></span><br><span style="color: hsl(120, 100%, 40%);">+       </tuple></span><br><span style="color: hsl(120, 100%, 40%);">+        <tuple id="ellipse-2d"></span><br><span style="color: hsl(120, 100%, 40%);">+               <status></span><br><span style="color: hsl(120, 100%, 40%);">+                        <gp:geopriv></span><br><span style="color: hsl(120, 100%, 40%);">+                            <gp:location-info></span><br><span style="color: hsl(120, 100%, 40%);">+                                      <gs:Ellipse srsName="urn:ogc:def:crs:EPSG::4326"></span><br><span style="color: hsl(120, 100%, 40%);">+                                             <gml:pos>42.5463 -73.2512</gml:pos></span><br><span style="color: hsl(120, 100%, 40%);">+                                               <gs:semiMajorAxis uom="urn:ogc:def:uom:EPSG::9001">1275</gs:semiMajorAxis></span><br><span style="color: hsl(120, 100%, 40%);">+                                              <gs:semiMinorAxis uom="urn:ogc:def:uom:EPSG::9001">670</gs:semiMinorAxis></span><br><span style="color: hsl(120, 100%, 40%);">+                                               <gs:orientation uom="urn:ogc:def:uom:EPSG::9102">43.2</gs:orientation></span><br><span style="color: hsl(120, 100%, 40%);">+                                  </gs:Ellipse></span><br><span style="color: hsl(120, 100%, 40%);">+                           </gp:location-info></span><br><span style="color: hsl(120, 100%, 40%);">+                             <gp:usage-rules/></span><br><span style="color: hsl(120, 100%, 40%);">+                               <gp:method>Device-Assisted_A-GPS</gp:method></span><br><span style="color: hsl(120, 100%, 40%);">+                      </gp:geopriv></span><br><span style="color: hsl(120, 100%, 40%);">+           </status></span><br><span style="color: hsl(120, 100%, 40%);">+               <timestamp>2007-06-22T20:57:29Z</timestamp></span><br><span style="color: hsl(120, 100%, 40%);">+       </tuple></span><br><span style="color: hsl(120, 100%, 40%);">+        <dm:device id="arcband-2d"></span><br><span style="color: hsl(120, 100%, 40%);">+           <gp:geopriv></span><br><span style="color: hsl(120, 100%, 40%);">+                    <gp:location-info></span><br><span style="color: hsl(120, 100%, 40%);">+                              <gs:ArcBand srsName="urn:ogc:def:crs:EPSG::4326"></span><br><span style="color: hsl(120, 100%, 40%);">+                                     <gml:pos>-43.5723 153.21760</gml:pos></span><br><span style="color: hsl(120, 100%, 40%);">+                                     <gs:innerRadius uom="urn:ogc:def:uom:EPSG::9001">3594</gs:innerRadius></span><br><span style="color: hsl(120, 100%, 40%);">+                                  <gs:outerRadius uom="urn:ogc:def:uom:EPSG::9001">4148</gs:outerRadius></span><br><span style="color: hsl(120, 100%, 40%);">+                                  <gs:startAngle uom="urn:ogc:def:uom:EPSG::9102">20</gs:startAngle></span><br><span style="color: hsl(120, 100%, 40%);">+                                      <gs:openingAngle uom="urn:ogc:def:uom:EPSG::9102">20</gs:openingAngle></span><br><span style="color: hsl(120, 100%, 40%);">+                          </gs:ArcBand></span><br><span style="color: hsl(120, 100%, 40%);">+                   </gp:location-info></span><br><span style="color: hsl(120, 100%, 40%);">+                     <gp:usage-rules></span><br><span style="color: hsl(120, 100%, 40%);">+                                <gp:retransmission-allowed>yes</gp:retransmission-allowed></span><br><span style="color: hsl(120, 100%, 40%);">+                                <gp:ruleset-preference>https:/www/more.com</gp:ruleset-preference></span><br><span style="color: hsl(120, 100%, 40%);">+                                <gp:retention-expires>2007-06-22T20:57:29Z</gp:retention-expires></span><br><span style="color: hsl(120, 100%, 40%);">+                 </gp:usage-rules></span><br><span style="color: hsl(120, 100%, 40%);">+                       <gp:method>TA-NMR</gp:method></span><br><span style="color: hsl(120, 100%, 40%);">+             </gp:geopriv></span><br><span style="color: hsl(120, 100%, 40%);">+           <dm:deviceID>mac:1234567890ab</dm:deviceID></span><br><span style="color: hsl(120, 100%, 40%);">+               <dm:timestamp>2007-06-22T20:57:29Z</dm:timestamp></span><br><span style="color: hsl(120, 100%, 40%);">+ </dm:device></span><br><span style="color: hsl(120, 100%, 40%);">+    <tuple id="sphere"></span><br><span style="color: hsl(120, 100%, 40%);">+           <status></span><br><span style="color: hsl(120, 100%, 40%);">+                        <gp:geopriv></span><br><span style="color: hsl(120, 100%, 40%);">+                            <gp:location-info></span><br><span style="color: hsl(120, 100%, 40%);">+                                      <gs:Sphere srsName="urn:ogc:def:crs:EPSG::4979"></span><br><span style="color: hsl(120, 100%, 40%);">+                                              <gml:pos>42.5463 -73.2512 26.3</gml:pos></span><br><span style="color: hsl(120, 100%, 40%);">+                                          <gs:radius uom="urn:ogc:def:uom:EPSG::9001">850.24</gs:radius></span><br><span style="color: hsl(120, 100%, 40%);">+                                  </gs:Sphere></span><br><span style="color: hsl(120, 100%, 40%);">+                            </gp:location-info></span><br><span style="color: hsl(120, 100%, 40%);">+                             <gp:usage-rules></span><br><span style="color: hsl(120, 100%, 40%);">+                                        <gbp:retransmission-allowed>no</gbp:retransmission-allowed></span><br><span style="color: hsl(120, 100%, 40%);">+                                       <gbp:retention-expiry>2010-11-14T20:00:00Z</gbp:retention-expiry></span><br><span style="color: hsl(120, 100%, 40%);">+                         </gp:usage-rules></span><br><span style="color: hsl(120, 100%, 40%);">+                               <gp:method>Device-Based_A-GPS</gp:method></span><br><span style="color: hsl(120, 100%, 40%);">+                 </gp:geopriv></span><br><span style="color: hsl(120, 100%, 40%);">+           </status></span><br><span style="color: hsl(120, 100%, 40%);">+       </tuple></span><br><span style="color: hsl(120, 100%, 40%);">+        <tuple id="ellipsoid"></span><br><span style="color: hsl(120, 100%, 40%);">+                <status></span><br><span style="color: hsl(120, 100%, 40%);">+                        <gp:geopriv></span><br><span style="color: hsl(120, 100%, 40%);">+                            <gp:location-info></span><br><span style="color: hsl(120, 100%, 40%);">+                                      <gs:Ellipsoid srsName="urn:ogc:def:crs:EPSG::4979"></span><br><span style="color: hsl(120, 100%, 40%);">+                                           <gml:pos>42.5463 -73.2512 26.3</gml:pos></span><br><span style="color: hsl(120, 100%, 40%);">+                                          <gs:semiMajorAxis uom="urn:ogc:def:uom:EPSG::9001">7.7156</gs:semiMajorAxis></span><br><span style="color: hsl(120, 100%, 40%);">+                                            <gs:semiMinorAxis uom="urn:ogc:def:uom:EPSG::9001">3.31</gs:semiMinorAxis></span><br><span style="color: hsl(120, 100%, 40%);">+                                              <gs:verticalAxis uom="urn:ogc:def:uom:EPSG::9001">28.7</gs:verticalAxis></span><br><span style="color: hsl(120, 100%, 40%);">+                                                <gs:orientation uom="urn:ogc:def:uom:EPSG::9102">90</gs:orientation></span><br><span style="color: hsl(120, 100%, 40%);">+                                    </gs:Ellipsoid></span><br><span style="color: hsl(120, 100%, 40%);">+                         </gp:location-info></span><br><span style="color: hsl(120, 100%, 40%);">+                             <gp:usage-rules/></span><br><span style="color: hsl(120, 100%, 40%);">+                               <gp:method>Hybrid_A-GPS</gp:method></span><br><span style="color: hsl(120, 100%, 40%);">+                       </gp:geopriv></span><br><span style="color: hsl(120, 100%, 40%);">+           </status></span><br><span style="color: hsl(120, 100%, 40%);">+               <timestamp>2007-06-22T20:57:29Z</timestamp></span><br><span style="color: hsl(120, 100%, 40%);">+       </tuple></span><br><span style="color: hsl(120, 100%, 40%);">+        <tuple id="prism"></span><br><span style="color: hsl(120, 100%, 40%);">+            <status></span><br><span style="color: hsl(120, 100%, 40%);">+                        <gp:geopriv></span><br><span style="color: hsl(120, 100%, 40%);">+                            <gp:location-info></span><br><span style="color: hsl(120, 100%, 40%);">+                                      <gs:Prism srsName="urn:ogc:def:crs:EPSG::4979"></span><br><span style="color: hsl(120, 100%, 40%);">+                                               <gs:base></span><br><span style="color: hsl(120, 100%, 40%);">+                                                       <gml:Polygon></span><br><span style="color: hsl(120, 100%, 40%);">+                                                           <gml:exterior></span><br><span style="color: hsl(120, 100%, 40%);">+                                                                  <gml:LinearRing></span><br><span style="color: hsl(120, 100%, 40%);">+                                                                                <gml:posList></span><br><span style="color: hsl(120, 100%, 40%);">+                                                                                   42.556844 -73.248157 36.6 <!--A --></span><br><span style="color: hsl(120, 100%, 40%);">+                                                                                     42.656844 -73.248157 36.6 <!--B --></span><br><span style="color: hsl(120, 100%, 40%);">+                                                                                     42.656844 -73.348157 36.6 <!--C --></span><br><span style="color: hsl(120, 100%, 40%);">+                                                                                     42.556844 -73.348157 36.6 <!--D --></span><br><span style="color: hsl(120, 100%, 40%);">+                                                                                     42.556844 -73.248157 36.6 <!--A --></span><br><span style="color: hsl(120, 100%, 40%);">+                                                                             </gml:posList></span><br><span style="color: hsl(120, 100%, 40%);">+                                                                  </gml:LinearRing></span><br><span style="color: hsl(120, 100%, 40%);">+                                                               </gml:exterior></span><br><span style="color: hsl(120, 100%, 40%);">+                                                 </gml:Polygon></span><br><span style="color: hsl(120, 100%, 40%);">+                                          </gs:base></span><br><span style="color: hsl(120, 100%, 40%);">+                                              <gs:height uom="urn:ogc:def:uom:EPSG::9001">2.4</gs:height></span><br><span style="color: hsl(120, 100%, 40%);">+                                     </gs:Prism></span><br><span style="color: hsl(120, 100%, 40%);">+                             </gp:location-info></span><br><span style="color: hsl(120, 100%, 40%);">+                             <gp:usage-rules/></span><br><span style="color: hsl(120, 100%, 40%);">+                               <gp:method>Wiremap</gp:method></span><br><span style="color: hsl(120, 100%, 40%);">+                    </gp:geopriv></span><br><span style="color: hsl(120, 100%, 40%);">+           </status></span><br><span style="color: hsl(120, 100%, 40%);">+               <timestamp>2007-06-22T20:57:29Z</timestamp></span><br><span style="color: hsl(120, 100%, 40%);">+       </tuple></span><br><span style="color: hsl(120, 100%, 40%);">+        <dm:device></span><br><span style="color: hsl(120, 100%, 40%);">+             <gp:geopriv></span><br><span style="color: hsl(120, 100%, 40%);">+                    <gp:location-info></span><br><span style="color: hsl(120, 100%, 40%);">+                              <ca:civicAddress xml:lang="en-AU"></span><br><span style="color: hsl(120, 100%, 40%);">+                                    <ca:country>AU</ca:country></span><br><span style="color: hsl(120, 100%, 40%);">+                                       <ca:A1>NSW</ca:A1></span><br><span style="color: hsl(120, 100%, 40%);">+                                        <ca:A3>Wollongong</ca:A3></span><br><span style="color: hsl(120, 100%, 40%);">+                                 <ca:A4>North Wollongong</ca:A4></span><br><span style="color: hsl(120, 100%, 40%);">+                                   <ca:RD>Flinders</ca:RD></span><br><span style="color: hsl(120, 100%, 40%);">+                                   <ca:STS>Street</ca:STS></span><br><span style="color: hsl(120, 100%, 40%);">+                                   <ca:RDBR>Campbell Street</ca:RDBR></span><br><span style="color: hsl(120, 100%, 40%);">+                                        <ca:LMK>Gilligan's Island</ca:LMK></span><br><span style="color: hsl(120, 100%, 40%);">+                                    <ca:LOC>Corner</ca:LOC></span><br><span style="color: hsl(120, 100%, 40%);">+                                   <ca:NAM> Video Rental Store </ca:NAM></span><br><span style="color: hsl(120, 100%, 40%);">+                                     <ca:PC>2500</ca:PC></span><br><span style="color: hsl(120, 100%, 40%);">+                                       <ca:ROOM> Westerns and Classics </ca:ROOM></span><br><span style="color: hsl(120, 100%, 40%);">+                                        <ca:PLC>store</ca:PLC></span><br><span style="color: hsl(120, 100%, 40%);">+                                    <ca:POBOX>Private Box 15</ca:POBOX></span><br><span style="color: hsl(120, 100%, 40%);">+                               </ca:civicAddress></span><br><span style="color: hsl(120, 100%, 40%);">+                      </gp:location-info></span><br><span style="color: hsl(120, 100%, 40%);">+                     <gp:usage-rules></span><br><span style="color: hsl(120, 100%, 40%);">+                                <gp:retransmission-allowed>yes</gp:retransmission-allowed></span><br><span style="color: hsl(120, 100%, 40%);">+                                <gp:ruleset-preference>https:/www/more.com</gp:ruleset-preference></span><br><span style="color: hsl(120, 100%, 40%);">+                                <gp:retention-expires>2007-06-22T20:57:29Z</gp:retention-expires></span><br><span style="color: hsl(120, 100%, 40%);">+                 </gp:usage-rules></span><br><span style="color: hsl(120, 100%, 40%);">+                       <gp:method>GPS</gp:method></span><br><span style="color: hsl(120, 100%, 40%);">+                </gp:geopriv></span><br><span style="color: hsl(120, 100%, 40%);">+           <dm:deviceID>mac:1234567890ab</dm:deviceID></span><br><span style="color: hsl(120, 100%, 40%);">+               <dm:timestamp>2007-06-22T20:57:29Z</dm:timestamp></span><br><span style="color: hsl(120, 100%, 40%);">+ </dm:device></span><br><span style="color: hsl(120, 100%, 40%);">+</presence></span><br><span>diff --git a/res/res_geolocation/pidf_to_eprofile.xslt b/res/res_geolocation/pidf_to_eprofile.xslt</span><br><span>new file mode 100644</span><br><span>index 0000000..05f4df8</span><br><span>--- /dev/null</span><br><span>+++ b/res/res_geolocation/pidf_to_eprofile.xslt</span><br><span>@@ -0,0 +1,212 @@</span><br><span style="color: hsl(120, 100%, 40%);">+<?xml version="1.0"?></span><br><span style="color: hsl(120, 100%, 40%);">+<xsl:stylesheet version="1.0"</span><br><span style="color: hsl(120, 100%, 40%);">+   xmlns:ca="urn:ietf:params:xml:ns:pidf:geopriv10:civicAddr"</span><br><span style="color: hsl(120, 100%, 40%);">+  xmlns:def="urn:ietf:params:xml:ns:pidf"</span><br><span style="color: hsl(120, 100%, 40%);">+     xmlns:dm="urn:ietf:params:xml:ns:pidf:data-model"</span><br><span style="color: hsl(120, 100%, 40%);">+   xmlns:fn="http://www.w3.org/2005/xpath-functions"</span><br><span style="color: hsl(120, 100%, 40%);">+   xmlns:gbp="urn:ietf:params:xml:ns:pidf:geopriv10:basicPolicy"</span><br><span style="color: hsl(120, 100%, 40%);">+       xmlns:gml="http://www.opengis.net/gml"</span><br><span style="color: hsl(120, 100%, 40%);">+      xmlns:gp="urn:ietf:params:xml:ns:pidf:geopriv10"</span><br><span style="color: hsl(120, 100%, 40%);">+    xmlns:gs="http://www.opengis.net/pidflo/1.0"</span><br><span style="color: hsl(120, 100%, 40%);">+        xmlns:xsl="http://www.w3.org/1999/XSL/Transform"></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+<!--</span><br><span style="color: hsl(120, 100%, 40%);">+   The whole purpose of this stylesheet is to convert a PIDF-LO document into a simple,</span><br><span style="color: hsl(120, 100%, 40%);">+  common XML document that is easily parsable by geoloc_eprofile into an eprofile.</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    For example:</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        <presence></span><br><span style="color: hsl(120, 100%, 40%);">+              <device></span><br><span style="color: hsl(120, 100%, 40%);">+                        <location-info format="GML">shape="Point", crs="2d", pos="38.456 -105.678"</location-info></span><br><span style="color: hsl(120, 100%, 40%);">+                        <usage-rules>retransmission-allowed=no</usage-rules></span><br><span style="color: hsl(120, 100%, 40%);">+                      <method>GPS</method></span><br><span style="color: hsl(120, 100%, 40%);">+              </device></span><br><span style="color: hsl(120, 100%, 40%);">+       </presence></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   WARNING:  Don't mess with this stylesheet before brushing up your</span><br><span style="color: hsl(120, 100%, 40%);">+ XPath and XSLT expertise.</span><br><span style="color: hsl(120, 100%, 40%);">+--></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+<!--</span><br><span style="color: hsl(120, 100%, 40%);">+        All of the namespaces that could be in the incoming PIDF-LO document</span><br><span style="color: hsl(120, 100%, 40%);">+  have to be declared above.  All matching is done based on the URI, not</span><br><span style="color: hsl(120, 100%, 40%);">+        the prefix so we can use whatever prefixes we want.  For instance,</span><br><span style="color: hsl(120, 100%, 40%);">+    even if "urn:ietf:params:xml:ns:pidf:data-model" were declared with</span><br><span style="color: hsl(120, 100%, 40%);">+ the "pdm" prefix in the incoming document and with "dm" here,</span><br><span style="color: hsl(120, 100%, 40%);">+     "dm:device" would match "pdm:device" in the document.</span><br><span style="color: hsl(120, 100%, 40%);">+--></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   <xsl:output method="xml" indent="yes"/></span><br><span style="color: hsl(120, 100%, 40%);">+     <xsl:strip-space elements="*"/></span><br><span style="color: hsl(120, 100%, 40%);">+       <xsl:param name="path"/></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    <!--</span><br><span style="color: hsl(120, 100%, 40%);">+               Even though the "presence", "tuple", and "status" elements won't have namespaces in the</span><br><span style="color: hsl(120, 100%, 40%);">+             incoming PIDF document, we have to use the pseudo-namespace "def" here because of namespace</span><br><span style="color: hsl(120, 100%, 40%);">+         processing quirks in libxml2 and libxslt.</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+           We don't use namespace prefixes in the output document at all.</span><br><span style="color: hsl(120, 100%, 40%);">+    --></span><br><span style="color: hsl(120, 100%, 40%);">+        <xsl:template match="/def:presence"></span><br><span style="color: hsl(120, 100%, 40%);">+          <xsl:element name="presence"></span><br><span style="color: hsl(120, 100%, 40%);">+                 <xsl:attribute name="entity"><xsl:value-of select="@entity"/></xsl:attribute></span><br><span style="color: hsl(120, 100%, 40%);">+                   <xsl:apply-templates select="$path"/></span><br><span style="color: hsl(120, 100%, 40%);">+         </xsl:element></span><br><span style="color: hsl(120, 100%, 40%);">+  </xsl:template></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       <xsl:template match="dm:device"></span><br><span style="color: hsl(120, 100%, 40%);">+              <xsl:element name="device"></span><br><span style="color: hsl(120, 100%, 40%);">+                   <xsl:attribute name="id"><xsl:value-of select="@id"/></xsl:attribute></span><br><span style="color: hsl(120, 100%, 40%);">+                   <xsl:apply-templates select=".//gp:location-info"/></span><br><span style="color: hsl(120, 100%, 40%);">+                   <xsl:apply-templates select=".//gp:usage-rules"/></span><br><span style="color: hsl(120, 100%, 40%);">+                     <xsl:apply-templates select=".//gp:method"/></span><br><span style="color: hsl(120, 100%, 40%);">+                  <xsl:apply-templates select=".//gp:note-well"/></span><br><span style="color: hsl(120, 100%, 40%);">+                       <xsl:if test="./dm:timestamp"></span><br><span style="color: hsl(120, 100%, 40%);">+                                <timestamp></span><br><span style="color: hsl(120, 100%, 40%);">+                                     <xsl:value-of select="./dm:timestamp"/></span><br><span style="color: hsl(120, 100%, 40%);">+                               </timestamp></span><br><span style="color: hsl(120, 100%, 40%);">+                    </xsl:if></span><br><span style="color: hsl(120, 100%, 40%);">+                       <xsl:if test="./dm:deviceID"></span><br><span style="color: hsl(120, 100%, 40%);">+                         <deviceID></span><br><span style="color: hsl(120, 100%, 40%);">+                                      <xsl:value-of select="./dm:deviceID"/></span><br><span style="color: hsl(120, 100%, 40%);">+                                </deviceID></span><br><span style="color: hsl(120, 100%, 40%);">+                     </xsl:if></span><br><span style="color: hsl(120, 100%, 40%);">+               </xsl:element></span><br><span style="color: hsl(120, 100%, 40%);">+  </xsl:template></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       <xsl:template match="def:tuple"></span><br><span style="color: hsl(120, 100%, 40%);">+              <xsl:element name="tuple"></span><br><span style="color: hsl(120, 100%, 40%);">+                    <xsl:attribute name="id"><xsl:value-of select="@id"/></xsl:attribute></span><br><span style="color: hsl(120, 100%, 40%);">+                   <xsl:apply-templates select=".//gp:location-info"/></span><br><span style="color: hsl(120, 100%, 40%);">+                   <xsl:apply-templates select=".//gp:usage-rules"/></span><br><span style="color: hsl(120, 100%, 40%);">+                     <xsl:apply-templates select=".//gp:method"/></span><br><span style="color: hsl(120, 100%, 40%);">+                  <xsl:apply-templates select=".//gp:note-well"/></span><br><span style="color: hsl(120, 100%, 40%);">+                       <xsl:if test="./timestamp"></span><br><span style="color: hsl(120, 100%, 40%);">+                           <timestamp></span><br><span style="color: hsl(120, 100%, 40%);">+                                     <xsl:value-of select="./timestamp"/></span><br><span style="color: hsl(120, 100%, 40%);">+                          </timestamp></span><br><span style="color: hsl(120, 100%, 40%);">+                    </xsl:if></span><br><span style="color: hsl(120, 100%, 40%);">+               </xsl:element></span><br><span style="color: hsl(120, 100%, 40%);">+  </xsl:template></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       <xsl:template match="dm:person"></span><br><span style="color: hsl(120, 100%, 40%);">+              <xsl:element name="person"></span><br><span style="color: hsl(120, 100%, 40%);">+                   <xsl:attribute name="id"><xsl:value-of select="@id"/></xsl:attribute></span><br><span style="color: hsl(120, 100%, 40%);">+                   <xsl:apply-templates select=".//gp:location-info"/></span><br><span style="color: hsl(120, 100%, 40%);">+                   <xsl:apply-templates select=".//gp:usage-rules"/></span><br><span style="color: hsl(120, 100%, 40%);">+                     <xsl:apply-templates select=".//gp:method"/></span><br><span style="color: hsl(120, 100%, 40%);">+                  <xsl:apply-templates select=".//gp:note-well"/></span><br><span style="color: hsl(120, 100%, 40%);">+                       <xsl:if test="./dm:timestamp"></span><br><span style="color: hsl(120, 100%, 40%);">+                                <timestamp></span><br><span style="color: hsl(120, 100%, 40%);">+                                     <xsl:value-of select="./dm:timestamp"/></span><br><span style="color: hsl(120, 100%, 40%);">+                               </timestamp></span><br><span style="color: hsl(120, 100%, 40%);">+                    </xsl:if></span><br><span style="color: hsl(120, 100%, 40%);">+               </xsl:element></span><br><span style="color: hsl(120, 100%, 40%);">+  </xsl:template></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       <xsl:template match="gp:location-info/gml:*"></span><br><span style="color: hsl(120, 100%, 40%);">+         <xsl:element name="location-info"></span><br><span style="color: hsl(120, 100%, 40%);">+                    <xsl:attribute name="format">gml</xsl:attribute></span><br><span style="color: hsl(120, 100%, 40%);">+                        <xsl:call-template name="shape" /></span><br><span style="color: hsl(120, 100%, 40%);">+            </xsl:element></span><br><span style="color: hsl(120, 100%, 40%);">+  </xsl:template></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       <xsl:template match="gp:location-info/gs:*"></span><br><span style="color: hsl(120, 100%, 40%);">+          <xsl:element name="location-info"></span><br><span style="color: hsl(120, 100%, 40%);">+                    <xsl:attribute name="format">gml</xsl:attribute></span><br><span style="color: hsl(120, 100%, 40%);">+                        <xsl:call-template name="shape" /></span><br><span style="color: hsl(120, 100%, 40%);">+            </xsl:element></span><br><span style="color: hsl(120, 100%, 40%);">+  </xsl:template></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       <xsl:template match="gp:location-info/ca:civicAddress"></span><br><span style="color: hsl(120, 100%, 40%);">+               <xsl:element name="location-info"></span><br><span style="color: hsl(120, 100%, 40%);">+                    <xsl:attribute name="format">civicAddress</xsl:attribute></span><br><span style="color: hsl(120, 100%, 40%);">+                       <xsl:call-template name="civicAddress" /></span><br><span style="color: hsl(120, 100%, 40%);">+             </xsl:element></span><br><span style="color: hsl(120, 100%, 40%);">+  </xsl:template></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       <!--</span><br><span style="color: hsl(120, 100%, 40%);">+               All of the "following-sibling" things just stick a comma after the value if there's another</span><br><span style="color: hsl(120, 100%, 40%);">+             element after it.  The result should be...</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+          name1="value1", name2="value2"</span><br><span style="color: hsl(120, 100%, 40%);">+    --></span><br><span style="color: hsl(120, 100%, 40%);">+        <xsl:template name="name-value"></span><br><span style="color: hsl(120, 100%, 40%);">+              <xsl:element name="{local-name(.)}"></span><br><span style="color: hsl(120, 100%, 40%);">+                  <xsl:value-of select="normalize-space(.)"/></span><br><span style="color: hsl(120, 100%, 40%);">+           </xsl:element></span><br><span style="color: hsl(120, 100%, 40%);">+  </xsl:template></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       <xsl:template name="length"><xsl:call-template name="name-value" /></xsl:template></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    <xsl:template name="angle"></span><br><span style="color: hsl(120, 100%, 40%);">+           <xsl:element name="{local-name(.)}"></span><br><span style="color: hsl(120, 100%, 40%);">+                  <xsl:choose></span><br><span style="color: hsl(120, 100%, 40%);">+                            <xsl:when test="@uom = 'urn:ogc:def:uom:EPSG::9102'"></span><br><span style="color: hsl(120, 100%, 40%);">+                                 <xsl:attribute name="uom">radians</xsl:attribute></xsl:when></span><br><span style="color: hsl(120, 100%, 40%);">+                              <xsl:otherwise></span><br><span style="color: hsl(120, 100%, 40%);">+                                 <xsl:attribute name="uom">degrees</xsl:attribute></xsl:otherwise></span><br><span style="color: hsl(120, 100%, 40%);">+                 </xsl:choose></span><br><span style="color: hsl(120, 100%, 40%);">+                   <xsl:value-of select="normalize-space(.)"/></span><br><span style="color: hsl(120, 100%, 40%);">+           </xsl:element></span><br><span style="color: hsl(120, 100%, 40%);">+  </xsl:template></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       <xsl:template match="gs:orientation"><xsl:call-template name="angle" /></xsl:template></span><br><span style="color: hsl(120, 100%, 40%);">+  <xsl:template match="gs:radius"><xsl:call-template name="length" /></xsl:template></span><br><span style="color: hsl(120, 100%, 40%);">+      <xsl:template match="gs:height"><xsl:call-template name="length" /></xsl:template></span><br><span style="color: hsl(120, 100%, 40%);">+      <xsl:template match="gs:semiMajorAxis"><xsl:call-template name="length" /></xsl:template></span><br><span style="color: hsl(120, 100%, 40%);">+       <xsl:template match="gs:semiMinorAxis"><xsl:call-template name="length" /></xsl:template></span><br><span style="color: hsl(120, 100%, 40%);">+       <xsl:template match="gs:verticalAxis"><xsl:call-template name="length" /></xsl:template></span><br><span style="color: hsl(120, 100%, 40%);">+        <xsl:template match="gs:innerRadius"><xsl:call-template name="length" /></xsl:template></span><br><span style="color: hsl(120, 100%, 40%);">+ <xsl:template match="gs:outerRadius"><xsl:call-template name="length" /></xsl:template></span><br><span style="color: hsl(120, 100%, 40%);">+ <xsl:template match="gs:startAngle"><xsl:call-template name="angle" /></xsl:template></span><br><span style="color: hsl(120, 100%, 40%);">+   <xsl:template match="gs:openingAngle"><xsl:call-template name="angle" /></xsl:template></span><br><span style="color: hsl(120, 100%, 40%);">+ <xsl:template match="gml:pos"><xsl:call-template name="name-value" /></xsl:template></span><br><span style="color: hsl(120, 100%, 40%);">+    <xsl:template match="gml:posList"><xsl:call-template name="name-value" /></xsl:template></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      <xsl:template name="shape"></span><br><span style="color: hsl(120, 100%, 40%);">+           <xsl:element name="{local-name(.)}"></span><br><span style="color: hsl(120, 100%, 40%);">+                  <xsl:choose></span><br><span style="color: hsl(120, 100%, 40%);">+                    <xsl:when test="@srsName = 'urn:ogc:def:crs:EPSG::4326'"></span><br><span style="color: hsl(120, 100%, 40%);">+                             <xsl:attribute name="srsName">2d</xsl:attribute></span><br><span style="color: hsl(120, 100%, 40%);">+                        </xsl:when></span><br><span style="color: hsl(120, 100%, 40%);">+                     <xsl:when test="@srsName = 'urn:ogc:def:crs:EPSG::4979'"></span><br><span style="color: hsl(120, 100%, 40%);">+                             <xsl:attribute name="srsName">3d</xsl:attribute></span><br><span style="color: hsl(120, 100%, 40%);">+                        </xsl:when></span><br><span style="color: hsl(120, 100%, 40%);">+                     <xsl:otherwise></span><br><span style="color: hsl(120, 100%, 40%);">+                         <xsl:attribute name="srsName">unknown</xsl:attribute></span><br><span style="color: hsl(120, 100%, 40%);">+                   </xsl:otherwise></span><br><span style="color: hsl(120, 100%, 40%);">+                        </xsl:choose></span><br><span style="color: hsl(120, 100%, 40%);">+                   <xsl:apply-templates /></span><br><span style="color: hsl(120, 100%, 40%);">+         </xsl:element></span><br><span style="color: hsl(120, 100%, 40%);">+  </xsl:template></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       <xsl:template match="ca:civicAddress/*"><xsl:call-template name="name-value" /></xsl:template></span><br><span style="color: hsl(120, 100%, 40%);">+  <xsl:template name="civicAddress"></span><br><span style="color: hsl(120, 100%, 40%);">+            <xsl:element name="{local-name(.)}"></span><br><span style="color: hsl(120, 100%, 40%);">+                  <xsl:attribute name="lang"><xsl:value-of select="@xml:lang"/></xsl:attribute></span><br><span style="color: hsl(120, 100%, 40%);">+                   <xsl:apply-templates select="./*"/></span><br><span style="color: hsl(120, 100%, 40%);">+           </xsl:element></span><br><span style="color: hsl(120, 100%, 40%);">+  </xsl:template></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       <xsl:template match="gp:usage-rules/*"></span><br><span style="color: hsl(120, 100%, 40%);">+               <xsl:call-template name="name-value" /></span><br><span style="color: hsl(120, 100%, 40%);">+       </xsl:template></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       <xsl:template match="gp:usage-rules"></span><br><span style="color: hsl(120, 100%, 40%);">+         <xsl:element name="usage-rules"></span><br><span style="color: hsl(120, 100%, 40%);">+                      <xsl:apply-templates /></span><br><span style="color: hsl(120, 100%, 40%);">+         </xsl:element></span><br><span style="color: hsl(120, 100%, 40%);">+  </xsl:template></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       <xsl:template match="gp:method"></span><br><span style="color: hsl(120, 100%, 40%);">+              <xsl:element name="method"></span><br><span style="color: hsl(120, 100%, 40%);">+           <xsl:value-of select="normalize-space(.)" /></span><br><span style="color: hsl(120, 100%, 40%);">+          </xsl:element></span><br><span style="color: hsl(120, 100%, 40%);">+  </xsl:template></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+</xsl:stylesheet></span><br><span></span><br></pre><div style="white-space:pre-wrap"></div><p>To view, visit <a href="https://gerrit.asterisk.org/c/asterisk/+/18783">change 18783</a>. To unsubscribe, or for help writing mail filters, visit <a href="https://gerrit.asterisk.org/settings">settings</a>.</p><div itemscope itemtype="http://schema.org/EmailMessage"><div itemscope itemprop="action" itemtype="http://schema.org/ViewAction"><link itemprop="url" href="https://gerrit.asterisk.org/c/asterisk/+/18783"/><meta itemprop="name" content="View Change"/></div></div>

<div style="display:none"> Gerrit-Project: asterisk </div>
<div style="display:none"> Gerrit-Branch: 18 </div>
<div style="display:none"> Gerrit-Change-Id: Ibfde963121b1ecf57fd98ee7060c4f0808416303 </div>
<div style="display:none"> Gerrit-Change-Number: 18783 </div>
<div style="display:none"> Gerrit-PatchSet: 2 </div>
<div style="display:none"> Gerrit-Owner: George Joseph <gjoseph@digium.com> </div>
<div style="display:none"> Gerrit-Reviewer: Friendly Automation </div>
<div style="display:none"> Gerrit-Reviewer: George Joseph <gjoseph@digium.com> </div>
<div style="display:none"> Gerrit-Reviewer: Kevin Harwell <kharwell@digium.com> </div>
<div style="display:none"> Gerrit-MessageType: merged </div>