<p>George Joseph has uploaded this change for <strong>review</strong>.</p><p><a href="https://gerrit.asterisk.org/c/asterisk/+/18251">View Change</a></p><pre style="font-family: monospace,monospace; white-space: pre-wrap;">res_pjsip_geolocation: Outbound Support<br><br>Primarily added the processing to convert eprofiles received<br>from the core to actual PIDF-LO XML documents and attach<br>them to outgoing SIP messages.<br><br>Along the way, additional tweaks needed to be made to core<br>XML and config capabilities as well as core res_geolocation<br>stuff.<br><br>Change-Id: Iccb956dd1800204472a21714d06d3b28486e9490<br>---<br>M include/asterisk/pbx.h<br>M include/asterisk/res_geolocation.h<br>M include/asterisk/res_pjsip.h<br>M include/asterisk/xml.h<br>M main/pbx_variables.c<br>M main/xml.c<br>M res/Makefile<br>A res/res_geolocation/eprofile_to_pidf.xslt<br>M res/res_geolocation/geoloc_civicaddr.c<br>M res/res_geolocation/geoloc_config.c<br>M res/res_geolocation/geoloc_datastore.c<br>M res/res_geolocation/geoloc_doc.xml<br>M res/res_geolocation/geoloc_eprofile.c<br>M res/res_geolocation/geoloc_gml.c<br>M res/res_geolocation/geoloc_private.h<br>M res/res_geolocation/pidf_to_eprofile.xslt<br>M res/res_pjsip.c<br>M res/res_pjsip_geolocation.c<br>18 files changed, 1,575 insertions(+), 177 deletions(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;">git pull ssh://gerrit.asterisk.org:29418/asterisk refs/changes/51/18251/1</pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;"><span>diff --git a/include/asterisk/pbx.h b/include/asterisk/pbx.h</span><br><span>index f5f0691..c905a4c 100644</span><br><span>--- a/include/asterisk/pbx.h</span><br><span>+++ b/include/asterisk/pbx.h</span><br><span>@@ -1455,6 +1455,28 @@</span><br><span>  * \param used Number of bytes read from the template.  (May be NULL)</span><br><span>  */</span><br><span> void ast_str_substitute_variables_full(struct ast_str **buf, ssize_t maxlen, struct ast_channel *c, struct varshead *headp, const char *templ, size_t *used);</span><br><span 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 Perform variable/function/expression substitution on an ast_str</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param buf      Result will be placed in this buffer.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param maxlen   -1 if the buffer should not grow, 0 if the buffer</span><br><span style="color: hsl(120, 100%, 40%);">+ *                 may grow to any size, and >0 if the buffer should</span><br><span style="color: hsl(120, 100%, 40%);">+ *                 grow only to that number of bytes.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param c        A channel from which to extract values, and to pass</span><br><span style="color: hsl(120, 100%, 40%);">+ *                 to any dialplan functions.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param headp    A channel variables list to also search for variables.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param templ    Variable template to expand.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param used     Number of bytes read from the template.  (May be NULL)</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param use_both Normally, if a channel is specified, headp is ignored.</span><br><span style="color: hsl(120, 100%, 40%);">+ *                 If this parameter is set to 1 and both a channel and headp</span><br><span style="color: hsl(120, 100%, 40%);">+ *                 are specified, the channel will be searched for variables</span><br><span style="color: hsl(120, 100%, 40%);">+ *                 first and any not found will be searched for in headp.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+void ast_str_substitute_variables_full2(struct ast_str **buf, ssize_t maxlen,</span><br><span style="color: hsl(120, 100%, 40%);">+     struct ast_channel *c, struct varshead *headp, const char *templ,</span><br><span style="color: hsl(120, 100%, 40%);">+     size_t *used, int use_both);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> /*! @} */</span><br><span> </span><br><span> int ast_extension_patmatch(const char *pattern, const char *data);</span><br><span>diff --git a/include/asterisk/res_geolocation.h b/include/asterisk/res_geolocation.h</span><br><span>index 9b8b188..cfe81fb 100644</span><br><span>--- a/include/asterisk/res_geolocation.h</span><br><span>+++ b/include/asterisk/res_geolocation.h</span><br><span>@@ -19,8 +19,9 @@</span><br><span> #ifndef INCLUDE_ASTERISK_RES_GEOLOCATION_H_</span><br><span> #define INCLUDE_ASTERISK_RES_GEOLOCATION_H_</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-#include "asterisk/sorcery.h"</span><br><span style="color: hsl(120, 100%, 40%);">+#include "asterisk/channel.h"</span><br><span> #include "asterisk/config.h"</span><br><span style="color: hsl(120, 100%, 40%);">+#include "asterisk/sorcery.h"</span><br><span> #include "asterisk/xml.h"</span><br><span> #include "asterisk/optional_api.h"</span><br><span> </span><br><span>@@ -30,7 +31,8 @@</span><br><span>   AST_PIDF_ELEMENT_NONE = 0,</span><br><span>   AST_PIDF_ELEMENT_TUPLE,</span><br><span>      AST_PIDF_ELEMENT_DEVICE,</span><br><span style="color: hsl(0, 100%, 40%);">-        AST_PIDF_ELEMENT_PERSON</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> };</span><br><span> </span><br><span> enum ast_geoloc_format {</span><br><span>@@ -38,6 +40,7 @@</span><br><span>     AST_GEOLOC_FORMAT_CIVIC_ADDRESS,</span><br><span>     AST_GEOLOC_FORMAT_GML,</span><br><span>       AST_GEOLOC_FORMAT_URI,</span><br><span style="color: hsl(120, 100%, 40%);">+        AST_GEOLOC_FORMAT_LAST,</span><br><span> };</span><br><span> </span><br><span> enum ast_geoloc_action {</span><br><span>@@ -45,12 +48,14 @@</span><br><span>  AST_GEOLOC_ACTION_APPEND,</span><br><span>    AST_GEOLOC_ACTION_PREPEND,</span><br><span>   AST_GEOLOC_ACTION_REPLACE,</span><br><span style="color: hsl(120, 100%, 40%);">+    AST_GEOLOC_ACTION_LAST,</span><br><span> };</span><br><span> </span><br><span> struct ast_geoloc_location {</span><br><span>    SORCERY_OBJECT(details);</span><br><span>     AST_DECLARE_STRING_FIELDS(</span><br><span>           AST_STRING_FIELD(method);</span><br><span style="color: hsl(120, 100%, 40%);">+             AST_STRING_FIELD(location_source);</span><br><span>   );</span><br><span>   enum ast_geoloc_format format;</span><br><span>       struct ast_variable *location_info;</span><br><span>@@ -60,6 +65,7 @@</span><br><span>      SORCERY_OBJECT(details);</span><br><span>     AST_DECLARE_STRING_FIELDS(</span><br><span>           AST_STRING_FIELD(location_reference);</span><br><span style="color: hsl(120, 100%, 40%);">+         AST_STRING_FIELD(notes);</span><br><span>     );</span><br><span>   enum ast_geoloc_pidf_element pidf_element;</span><br><span>   enum ast_geoloc_action action;</span><br><span>@@ -74,7 +80,9 @@</span><br><span>   AST_DECLARE_STRING_FIELDS(</span><br><span>           AST_STRING_FIELD(id);</span><br><span>                AST_STRING_FIELD(location_reference);</span><br><span style="color: hsl(120, 100%, 40%);">+         AST_STRING_FIELD(location_source);</span><br><span>           AST_STRING_FIELD(method);</span><br><span style="color: hsl(120, 100%, 40%);">+             AST_STRING_FIELD(notes);</span><br><span>     );</span><br><span>   enum ast_geoloc_pidf_element pidf_element;</span><br><span>   enum ast_geoloc_action action;</span><br><span>@@ -147,8 +155,8 @@</span><br><span> enum ast_geoloc_validate_result {</span><br><span>    AST_GEOLOC_VALIDATE_INVALID_VALUE = -1,</span><br><span>      AST_GEOLOC_VALIDATE_SUCCESS = 0,</span><br><span style="color: hsl(0, 100%, 40%);">-        AST_GEOLOC_VALIDATE_MISSING_TYPE,</span><br><span style="color: hsl(0, 100%, 40%);">-       AST_GEOLOC_VALIDATE_INVALID_TYPE,</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>   AST_GEOLOC_VALIDATE_INVALID_VARNAME,</span><br><span>         AST_GEOLOC_VALIDATE_NOT_ENOUGH_VARNAMES,</span><br><span>     AST_GEOLOC_VALIDATE_TOO_MANY_VARNAMES,</span><br><span>@@ -325,12 +333,13 @@</span><br><span>  * \brief Allocate a new effective profile from an XML PIDF-LO document</span><br><span>  *</span><br><span>  * \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>  * \param reference_string  An identifying string to use in error messages.</span><br><span>  *</span><br><span>  * \return The effective profile ao2 object.</span><br><span>  */</span><br><span> struct ast_geoloc_eprofile *ast_geoloc_eprofile_create_from_pidf(</span><br><span style="color: hsl(0, 100%, 40%);">-     struct ast_xml_doc *pidf_xmldoc, const char *reference_string);</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> </span><br><span> /*!</span><br><span>  * \brief Allocate a new effective profile from a URI.</span><br><span>@@ -343,6 +352,12 @@</span><br><span> struct ast_geoloc_eprofile *ast_geoloc_eprofile_create_from_uri(const char *uri,</span><br><span>      const char *reference_string);</span><br><span> </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> /*!</span><br><span>  * \brief Refresh the effective profile with any changed info.</span><br><span>  *</span><br><span>diff --git a/include/asterisk/res_pjsip.h b/include/asterisk/res_pjsip.h</span><br><span>index 40e13e2..6a705d7 100644</span><br><span>--- a/include/asterisk/res_pjsip.h</span><br><span>+++ b/include/asterisk/res_pjsip.h</span><br><span>@@ -2379,6 +2379,17 @@</span><br><span> int ast_sip_add_header(pjsip_tx_data *tdata, const char *name, const char *value);</span><br><span> </span><br><span> /*!</span><br><span style="color: hsl(120, 100%, 40%);">+ * \brief Add a header to an outbound SIP message, returning a pointer to the header</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param tdata The message to add the header to</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param name The header name</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param value The header value</span><br><span style="color: hsl(120, 100%, 40%);">+ * \return The pjsip_generic_string_hdr * added.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+pjsip_generic_string_hdr *ast_sip_add_header2(pjsip_tx_data *tdata,</span><br><span style="color: hsl(120, 100%, 40%);">+   const char *name, const char *value);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*!</span><br><span>  * \brief Add a body to an outbound SIP message</span><br><span>  *</span><br><span>  * If this is called multiple times, the latest body will replace the current</span><br><span>diff --git a/include/asterisk/xml.h b/include/asterisk/xml.h</span><br><span>index 5564051..c1b0797 100644</span><br><span>--- a/include/asterisk/xml.h</span><br><span>+++ b/include/asterisk/xml.h</span><br><span>@@ -261,6 +261,17 @@</span><br><span> int ast_xml_doc_dump_file(FILE *output, struct ast_xml_doc *doc);</span><br><span> </span><br><span> /*!</span><br><span style="color: hsl(120, 100%, 40%);">+ * \brief Dump the specified document to a buffer</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param doc The XML doc to dump</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param buffer A pointer to a char * to receive the address of the results</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param length A pointer to an int to receive the length of the results</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \note The result buffer must be freed with ast_xml_free_text().</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+void ast_xml_doc_dump_memory(struct ast_xml_doc *doc, char **buffer, int *length);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*!</span><br><span>  * \brief Free the XPath results</span><br><span>  * \param results The XPath results object to dispose of</span><br><span>  *</span><br><span>diff --git a/main/pbx_variables.c b/main/pbx_variables.c</span><br><span>index 6f7439f..48e499c 100644</span><br><span>--- a/main/pbx_variables.c</span><br><span>+++ b/main/pbx_variables.c</span><br><span>@@ -394,7 +394,9 @@</span><br><span>       return ret;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-void ast_str_substitute_variables_full(struct ast_str **buf, ssize_t maxlen, struct ast_channel *c, struct varshead *headp, const char *templ, size_t *used)</span><br><span style="color: hsl(120, 100%, 40%);">+void ast_str_substitute_variables_full2(struct ast_str **buf, ssize_t maxlen,</span><br><span style="color: hsl(120, 100%, 40%);">+       struct ast_channel *c, struct varshead *headp, const char *templ,</span><br><span style="color: hsl(120, 100%, 40%);">+     size_t *used, int use_both)</span><br><span> {</span><br><span>     /* Substitutes variables into buf, based on string templ */</span><br><span>  const char *whereweare;</span><br><span>@@ -501,7 +503,8 @@</span><br><span> </span><br><span>                    /* Store variable name expression to lookup. */</span><br><span>                      ast_str_set_substr(&substr1, 0, vars, len);</span><br><span style="color: hsl(0, 100%, 40%);">-                 ast_debug(5, "Evaluating '%s' (from '%s' len %d)\n", ast_str_buffer(substr1), vars, len);</span><br><span style="color: hsl(120, 100%, 40%);">+                   ast_debug(5, "Evaluating '%s' (from '%s' len %d)\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                                ast_str_buffer(substr1), vars, len);</span><br><span> </span><br><span>                     /* Substitute if necessary */</span><br><span>                        if (needsub) {</span><br><span>@@ -511,7 +514,8 @@</span><br><span>                                                 continue;</span><br><span>                                    }</span><br><span>                            }</span><br><span style="color: hsl(0, 100%, 40%);">-                               ast_str_substitute_variables_full(&substr2, 0, c, headp, ast_str_buffer(substr1), NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+                          ast_str_substitute_variables_full2(&substr2, 0, c, headp,</span><br><span style="color: hsl(120, 100%, 40%);">+                                 ast_str_buffer(substr1), NULL, use_both);</span><br><span>                            finalvars = ast_str_buffer(substr2);</span><br><span>                         } else {</span><br><span>                             finalvars = ast_str_buffer(substr1);</span><br><span>@@ -520,9 +524,13 @@</span><br><span>                  parse_variable_name(finalvars, &offset, &offset2, &isfunction);</span><br><span>                  if (isfunction) {</span><br><span>                            /* Evaluate function */</span><br><span style="color: hsl(0, 100%, 40%);">-                         if (c || !headp) {</span><br><span style="color: hsl(120, 100%, 40%);">+                            res = -1;</span><br><span style="color: hsl(120, 100%, 40%);">+                             if (c) {</span><br><span>                                     res = ast_func_read2(c, finalvars, &substr3, 0);</span><br><span style="color: hsl(0, 100%, 40%);">-                            } else {</span><br><span style="color: hsl(120, 100%, 40%);">+                                      ast_debug(2, "Function %s result is '%s' from channel\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                                           finalvars, res ? "" : ast_str_buffer(substr3));</span><br><span style="color: hsl(120, 100%, 40%);">+                             }</span><br><span style="color: hsl(120, 100%, 40%);">+                             if (headp && (!c || (c && res == -1 && use_both))) {</span><br><span>                                         struct varshead old;</span><br><span>                                         struct ast_channel *bogus;</span><br><span> </span><br><span>@@ -538,13 +546,22 @@</span><br><span>                                               ast_log(LOG_ERROR, "Unable to allocate bogus channel for function value substitution.\n");</span><br><span>                                                 res = -1;</span><br><span>                                    }</span><br><span style="color: hsl(120, 100%, 40%);">+                                     ast_debug(2, "Function %s result is '%s' from headp\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                                             finalvars, res ? "" : ast_str_buffer(substr3));</span><br><span>                            }</span><br><span style="color: hsl(0, 100%, 40%);">-                               ast_debug(2, "Function %s result is '%s'\n",</span><br><span style="color: hsl(0, 100%, 40%);">-                                  finalvars, res ? "" : ast_str_buffer(substr3));</span><br><span>                    } else {</span><br><span style="color: hsl(0, 100%, 40%);">-                                /* Retrieve variable value */</span><br><span style="color: hsl(0, 100%, 40%);">-                           ast_str_retrieve_variable(&substr3, 0, c, headp, finalvars);</span><br><span style="color: hsl(0, 100%, 40%);">-                                res = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+                              const char *result;</span><br><span style="color: hsl(120, 100%, 40%);">+                           if (c) {</span><br><span style="color: hsl(120, 100%, 40%);">+                                      result = ast_str_retrieve_variable(&substr3, 0, c, NULL, finalvars);</span><br><span style="color: hsl(120, 100%, 40%);">+                                      ast_debug(2, "Variable %s result is '%s' from channel\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                                           finalvars, S_OR(result, ""));</span><br><span style="color: hsl(120, 100%, 40%);">+                               }</span><br><span style="color: hsl(120, 100%, 40%);">+                             if (headp && (!c || (c && !result && use_both))) {</span><br><span style="color: hsl(120, 100%, 40%);">+                                    result = ast_str_retrieve_variable(&substr3, 0, NULL, headp, finalvars);</span><br><span style="color: hsl(120, 100%, 40%);">+                                  ast_debug(2, "Variable %s result is '%s' from headp\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                                             finalvars, S_OR(result, ""));</span><br><span style="color: hsl(120, 100%, 40%);">+                               }</span><br><span style="color: hsl(120, 100%, 40%);">+                             res = (result ? 0 : -1);</span><br><span>                     }</span><br><span>                    if (!res) {</span><br><span>                          ast_str_substring(substr3, offset, offset2);</span><br><span>@@ -596,7 +613,8 @@</span><br><span>                                           continue;</span><br><span>                                    }</span><br><span>                            }</span><br><span style="color: hsl(0, 100%, 40%);">-                               ast_str_substitute_variables_full(&substr2, 0, c, headp, ast_str_buffer(substr1), NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+                          ast_str_substitute_variables_full2(&substr2, 0, c, headp,</span><br><span style="color: hsl(120, 100%, 40%);">+                                 ast_str_buffer(substr1), NULL, use_both);</span><br><span>                            finalvars = ast_str_buffer(substr2);</span><br><span>                         } else {</span><br><span>                             finalvars = ast_str_buffer(substr1);</span><br><span>@@ -616,6 +634,12 @@</span><br><span>  ast_free(substr3);</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+void ast_str_substitute_variables_full(struct ast_str **buf, ssize_t maxlen,</span><br><span style="color: hsl(120, 100%, 40%);">+     struct ast_channel *chan, struct varshead *headp, const char *templ, size_t *used)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_str_substitute_variables_full2(buf, maxlen, chan, headp, templ, used, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> void ast_str_substitute_variables(struct ast_str **buf, ssize_t maxlen, struct ast_channel *chan, const char *templ)</span><br><span> {</span><br><span>      ast_str_substitute_variables_full(buf, maxlen, chan, NULL, templ, NULL);</span><br><span>diff --git a/main/xml.c b/main/xml.c</span><br><span>index 987f125..d244e4e 100644</span><br><span>--- a/main/xml.c</span><br><span>+++ b/main/xml.c</span><br><span>@@ -361,6 +361,11 @@</span><br><span>         return xmlDocDump(output, (xmlDocPtr)doc);</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+void ast_xml_doc_dump_memory(struct ast_xml_doc *doc, char **buffer, int *length)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+     xmlDocDumpFormatMemory((xmlDocPtr)doc, (xmlChar **)buffer, length, 1);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> const char *ast_xml_node_get_name(struct ast_xml_node *node)</span><br><span> {</span><br><span>     return (const char *) ((xmlNode *) node)->name;</span><br><span>diff --git a/res/Makefile b/res/Makefile</span><br><span>index 6abdd2d..b9d1b98 100644</span><br><span>--- a/res/Makefile</span><br><span>+++ b/res/Makefile</span><br><span>@@ -70,7 +70,7 @@</span><br><span> $(call MOD_ADD_C,res_geolocation,$(wildcard res_geolocation/*.c))</span><br><span> </span><br><span> # These are the xml and xslt files to be embedded</span><br><span style="color: hsl(0, 100%, 40%);">-res_geolocation.so: res_geolocation/pidf_lo_test.o res_geolocation/pidf_to_eprofile.o</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>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..c7a8888</span><br><span>--- /dev/null</span><br><span>+++ b/res/res_geolocation/eprofile_to_pidf.xslt</span><br><span>@@ -0,0 +1,238 @@</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%);">+       <!-- When we're using the GML format, things get more complex --></span><br><span style="color: hsl(120, 100%, 40%);">+   <xsl:template match="location-info/Point|Polygon|Circle|Ellipse|ArcBand|Sphere|Ellipsoid|Prism"></span><br><span style="color: hsl(120, 100%, 40%);">+              <xsl:apply-templates/></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"></span><br><span style="color: hsl(120, 100%, 40%);">+          <gml:Point></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%);">+           </gml:Point></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="Circle|Ellipse|ArcBand|Sphere|Ellipsoid"></span><br><span style="color: hsl(120, 100%, 40%);">+                <xsl:element name="gs:{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>index 6816ebd..9a114cd 100644</span><br><span>--- a/res/res_geolocation/geoloc_civicaddr.c</span><br><span>+++ b/res/res_geolocation/geoloc_civicaddr.c</span><br><span>@@ -20,6 +20,7 @@</span><br><span> #include "asterisk/config.h"</span><br><span> #include "asterisk/cli.h"</span><br><span> #include "asterisk/res_geolocation.h"</span><br><span style="color: hsl(120, 100%, 40%);">+#include "asterisk/xml.h"</span><br><span> #include "geoloc_private.h"</span><br><span> </span><br><span> struct addr_field_entry {</span><br><span>@@ -93,16 +94,16 @@</span><br><span>    struct addr_field_entry key = { .name = name };</span><br><span>      struct addr_field_entry *entry = bsearch(&key, addr_name_code_entries, ARRAY_LEN(addr_name_code_entries),</span><br><span>                sizeof(struct addr_field_entry), compare_civicaddr_names);</span><br><span style="color: hsl(0, 100%, 40%);">-      return entry ? entry->code : NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+ return entry ? entry->code : name;</span><br><span> }</span><br><span> </span><br><span> const char *ast_geoloc_civicaddr_resolve_variable(const char *variable)</span><br><span> {</span><br><span style="color: hsl(0, 100%, 40%);">-  const char *result = ast_geoloc_civicaddr_get_name_from_code(variable);</span><br><span style="color: hsl(120, 100%, 40%);">+       const char *result = ast_geoloc_civicaddr_get_code_from_name(variable);</span><br><span>      if (result) {</span><br><span>                return result;</span><br><span>       }</span><br><span style="color: hsl(0, 100%, 40%);">-       return ast_geoloc_civicaddr_get_code_from_name(variable);</span><br><span style="color: hsl(120, 100%, 40%);">+     return ast_geoloc_civicaddr_get_name_from_code(variable);</span><br><span> }</span><br><span> </span><br><span> enum ast_geoloc_validate_result ast_geoloc_civicaddr_validate_varlist(</span><br><span>@@ -149,6 +150,54 @@</span><br><span>  AST_CLI_DEFINE(handle_civicaddr_show, "Show the mappings between civicAddress official codes and synonyms"),</span><br><span> };</span><br><span> </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%);">+               const char *n;</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%);">+             n = ast_geoloc_civicaddr_get_code_from_name(var->name);</span><br><span style="color: hsl(120, 100%, 40%);">+            child_node = ast_xml_new_child(ca_node, n);</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", n, 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> int geoloc_civicaddr_unload(void)</span><br><span> {</span><br><span>    ast_cli_unregister_multiple(geoloc_civicaddr_cli, ARRAY_LEN(geoloc_civicaddr_cli));</span><br><span>diff --git a/res/res_geolocation/geoloc_config.c b/res/res_geolocation/geoloc_config.c</span><br><span>index 2350463..daefcdb 100644</span><br><span>--- a/res/res_geolocation/geoloc_config.c</span><br><span>+++ b/res/res_geolocation/geoloc_config.c</span><br><span>@@ -102,6 +102,7 @@</span><br><span> </span><br><span>       switch (location->format) {</span><br><span>       case AST_GEOLOC_FORMAT_NONE:</span><br><span style="color: hsl(120, 100%, 40%);">+  case AST_GEOLOC_FORMAT_LAST:</span><br><span>                 ast_log(LOG_ERROR, "Location '%s' must have a format\n", location_id);</span><br><span>             return -1;</span><br><span>   case AST_GEOLOC_FORMAT_CIVIC_ADDRESS:</span><br><span>@@ -134,6 +135,18 @@</span><br><span>                 break;</span><br><span>       }</span><br><span> </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>        return 0;</span><br><span> }</span><br><span> </span><br><span>@@ -165,6 +178,7 @@</span><br><span>     if (profile->location_refinement) {</span><br><span>               switch (location->format) {</span><br><span>               case AST_GEOLOC_FORMAT_NONE:</span><br><span style="color: hsl(120, 100%, 40%);">+          case AST_GEOLOC_FORMAT_LAST:</span><br><span>                         break;</span><br><span>               case AST_GEOLOC_FORMAT_CIVIC_ADDRESS:</span><br><span>                        result = ast_geoloc_civicaddr_validate_varlist(profile->location_refinement, &failed);</span><br><span>@@ -433,6 +447,7 @@</span><br><span>          struct ast_str *refinement_str = NULL;</span><br><span>               struct ast_str *variables_str = NULL;</span><br><span>                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>              struct ast_geoloc_eprofile *eprofile = ast_geoloc_eprofile_create_from_profile(profile);</span><br><span>             ao2_ref(profile, -1);</span><br><span> </span><br><span>@@ -443,20 +458,24 @@</span><br><span> </span><br><span>                refinement_str = ast_variable_list_join(eprofile->location_refinement, ",", "=", "\"", NULL);</span><br><span>          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> </span><br><span>             action_to_str(eprofile, NULL, &action);</span><br><span> </span><br><span>              ast_cli(a->fd,</span><br><span style="color: hsl(0, 100%, 40%);">-                       "id:                            %-s\n"</span><br><span style="color: hsl(0, 100%, 40%);">-                        "received_location_disposition: %-s\n"</span><br><span style="color: hsl(0, 100%, 40%);">-                        "send_location:                 %-s\n"</span><br><span style="color: hsl(0, 100%, 40%);">-                        "pidf_element:                  %-s\n"</span><br><span style="color: hsl(0, 100%, 40%);">-                        "location_reference:            %-s\n"</span><br><span style="color: hsl(0, 100%, 40%);">-                        "Location_format:               %-s\n"</span><br><span style="color: hsl(0, 100%, 40%);">-                        "location_reference_details:    %-s\n"</span><br><span style="color: hsl(0, 100%, 40%);">-                        "location_refinement:           %-s\n"</span><br><span style="color: hsl(0, 100%, 40%);">-                        "location_variables:            %-s\n"</span><br><span style="color: hsl(0, 100%, 40%);">-                        "effective_location:            %-s\n\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                   "id:                   %-s\n"</span><br><span style="color: hsl(120, 100%, 40%);">+                       "action:               %-s\n"</span><br><span style="color: hsl(120, 100%, 40%);">+                       "send_location:        %-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>                     eprofile->id,</span><br><span>                     action,</span><br><span>                      eprofile->send_location ? "yes" : "no",</span><br><span>@@ -464,9 +483,13 @@</span><br><span>                        S_OR(eprofile->location_reference, "<none>"),</span><br><span>                     format_names[eprofile->format],</span><br><span>                   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>                         S_COR(refinement_str, ast_str_buffer(refinement_str), "<none>"),</span><br><span>                     S_COR(variables_str, ast_str_buffer(variables_str), "<none>"),</span><br><span style="color: hsl(0, 100%, 40%);">-                  S_COR(resolved_str, ast_str_buffer(resolved_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>           ao2_ref(eprofile, -1);</span><br><span> </span><br><span>           ast_free(action);</span><br><span>@@ -474,6 +497,7 @@</span><br><span>              ast_free(refinement_str);</span><br><span>            ast_free(variables_str);</span><br><span>             ast_free(resolved_str);</span><br><span style="color: hsl(120, 100%, 40%);">+               ast_free(usage_rules_str);</span><br><span>           count++;</span><br><span>     }</span><br><span>    ao2_iterator_destroy(&iter);</span><br><span>@@ -575,6 +599,11 @@</span><br><span>              format_handler, format_to_str, NULL, 0, 0);</span><br><span>  ast_sorcery_object_field_register_custom(geoloc_sorcery, "location", "location_info", NULL,</span><br><span>              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> </span><br><span>     ast_sorcery_apply_default(geoloc_sorcery, "profile", "config", "geolocation.conf,criteria=type=profile");</span><br><span>      if (ast_sorcery_object_register(geoloc_sorcery, "profile", geoloc_profile_alloc, NULL, geoloc_profile_apply_handler)) {</span><br><span>@@ -599,6 +628,8 @@</span><br><span>              location_refinement_handler, location_refinement_to_str, location_refinement_dup, 0, 0);</span><br><span>     ast_sorcery_object_field_register_custom(geoloc_sorcery, "profile", "location_variables", NULL,</span><br><span>          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> </span><br><span>         ast_sorcery_load(geoloc_sorcery);</span><br><span> </span><br><span>diff --git a/res/res_geolocation/geoloc_datastore.c b/res/res_geolocation/geoloc_datastore.c</span><br><span>index 1c188f5..2ba2204 100644</span><br><span>--- a/res/res_geolocation/geoloc_datastore.c</span><br><span>+++ b/res/res_geolocation/geoloc_datastore.c</span><br><span>@@ -235,7 +235,7 @@</span><br><span>             return -1;</span><br><span>   }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-   AST_VECTOR_REMOVE(&eds->eprofiles, ix, 1);</span><br><span style="color: hsl(120, 100%, 40%);">+     ao2_ref(AST_VECTOR_REMOVE(&eds->eprofiles, ix, 1), -1);</span><br><span>       return 0;</span><br><span> }</span><br><span> </span><br><span>diff --git a/res/res_geolocation/geoloc_doc.xml b/res/res_geolocation/geoloc_doc.xml</span><br><span>index 70de7bb..149baf1 100644</span><br><span>--- a/res/res_geolocation/geoloc_doc.xml</span><br><span>+++ b/res/res_geolocation/geoloc_doc.xml</span><br><span>@@ -19,22 +19,22 @@</span><br><span>                                                        <enum name="civicAddress"></span><br><span>                                                           <para></span><br><span>                                                                         The</span><br><span style="color: hsl(0, 100%, 40%);">-                                                                     <literal>location</literal></span><br><span style="color: hsl(120, 100%, 40%);">+                                                                       <literal>location_info</literal></span><br><span>                                                                         parameter must contain a comma separated list of IANA codes</span><br><span style="color: hsl(0, 100%, 40%);">-                                                                     describing this location.</span><br><span style="color: hsl(120, 100%, 40%);">+                                                                     describing the civicAddress of this location.</span><br><span>                                                                </para></span><br><span>                                                        </enum></span><br><span>                                                        <enum name="GML"></span><br><span>                                                            <para></span><br><span>                                                                         The</span><br><span style="color: hsl(0, 100%, 40%);">-                                                                     <literal>location</literal> parameter must contain a comma</span><br><span style="color: hsl(120, 100%, 40%);">+                                                                        <literal>location_info</literal> parameter must contain a comma</span><br><span>                                                                  separated list valid GML elements describing this location.</span><br><span>                                                          </para></span><br><span>                                                        </enum></span><br><span>                                                        <enum name="URI"></span><br><span>                                                            <para></span><br><span>                                                                         The</span><br><span style="color: hsl(0, 100%, 40%);">-                                                                     <literal>location</literal> parameter must contain a single</span><br><span style="color: hsl(120, 100%, 40%);">+                                                                       <literal>location_info</literal> parameter must contain a single</span><br><span>                                                                         URI parameter which contains an external URI describing this location.</span><br><span>                                                               </para></span><br><span>                                                        </enum></span><br><span>@@ -45,10 +45,26 @@</span><br><span>                                  <synopsis>Location information</synopsis></span><br><span>                                        <description></span><br><span>                                          <para>The contents of this parameter are specific to the</span><br><span style="color: hsl(0, 100%, 40%);">-                                                  specification type.</para></span><br><span style="color: hsl(120, 100%, 40%);">+                                                      location <literal>format</literal>.</para></span><br><span>                                         </description></span><br><span>                                 </configOption></span><br><span style="color: hsl(0, 100%, 40%);">-                   </configObject>   </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 provides, 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.</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 teh method used to determine the location.  It could be</span><br><span style="color: hsl(120, 100%, 40%);">+                                              something like "GPS" or "802.11".  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%);">+                                      </description></span><br><span style="color: hsl(120, 100%, 40%);">+                          </configOption></span><br><span style="color: hsl(120, 100%, 40%);">+                 </configObject></span><br><span>                        <configObject name="profile"></span><br><span>                                <synopsis>Profile</synopsis></span><br><span>                             <description></span><br><span>@@ -89,6 +105,15 @@</span><br><span>                                            <para>xxxx</para></span><br><span>                                        </description></span><br><span>                                 </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>                                <configOption name="action" default="no"></span><br><span>                                  <synopsis>Determine whether the location information supplied to a</span><br><span>                                             channel should be used</synopsis></span><br><span>@@ -182,7 +207,7 @@</span><br><span>                        </para></parameter></span><br><span>              </syntax></span><br><span>              <description></span><br><span style="color: hsl(0, 100%, 40%);">-                     <para>This application deleted a Geolocation Profile from a channel.</para></span><br><span style="color: hsl(120, 100%, 40%);">+                       <para>This application deletes a Geolocation Profile from a channel.</para></span><br><span>                      <para>The following variable is set:</para></span><br><span>                      <variablelist></span><br><span>                                 <variable name="GEOLOC_PROFILE_COUNT"></span><br><span>@@ -191,6 +216,5 @@</span><br><span>                         </variablelist></span><br><span>                </description></span><br><span>         </application></span><br><span style="color: hsl(0, 100%, 40%);">-    </span><br><span> </docs></span><br><span> </span><br><span>diff --git a/res/res_geolocation/geoloc_eprofile.c b/res/res_geolocation/geoloc_eprofile.c</span><br><span>index 26c9476..57f8ab4 100644</span><br><span>--- a/res/res_geolocation/geoloc_eprofile.c</span><br><span>+++ b/res/res_geolocation/geoloc_eprofile.c</span><br><span>@@ -17,6 +17,8 @@</span><br><span>  */</span><br><span> </span><br><span> #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> #include "asterisk/xml.h"</span><br><span> #include "geoloc_private.h"</span><br><span> </span><br><span>@@ -28,7 +30,12 @@</span><br><span> extern const uint8_t _binary_res_geolocation_pidf_lo_test_xml_end[];</span><br><span> static size_t pidf_lo_test_xml_size;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-static struct ast_xslt_doc *pidf_lo_xslt;</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> </span><br><span> static struct ast_sorcery *geoloc_sorcery;</span><br><span> </span><br><span>@@ -91,6 +98,7 @@</span><br><span> </span><br><span>              eprofile->format = loc->format;</span><br><span>                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>              ao2_ref(loc, -1);</span><br><span>            if (rc != 0) {</span><br><span>                       return -1;</span><br><span>@@ -145,11 +153,16 @@</span><br><span>   }</span><br><span> </span><br><span>        ao2_lock(profile);</span><br><span style="color: hsl(0, 100%, 40%);">-      ast_string_field_set(eprofile, location_reference, profile->location_reference);</span><br><span>  eprofile->geolocation_routing = profile->geolocation_routing;</span><br><span>  eprofile->pidf_element = profile->pidf_element;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-       rc = DUP_VARS(eprofile->location_refinement, profile->location_refinement);</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>    if (rc == 0) {</span><br><span>               rc = DUP_VARS(eprofile->location_variables, profile->location_variables);</span><br><span>      }</span><br><span>@@ -174,10 +187,41 @@</span><br><span>    return eprofile;</span><br><span> }</span><br><span> </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> struct ast_geoloc_eprofile *ast_geoloc_eprofile_create_from_uri(const char *uri,</span><br><span style="color: hsl(0, 100%, 40%);">-      const char *reference_string)</span><br><span style="color: hsl(120, 100%, 40%);">+ const char *ref_str)</span><br><span> {</span><br><span>    struct ast_geoloc_eprofile *eprofile = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+  char *ra = NULL;</span><br><span>     char *local_uri;</span><br><span> </span><br><span>         if (ast_strlen_zero(uri)) {</span><br><span>@@ -188,9 +232,11 @@</span><br><span>   if (local_uri[0] == '<') {</span><br><span>                local_uri++;</span><br><span>         }</span><br><span style="color: hsl(0, 100%, 40%);">-       if (ast_ends_with(local_uri, ">")) {</span><br><span style="color: hsl(0, 100%, 40%);">-               local_uri[strlen(local_uri)-1] = '\0';</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>  }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>  ast_strip(local_uri);</span><br><span> </span><br><span>    eprofile = ast_geoloc_eprofile_alloc(local_uri);</span><br><span>@@ -198,12 +244,195 @@</span><br><span>            return NULL;</span><br><span>         }</span><br><span> </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>       eprofile->format = AST_GEOLOC_FORMAT_URI;</span><br><span>         eprofile->location_info = ast_variable_new("URI", local_uri, "");</span><br><span> </span><br><span>         return eprofile;</span><br><span> }</span><br><span> </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%);">+     struct ast_str *buf = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+   char *dup;</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%);">+                    char *newval = ast_malloc(strlen(value) + 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%);">+   dup = ast_strdupa(ast_str_buffer(buf));</span><br><span style="color: hsl(120, 100%, 40%);">+       ast_free(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, dup);</span><br><span 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%);">+     struct ast_str *buf = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+   char *dup;</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%);">+   dup = ast_strdupa(ast_str_buffer(buf));</span><br><span style="color: hsl(120, 100%, 40%);">+       ast_free(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, dup);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> static struct ast_geoloc_eprofile *geoloc_eprofile_create_from_xslt_result(</span><br><span>   struct ast_xml_doc *result_doc,</span><br><span>      const char *reference_string)</span><br><span>@@ -214,65 +443,69 @@</span><br><span>        struct ast_xml_node *location_info = NULL;</span><br><span>   struct ast_xml_node *usage_rules = NULL;</span><br><span>     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>         const char *id;</span><br><span>      const char *format_str;</span><br><span>      const char *pidf_element_str;</span><br><span style="color: hsl(0, 100%, 40%);">-   const char *location_str;</span><br><span style="color: hsl(0, 100%, 40%);">-       const char *usage_str;</span><br><span>       const char *method_str;</span><br><span style="color: hsl(0, 100%, 40%);">- char *duped;</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> </span><br><span>      presence = ast_xml_get_root(result_doc);</span><br><span>     pidf_element = ast_xml_node_get_children(presence);</span><br><span>  location_info = ast_xml_find_child_element(pidf_element, "location-info", NULL, NULL);</span><br><span>     usage_rules = ast_xml_find_child_element(pidf_element, "usage-rules", NULL, NULL);</span><br><span>         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> </span><br><span>         id = S_OR(ast_xml_get_attribute(pidf_element, "id"), ast_xml_get_attribute(presence, "entity"));</span><br><span>         eprofile = ast_geoloc_eprofile_alloc(id);</span><br><span>    if (!eprofile) {</span><br><span style="color: hsl(0, 100%, 40%);">-                return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+          SCOPE_EXIT_RTN_VALUE(NULL, "%s: Allocation failure\n", reference_string);</span><br><span>  }</span><br><span> </span><br><span>        format_str = ast_xml_get_attribute(location_info, "format");</span><br><span style="color: hsl(0, 100%, 40%);">-  if (ast_strings_equal(format_str, "gml")) {</span><br><span style="color: hsl(120, 100%, 40%);">+ if (strcasecmp(format_str, "gml") == 0) {</span><br><span>          eprofile->format = AST_GEOLOC_FORMAT_GML;</span><br><span style="color: hsl(0, 100%, 40%);">-    } else if (ast_strings_equal(format_str, "civicAddress")) {</span><br><span style="color: hsl(120, 100%, 40%);">+ } else if (strcasecmp(format_str, "civicAddress") == 0) {</span><br><span>          eprofile->format = AST_GEOLOC_FORMAT_CIVIC_ADDRESS;</span><br><span>       } else {</span><br><span>             ao2_ref(eprofile, -1);</span><br><span style="color: hsl(0, 100%, 40%);">-          ast_log(LOG_ERROR, "%s: Unknown format '%s'\n", reference_string, format_str);</span><br><span style="color: hsl(0, 100%, 40%);">-                return NULL;</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>      }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-   pidf_element_str = ast_xml_get_attribute(pidf_element, "name");</span><br><span style="color: hsl(120, 100%, 40%);">+     pidf_element_str = ast_xml_node_get_name(pidf_element);</span><br><span>      eprofile->pidf_element = geoloc_pidf_element_str_to_enum(pidf_element_str);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-      location_str = ast_xml_get_text(location_info);</span><br><span style="color: hsl(0, 100%, 40%);">- duped = ast_strdupa(location_str);</span><br><span style="color: hsl(0, 100%, 40%);">-      eprofile->location_info = ast_variable_list_from_string(duped, ",", "=", "\"");</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>   if (!eprofile->location_info) {</span><br><span>           ao2_ref(eprofile, -1);</span><br><span style="color: hsl(0, 100%, 40%);">-          ast_log(LOG_ERROR, "%s: Unable to create location variables from '%s'\n", reference_string, location_str);</span><br><span style="color: hsl(0, 100%, 40%);">-            return NULL;</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>    }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-   usage_str = ast_xml_get_text(usage_rules);</span><br><span style="color: hsl(0, 100%, 40%);">-      duped = ast_strdupa(usage_str);</span><br><span style="color: hsl(0, 100%, 40%);">- eprofile->usage_rules = ast_variable_list_from_string(duped, ",", "=", "\"");</span><br><span style="color: hsl(120, 100%, 40%);">+   eprofile->usage_rules = var_list_from_node(usage_rules, reference_string);</span><br><span> </span><br><span>    method_str = ast_xml_get_text(method);</span><br><span>       ast_string_field_set(eprofile, method, method_str);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">- return eprofile;</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> }</span><br><span> </span><br><span> struct ast_geoloc_eprofile *ast_geoloc_eprofile_create_from_pidf(</span><br><span style="color: hsl(0, 100%, 40%);">-        struct ast_xml_doc *pidf_xmldoc, const char *reference_string)</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> {</span><br><span>   RAII_VAR(struct ast_xml_doc *, result_doc, NULL, ast_xml_close);</span><br><span>     struct ast_geoloc_eprofile *eprofile;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span>        /*</span><br><span>    * The namespace prefixes used here (dm, def, gp, etc) don't have to match</span><br><span>        * the ones used in the received PIDF-LO document but they MUST match the</span><br><span>@@ -292,28 +525,30 @@</span><br><span>    const char *find_device[] = { "path", "/def:presence/dm:device[.//gp:location-info][1]", NULL};</span><br><span>  const char *find_tuple[] = { "path", "/def:presence/def:tuple[.//gp:location-info][1]", NULL};</span><br><span>   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> </span><br><span style="color: hsl(0, 100%, 40%);">-  result_doc = ast_xslt_apply(pidf_lo_xslt, pidf_xmldoc, find_device);</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>        if (!result_doc || !ast_xml_node_get_children((struct ast_xml_node *)result_doc)) {</span><br><span>          ast_xml_close(result_doc);</span><br><span style="color: hsl(0, 100%, 40%);">-              result_doc = ast_xslt_apply(pidf_lo_xslt, pidf_xmldoc, find_tuple);</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>         }</span><br><span>    if (!result_doc || !ast_xml_node_get_children((struct ast_xml_node *)result_doc)) {</span><br><span>          ast_xml_close(result_doc);</span><br><span style="color: hsl(0, 100%, 40%);">-              result_doc = ast_xslt_apply(pidf_lo_xslt, pidf_xmldoc, find_person);</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>        }</span><br><span>    if (!result_doc || !ast_xml_node_get_children((struct ast_xml_node *)result_doc)) {</span><br><span style="color: hsl(0, 100%, 40%);">-             return NULL;</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>    }</span><br><span> </span><br><span>        /*</span><br><span>    * The document returned from the stylesheet application looks like this...</span><br><span>   * <presence id="presence-entity"></span><br><span style="color: hsl(0, 100%, 40%);">-       *     <pidf-element name="tuple" id="element-id"></span><br><span style="color: hsl(0, 100%, 40%);">-     *         <location-info format="gml">format="gml", type="Ellipsoid", crs="3d", ...</location-info></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>     *         <usage-rules>retransmission-allowed="no", retention-expiry="2010-11-14T20:00:00Z"</usage-rules></span><br><span>    *         <method>Hybrid_A-GPS</method></span><br><span style="color: hsl(0, 100%, 40%);">-     *     </pidf-element></span><br><span style="color: hsl(120, 100%, 40%);">+   *     </tuple></span><br><span>         *  </presence></span><br><span>         *</span><br><span>    * Regardless of whether the pidf-element was tuple, device or person and whether</span><br><span>@@ -325,9 +560,237 @@</span><br><span>     * ast_variable_list_from_string().</span><br><span>   */</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">- eprofile = geoloc_eprofile_create_from_xslt_result(result_doc, reference_string);</span><br><span style="color: hsl(120, 100%, 40%);">+     eprofile = geoloc_eprofile_create_from_xslt_result(result_doc, ref_str);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-    return eprofile;</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> }</span><br><span> </span><br><span> #ifdef TEST_FRAMEWORK</span><br><span>@@ -342,8 +805,12 @@</span><br><span> int geoloc_eprofile_unload(void)</span><br><span> {</span><br><span>    unload_tests();</span><br><span style="color: hsl(0, 100%, 40%);">- if (pidf_lo_xslt) {</span><br><span style="color: hsl(0, 100%, 40%);">-             ast_xslt_close(pidf_lo_xslt);</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>       }</span><br><span> </span><br><span>        if (geoloc_sorcery) {</span><br><span>@@ -355,21 +822,32 @@</span><br><span> </span><br><span> int geoloc_eprofile_load(void)</span><br><span> {</span><br><span style="color: hsl(0, 100%, 40%);">-        geoloc_sorcery = geoloc_get_sorcery();</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span>       pidf_to_eprofile_xslt_size =</span><br><span>                 (_binary_res_geolocation_pidf_to_eprofile_xslt_end - _binary_res_geolocation_pidf_to_eprofile_xslt_start);</span><br><span> </span><br><span>       pidf_lo_test_xml_size =</span><br><span>              (_binary_res_geolocation_pidf_lo_test_xml_end - _binary_res_geolocation_pidf_lo_test_xml_start);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-    pidf_lo_xslt = ast_xslt_read_memory(</span><br><span style="color: hsl(120, 100%, 40%);">+  pidf_to_eprofile_xslt = ast_xslt_read_memory(</span><br><span>                (char *)_binary_res_geolocation_pidf_to_eprofile_xslt_start, pidf_to_eprofile_xslt_size);</span><br><span style="color: hsl(0, 100%, 40%);">-       if (!pidf_lo_xslt) {</span><br><span style="color: hsl(0, 100%, 40%);">-            ast_log(LOG_ERROR, "Unable to read pidf_lo_xslt from memory\n");</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>          return AST_MODULE_LOAD_DECLINE;</span><br><span>      }</span><br><span> </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>     load_tests();</span><br><span> </span><br><span>    return AST_MODULE_LOAD_SUCCESS;</span><br><span>@@ -430,12 +908,12 @@</span><br><span>      const char *search[] = { "path", path, NULL };</span><br><span> </span><br><span>         if (!ast_strlen_zero(path)) {</span><br><span style="color: hsl(0, 100%, 40%);">-           result_doc = ast_xslt_apply(pidf_lo_xslt, pidf_xmldoc, (const char **)search);</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>              ast_test_validate(test, (result_doc && ast_xml_node_get_children((struct ast_xml_node *)result_doc)));</span><br><span> </span><br><span>           eprofile = geoloc_eprofile_create_from_xslt_result(result_doc, "test_create_from_xslt");</span><br><span>   } else {</span><br><span style="color: hsl(0, 100%, 40%);">-                eprofile = ast_geoloc_eprofile_create_from_pidf(pidf_xmldoc, "test_create_from_pidf");</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>       }</span><br><span> </span><br><span>        ast_test_validate(test, eprofile != NULL);</span><br><span>@@ -451,13 +929,15 @@</span><br><span> </span><br><span>       str = ast_variable_list_join(eprofile->location_info, ",", "=", NULL, NULL);</span><br><span>  ast_test_validate(test, str != NULL);</span><br><span style="color: hsl(0, 100%, 40%);">-   ast_test_status_update(test, "location_vars: %s\n", ast_str_buffer(str));</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>         ast_test_validate(test, ast_strings_equal(ast_str_buffer(str), location));</span><br><span>   ast_free(str);</span><br><span> </span><br><span>   str = ast_variable_list_join(eprofile->usage_rules, ",", "=", "'", NULL);</span><br><span>       ast_test_validate(test, str != NULL);</span><br><span style="color: hsl(0, 100%, 40%);">-   ast_test_status_update(test, "usage_rules: %s\n", ast_str_buffer(str));</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>   ast_test_validate(test, ast_strings_equal(ast_str_buffer(str), usage));</span><br><span> </span><br><span>  return AST_TEST_PASS;</span><br><span>@@ -489,9 +969,8 @@</span><br><span>          AST_PIDF_ELEMENT_DEVICE,</span><br><span>             AST_GEOLOC_FORMAT_GML,</span><br><span>               "TA-NMR",</span><br><span style="color: hsl(0, 100%, 40%);">-             "format=gml,type=ArcBand,crs=2d,pos=-43.5723 153.21760,innerRadius=3594,"</span><br><span style="color: hsl(0, 100%, 40%);">-                             "outerRadius=4148,startAngle=20,startAngle_uom=radians,openingAngle=20,"</span><br><span style="color: hsl(0, 100%, 40%);">-                              "openingAngle_uom=radians",</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>          "retransmission-allowed='yes',ruleset-preference='https:/www/more.com',"</span><br><span>                   "retention-expires='2007-06-22T20:57:29Z'"</span><br><span>                 );</span><br><span>@@ -504,7 +983,7 @@</span><br><span>             AST_PIDF_ELEMENT_DEVICE,</span><br><span>             AST_GEOLOC_FORMAT_CIVIC_ADDRESS,</span><br><span>             "GPS",</span><br><span style="color: hsl(0, 100%, 40%);">-                "format=civicAddress,country=AU,A1=NSW,A3=Wollongong,A4=North Wollongong,"</span><br><span style="color: hsl(120, 100%, 40%);">+          "lang=en-AU,country=AU,A1=NSW,A3=Wollongong,A4=North Wollongong,"</span><br><span>                  "RD=Flinders,STS=Street,RDBR=Campbell Street,LMK=Gilligan's Island,"</span><br><span>                   "LOC=Corner,NAM=Video Rental Store,PC=2500,ROOM=Westerns and Classics,"</span><br><span>                    "PLC=store,POBOX=Private Box 15",</span><br><span>diff --git a/res/res_geolocation/geoloc_gml.c b/res/res_geolocation/geoloc_gml.c</span><br><span>index 04e363d..8a66162 100644</span><br><span>--- a/res/res_geolocation/geoloc_gml.c</span><br><span>+++ b/res/res_geolocation/geoloc_gml.c</span><br><span>@@ -127,10 +127,10 @@</span><br><span>     int def_index = -1;</span><br><span>  const struct ast_variable *var;</span><br><span>      int i;</span><br><span style="color: hsl(0, 100%, 40%);">-  const char *shape_type = ast_variable_find_in_list(varlist, "type");</span><br><span style="color: hsl(120, 100%, 40%);">+        const char *shape_type = ast_variable_find_in_list(varlist, "shape");</span><br><span> </span><br><span>  if (!shape_type) {</span><br><span style="color: hsl(0, 100%, 40%);">-              return AST_GEOLOC_VALIDATE_MISSING_TYPE;</span><br><span style="color: hsl(120, 100%, 40%);">+              return AST_GEOLOC_VALIDATE_MISSING_SHAPE;</span><br><span>    }</span><br><span> </span><br><span>        for (i = 0; i < ARRAY_LEN(gml_shape_defs); i++) {</span><br><span>@@ -139,12 +139,12 @@</span><br><span>                 }</span><br><span>    }</span><br><span>    if (def_index < 0) {</span><br><span style="color: hsl(0, 100%, 40%);">-         return AST_GEOLOC_VALIDATE_INVALID_TYPE;</span><br><span style="color: hsl(120, 100%, 40%);">+              return AST_GEOLOC_VALIDATE_INVALID_SHAPE;</span><br><span>    }</span><br><span> </span><br><span>        for (var = varlist; var; var = var->next) {</span><br><span>               int vname_index = -1;</span><br><span style="color: hsl(0, 100%, 40%);">-           if (ast_strings_equal("type", var->name)) {</span><br><span style="color: hsl(120, 100%, 40%);">+              if (ast_strings_equal("shape", var->name)) {</span><br><span>                    continue;</span><br><span>            }</span><br><span>            for (i = 0; i < ARRAY_LEN(gml_shape_defs[def_index].required_attributes); i++) {</span><br><span>@@ -235,6 +235,113 @@</span><br><span>  AST_CLI_DEFINE(handle_gml_show, "Show the GML Shape definitions"),</span><br><span> };</span><br><span> </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> int geoloc_gml_unload(void)</span><br><span> {</span><br><span>         ast_cli_unregister_multiple(geoloc_gml_cli, ARRAY_LEN(geoloc_gml_cli));</span><br><span>diff --git a/res/res_geolocation/geoloc_private.h b/res/res_geolocation/geoloc_private.h</span><br><span>index 18b51a7..860f3b5 100644</span><br><span>--- a/res/res_geolocation/geoloc_private.h</span><br><span>+++ b/res/res_geolocation/geoloc_private.h</span><br><span>@@ -139,10 +139,14 @@</span><br><span> int geoloc_config_reload(void);</span><br><span> int geoloc_config_unload(void);</span><br><span> </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> int geoloc_civicaddr_load(void);</span><br><span> int geoloc_civicaddr_unload(void);</span><br><span> int geoloc_civicaddr_reload(void);</span><br><span> </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> int geoloc_gml_unload(void);</span><br><span> int geoloc_gml_load(void);</span><br><span> int geoloc_gml_reload(void);</span><br><span>diff --git a/res/res_geolocation/pidf_to_eprofile.xslt b/res/res_geolocation/pidf_to_eprofile.xslt</span><br><span>index 409ba9e..4e717ad 100644</span><br><span>--- a/res/res_geolocation/pidf_to_eprofile.xslt</span><br><span>+++ b/res/res_geolocation/pidf_to_eprofile.xslt</span><br><span>@@ -9,57 +9,102 @@</span><br><span>         xmlns:gp="urn:ietf:params:xml:ns:pidf:geopriv10"</span><br><span>   xmlns:gs="http://www.opengis.net/pidflo/1.0"</span><br><span>       xmlns:xsl="http://www.w3.org/1999/XSL/Transform"></span><br><span style="color: hsl(0, 100%, 40%);">-  <!--xsl:output method="text" /--></span><br><span style="color: hsl(0, 100%, 40%);">-       <xsl:strip-space elements="*" /></span><br><span 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 cound 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>      <xsl:param name="path"/></span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-        <xsl:template name="name-value"></span><br><span style="color: hsl(0, 100%, 40%);">-                <xsl:value-of select="local-name(.)" /><xsl:text>="</xsl:text></span><br><span style="color: hsl(0, 100%, 40%);">-         <xsl:value-of select="normalize-space(.)" /><xsl:text>"</xsl:text></span><br><span style="color: hsl(0, 100%, 40%);">-             <xsl:if test="following-sibling::*"><xsl:text>, </xsl:text></xsl:if></span><br><span 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>         </xsl:template></span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-       <xsl:template name="length"><xsl:call-template name="name-value" /></xsl:template></span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-        <xsl:template name="angle"></span><br><span style="color: hsl(0, 100%, 40%);">-             <xsl:value-of select="local-name(.)" /><xsl:text>="</xsl:text></span><br><span style="color: hsl(0, 100%, 40%);">-         <xsl:value-of select="normalize-space(.)" /><xsl:text>"</xsl:text><xsl:text>, </xsl:text></span><br><span style="color: hsl(0, 100%, 40%);">-          <xsl:value-of select="local-name(.)" /><xsl:text>_uom="</xsl:text></span><br><span style="color: hsl(0, 100%, 40%);">-             <xsl:choose></span><br><span style="color: hsl(0, 100%, 40%);">-                      <xsl:when test="@uom = 'urn:ogc:def:uom:EPSG::9102'"><xsl:text>radians</xsl:text></xsl:when></span><br><span style="color: hsl(0, 100%, 40%);">-                  <xsl:otherwise><xsl:text>degrees</xsl:text></xsl:otherwise></span><br><span style="color: hsl(0, 100%, 40%);">-             </xsl:choose></span><br><span style="color: hsl(0, 100%, 40%);">-             <xsl:text>"</xsl:text></span><br><span style="color: hsl(0, 100%, 40%);">-         <xsl:if test="following-sibling::*"><xsl:text>, </xsl:text></xsl:if></span><br><span style="color: hsl(0, 100%, 40%);">-  </xsl:template></span><br><span style="color: hsl(0, 100%, 40%);">-   <xsl:template match="gs:orientation"><xsl:call-template name="angle" /></xsl:template></span><br><span style="color: hsl(0, 100%, 40%);">-    <xsl:template match="gs:radius"><xsl:call-template name="length" /></xsl:template></span><br><span style="color: hsl(0, 100%, 40%);">-        <xsl:template match="gs:height"><xsl:call-template name="length" /></xsl:template></span><br><span style="color: hsl(0, 100%, 40%);">-        <xsl:template match="gs:semiMajorAxis"><xsl:call-template name="length" /></xsl:template></span><br><span style="color: hsl(0, 100%, 40%);">- <xsl:template match="gs:semiMinorAxis"><xsl:call-template name="length" /></xsl:template></span><br><span style="color: hsl(0, 100%, 40%);">- <xsl:template match="gs:verticalAxis"><xsl:call-template name="length" /></xsl:template></span><br><span style="color: hsl(0, 100%, 40%);">-  <xsl:template match="gs:innerRadius"><xsl:call-template name="length" /></xsl:template></span><br><span style="color: hsl(0, 100%, 40%);">-   <xsl:template match="gs:outerRadius"><xsl:call-template name="length" /></xsl:template></span><br><span style="color: hsl(0, 100%, 40%);">-   <xsl:template match="gs:startAngle"><xsl:call-template name="angle" /></xsl:template></span><br><span style="color: hsl(0, 100%, 40%);">-     <xsl:template match="gs:openingAngle"><xsl:call-template name="angle" /></xsl:template></span><br><span style="color: hsl(0, 100%, 40%);">-   <xsl:template match="gml:pos"><xsl:call-template name="name-value" /></xsl:template></span><br><span style="color: hsl(0, 100%, 40%);">-      <xsl:template match="gml:posList"><xsl:call-template name="name-value" /></xsl:template></span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-  <xsl:template name="shape"></span><br><span style="color: hsl(0, 100%, 40%);">-             <xsl:text>format="gml", type="</xsl:text><xsl:value-of select="local-name(.)" /><xsl:text>", </xsl:text></span><br><span style="color: hsl(0, 100%, 40%);">-            <xsl:text>crs="</xsl:text></span><br><span style="color: hsl(0, 100%, 40%);">-             <xsl:choose></span><br><span style="color: hsl(0, 100%, 40%);">-                      <xsl:when test="@srsName = 'urn:ogc:def:crs:EPSG::4326'"><xsl:text>2d</xsl:text></xsl:when></span><br><span style="color: hsl(0, 100%, 40%);">-                   <xsl:when test="@srsName = 'urn:ogc:def:crs:EPSG::4979'"><xsl:text>3d</xsl:text></xsl:when></span><br><span style="color: hsl(0, 100%, 40%);">-                   <xsl:otherwise><xsl:text>unknown</xsl:text></xsl:otherwise></span><br><span style="color: hsl(0, 100%, 40%);">-             </xsl:choose></span><br><span style="color: hsl(0, 100%, 40%);">-             <xsl:text>", </xsl:text></span><br><span style="color: hsl(0, 100%, 40%);">-               <xsl:apply-templates /></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>         </xsl:template></span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-       <xsl:template match="ca:civicAddress/*"><xsl:call-template name="name-value" /> </xsl:template></span><br><span style="color: hsl(0, 100%, 40%);">-   <xsl:template name="civicAddress"><xsl:text>format="civicAddress", </xsl:text></span><br><span style="color: hsl(0, 100%, 40%);">-            <xsl:apply-templates /></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>         </xsl:template></span><br><span> </span><br><span>    <xsl:template match="gp:location-info/gml:*"></span><br><span>@@ -76,13 +121,77 @@</span><br><span>                 </xsl:element></span><br><span>         </xsl:template></span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-       <xsl:template match="gp:location-info/ca:*"></span><br><span style="color: hsl(120, 100%, 40%);">+  <xsl:template match="gp:location-info/ca:civicAddress"></span><br><span>              <xsl:element name="location-info"></span><br><span>                   <xsl:attribute name="format">civicAddress</xsl:attribute></span><br><span>                      <xsl:call-template name="civicAddress" /></span><br><span>            </xsl:element></span><br><span>         </xsl:template></span><br><span> </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>      <xsl:template match="gp:usage-rules/*"></span><br><span>              <xsl:call-template name="name-value" /></span><br><span>      </xsl:template></span><br><span>@@ -94,31 +203,10 @@</span><br><span>         </xsl:template></span><br><span> </span><br><span>    <xsl:template match="gp:method"></span><br><span style="color: hsl(120, 100%, 40%);">+              <xsl:element name="method"></span><br><span>          <xsl:value-of select="normalize-space(.)" /></span><br><span style="color: hsl(0, 100%, 40%);">-    </xsl:template></span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-   <xsl:template name="topnode"></span><br><span style="color: hsl(0, 100%, 40%);">-           <xsl:element name="pidf-element"></span><br><span style="color: hsl(0, 100%, 40%);">-                       <xsl:attribute name="name"><xsl:value-of select="local-name(.)"/></xsl:attribute></span><br><span style="color: hsl(0, 100%, 40%);">-                 <xsl:attribute name="id"><xsl:value-of select="@id"/></xsl:attribute></span><br><span style="color: hsl(0, 100%, 40%);">-                     <xsl:apply-templates select=".//gp:location-info"/></span><br><span style="color: hsl(0, 100%, 40%);">-                     <xsl:apply-templates select=".//gp:usage-rules"/></span><br><span style="color: hsl(0, 100%, 40%);">-                       <xsl:element name="method"></span><br><span style="color: hsl(0, 100%, 40%);">-                     <xsl:apply-templates select=".//gp:method"/></span><br><span style="color: hsl(0, 100%, 40%);">-                    </xsl:element></span><br><span style="color: hsl(0, 100%, 40%);">-            </xsl:element></span><br><span style="color: hsl(0, 100%, 40%);">-            <xsl:text></span><br><span style="color: hsl(0, 100%, 40%);">-</xsl:text></span><br><span style="color: hsl(0, 100%, 40%);">-       </xsl:template></span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-   <xsl:template match="dm:device"><xsl:call-template name="topnode" /></xsl:template></span><br><span style="color: hsl(0, 100%, 40%);">-       <xsl:template match="def:tuple"><xsl:call-template name="topnode" /></xsl:template></span><br><span style="color: hsl(0, 100%, 40%);">-       <xsl:template match="dm:person"><xsl:call-template name="topnode" /></xsl:template></span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-       <xsl:template match="/"></span><br><span style="color: hsl(0, 100%, 40%);">-                <xsl:element name="presence"></span><br><span style="color: hsl(0, 100%, 40%);">-                   <xsl:attribute name="entity"><xsl:value-of select="/*/@entity"/></xsl:attribute></span><br><span style="color: hsl(0, 100%, 40%);">-                  <xsl:apply-templates select="$path"/></span><br><span>                </xsl:element></span><br><span>         </xsl:template></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       </span><br><span> </xsl:stylesheet></span><br><span>diff --git a/res/res_pjsip.c b/res/res_pjsip.c</span><br><span>index 8900964..c910551 100644</span><br><span>--- a/res/res_pjsip.c</span><br><span>+++ b/res/res_pjsip.c</span><br><span>@@ -1825,6 +1825,22 @@</span><br><span>        return 0;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+pjsip_generic_string_hdr *ast_sip_add_header2(pjsip_tx_data *tdata,</span><br><span style="color: hsl(120, 100%, 40%);">+       const char *name, const char *value)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+       pj_str_t hdr_name;</span><br><span style="color: hsl(120, 100%, 40%);">+    pj_str_t hdr_value;</span><br><span style="color: hsl(120, 100%, 40%);">+   pjsip_generic_string_hdr *hdr;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      pj_cstr(&hdr_name, name);</span><br><span style="color: hsl(120, 100%, 40%);">+ pj_cstr(&hdr_value, value);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     hdr = pjsip_generic_string_hdr_create(tdata->pool, &hdr_name, &hdr_value);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr *) hdr);</span><br><span style="color: hsl(120, 100%, 40%);">+  return hdr;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> static pjsip_msg_body *ast_body_to_pjsip_body(pj_pool_t *pool, const struct ast_sip_body *body)</span><br><span> {</span><br><span>     pj_str_t type;</span><br><span>diff --git a/res/res_pjsip_geolocation.c b/res/res_pjsip_geolocation.c</span><br><span>index 7555134..0e9eb37 100644</span><br><span>--- a/res/res_pjsip_geolocation.c</span><br><span>+++ b/res/res_pjsip_geolocation.c</span><br><span>@@ -40,6 +40,8 @@</span><br><span> static int find_pidf(const char *session_name, struct pjsip_rx_data *rdata, char *geoloc_uri,</span><br><span>         char **pidf_body, unsigned int *pidf_len)</span><br><span> {</span><br><span style="color: hsl(120, 100%, 40%);">+        char *local_uri = ast_strdupa(geoloc_uri);</span><br><span style="color: hsl(120, 100%, 40%);">+    char *ra = NULL;</span><br><span>     /*</span><br><span>    * If the URI is "cid" then we're going to search for a pidf document</span><br><span>   * in the body of the message.  If there's no body, there's no point.</span><br><span>@@ -50,6 +52,14 @@</span><br><span>           return -1;</span><br><span>   }</span><br><span> </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>  /*</span><br><span>    * If the message content type is 'application/pidf+xml', then the pidf is</span><br><span>    * the only document in the message and we'll just parse the entire body</span><br><span>@@ -62,7 +72,7 @@</span><br><span>             *pidf_len = rdata->msg_info.msg->body->len;</span><br><span>         } else if (ast_sip_are_media_types_equal(&rdata->msg_info.ctype->media,</span><br><span>            &pjsip_media_type_multipart_mixed)) {</span><br><span style="color: hsl(0, 100%, 40%);">-               pj_str_t cid = pj_str(geoloc_uri);</span><br><span style="color: hsl(120, 100%, 40%);">+            pj_str_t cid = pj_str(local_uri);</span><br><span>            pjsip_multipart_part *mp = pjsip_multipart_find_part_by_cid_str(</span><br><span>                     rdata->tp_info.pool, rdata->msg_info.msg->body, &cid);</span><br><span> </span><br><span>@@ -229,30 +239,25 @@</span><br><span>       *                        / absoluteURI ; (from RFC 3261)</span><br><span>     */</span><br><span>  while((geoloc_uri = ast_strsep(&duped_geoloc_hdr_value, ',', AST_STRSEP_TRIM))) {</span><br><span style="color: hsl(0, 100%, 40%);">-           /* geoloc_uri should now be <scheme:location> */</span><br><span style="color: hsl(0, 100%, 40%);">-          int uri_len = strlen(geoloc_uri);</span><br><span style="color: hsl(120, 100%, 40%);">+             /* geoloc_uri should now be <scheme:location>[;loc-src=fqdn] */</span><br><span>                char *pidf_body = NULL;</span><br><span>              unsigned int pidf_len = 0;</span><br><span>           struct ast_xml_doc *incoming_doc = NULL;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span>             struct ast_geoloc_eprofile *eprofile = NULL;</span><br><span>                 int rc = 0;</span><br><span> </span><br><span>              ast_trace(4, "Processing URI '%s'\n", geoloc_uri);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-                if (geoloc_uri[0] != '<' || geoloc_uri[uri_len - 1] != '>') {</span><br><span style="color: hsl(120, 100%, 40%);">+           if (geoloc_uri[0] != '<' || strchr(geoloc_uri, '>') == NULL) {</span><br><span>                         ast_log(LOG_WARNING, "%s: Geolocation header has bad URI '%s'.  Skipping\n", session_name,</span><br><span>                                 geoloc_uri);</span><br><span>                         continue;</span><br><span>            }</span><br><span style="color: hsl(0, 100%, 40%);">-               /* Trim the trailing '>' and skip the leading '<' */</span><br><span style="color: hsl(0, 100%, 40%);">-              geoloc_uri[uri_len - 1] = '\0';</span><br><span style="color: hsl(0, 100%, 40%);">-         geoloc_uri++;</span><br><span>                /*</span><br><span>            * If the URI isn't "cid" then we're just going to pass it through.</span><br><span>                 */</span><br><span style="color: hsl(0, 100%, 40%);">-             if (!ast_begins_with(geoloc_uri, "cid:")) {</span><br><span style="color: hsl(0, 100%, 40%);">-                   ast_trace(4, "Processing URI '%s'.  Reference\n", geoloc_uri);</span><br><span style="color: hsl(120, 100%, 40%);">+              if (!ast_begins_with(geoloc_uri, "<cid:")) {</span><br><span style="color: hsl(120, 100%, 40%);">+                     ast_trace(4, "Processing URI '%s'\n", geoloc_uri);</span><br><span> </span><br><span>                     eprofile = ast_geoloc_eprofile_create_from_uri(geoloc_uri, session_name);</span><br><span>                    if (!eprofile) {</span><br><span>@@ -261,11 +266,13 @@</span><br><span>                             continue;</span><br><span>                    }</span><br><span>            } else {</span><br><span style="color: hsl(0, 100%, 40%);">-                        ast_trace(4, "Processing URI '%s'.  PIDF\n", geoloc_uri);</span><br><span style="color: hsl(120, 100%, 40%);">+                   ast_trace(4, "Processing PIDF-LO '%s'\n", geoloc_uri);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>                   rc = find_pidf(session_name, rdata, geoloc_uri, &pidf_body, &pidf_len);</span><br><span>                      if (rc != 0 || !pidf_body || pidf_len == 0) {</span><br><span>                                continue;</span><br><span>                    }</span><br><span style="color: hsl(120, 100%, 40%);">+                     ast_trace(5, "Processing PIDF-LO "PJSTR_PRINTF_SPEC"\n", (int)pidf_len, pidf_body);</span><br><span> </span><br><span>                  incoming_doc = ast_xml_read_memory(pidf_body, pidf_len);</span><br><span>                     if (!incoming_doc) {</span><br><span>@@ -274,7 +281,7 @@</span><br><span>                           continue;</span><br><span>                    }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-                   eprofile = ast_geoloc_eprofile_create_from_pidf(incoming_doc, session_name);</span><br><span style="color: hsl(120, 100%, 40%);">+                  eprofile = ast_geoloc_eprofile_create_from_pidf(incoming_doc, geoloc_uri, session_name);</span><br><span>             }</span><br><span>            eprofile->action = config_profile->action;</span><br><span>             eprofile->send_location = config_profile->send_location;</span><br><span>@@ -323,9 +330,276 @@</span><br><span>               session_name, eprofile_count);</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+static int add_pidf_to_tdata(struct ast_datastore *tempds, struct ast_channel *channel,</span><br><span style="color: hsl(120, 100%, 40%);">+      struct ast_vector_string *uris, int pidf_index, struct pjsip_tx_data *tdata, const char *session_name)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+     static const pj_str_t from_name = { "From", 4};</span><br><span style="color: hsl(120, 100%, 40%);">+     static const pj_str_t cid_name = { "Content-ID", 10 };</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    pjsip_sip_uri *sip_uri;</span><br><span style="color: hsl(120, 100%, 40%);">+       pjsip_generic_string_hdr *cid;</span><br><span style="color: hsl(120, 100%, 40%);">+        pj_str_t cid_value;</span><br><span style="color: hsl(120, 100%, 40%);">+   pjsip_from_hdr *from = pjsip_msg_find_hdr_by_name(tdata->msg, &from_name, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+       pjsip_sdp_info *tdata_sdp_info;</span><br><span style="color: hsl(120, 100%, 40%);">+       pjsip_msg_body *multipart_body = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+        pjsip_multipart_part *pidf_part;</span><br><span style="color: hsl(120, 100%, 40%);">+      pj_str_t pidf_body_text;</span><br><span style="color: hsl(120, 100%, 40%);">+      char id[6];</span><br><span style="color: hsl(120, 100%, 40%);">+   size_t alloc_size;</span><br><span style="color: hsl(120, 100%, 40%);">+    char *base_cid;</span><br><span style="color: hsl(120, 100%, 40%);">+       const char *final;</span><br><span style="color: hsl(120, 100%, 40%);">+    int rc = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+   RAII_VAR(struct ast_str *, buf, ast_str_create(1024), ast_free);</span><br><span style="color: hsl(120, 100%, 40%);">+      SCOPE_ENTER(3, "%s\n", session_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%);">+     * ast_geoloc_eprofiles_to_pidf() takes the datastore with all of the eprofiles</span><br><span style="color: hsl(120, 100%, 40%);">+        * in it, skips over the ones not needing PIDF processing and combines the</span><br><span style="color: hsl(120, 100%, 40%);">+     * rest into one document.</span><br><span style="color: hsl(120, 100%, 40%);">+     */</span><br><span style="color: hsl(120, 100%, 40%);">+   final = ast_geoloc_eprofiles_to_pidf(tempds, channel, &buf, session_name);</span><br><span style="color: hsl(120, 100%, 40%);">+        ast_trace(5, "Final pidf: \n%s\n", final);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        /*</span><br><span style="color: hsl(120, 100%, 40%);">+     * There _should_ be an SDP already attached to the tdata at this point</span><br><span style="color: hsl(120, 100%, 40%);">+        * but maybe not.  If we can find an existing one, we'll convert the tdata</span><br><span style="color: hsl(120, 100%, 40%);">+         * body into a multipart body and add the SDP as the first part.  Then we'll</span><br><span style="color: hsl(120, 100%, 40%);">+       * create another part to hold the PIDF.</span><br><span style="color: hsl(120, 100%, 40%);">+       *</span><br><span style="color: hsl(120, 100%, 40%);">+     * If we don't find one, we're going to create an empty multipart body</span><br><span style="color: hsl(120, 100%, 40%);">+         * and add the PIDF part to it.</span><br><span style="color: hsl(120, 100%, 40%);">+        *</span><br><span style="color: hsl(120, 100%, 40%);">+     * Technically, if we only have the PIDF, we don't need a multipart</span><br><span style="color: hsl(120, 100%, 40%);">+        * body to hold it but that means we'd have to add the Content-ID header</span><br><span style="color: hsl(120, 100%, 40%);">+   * to the main SIP message.  Since it's unlikely, it's just better to</span><br><span style="color: hsl(120, 100%, 40%);">+  * add the multipary body and leave the rest of the processing unchanged.</span><br><span style="color: hsl(120, 100%, 40%);">+      */</span><br><span style="color: hsl(120, 100%, 40%);">+   tdata_sdp_info = pjsip_tdata_get_sdp_info(tdata);</span><br><span style="color: hsl(120, 100%, 40%);">+     if (tdata_sdp_info->sdp) {</span><br><span style="color: hsl(120, 100%, 40%);">+         ast_trace(4, "body: %p %u\n", tdata_sdp_info->sdp, (unsigned)tdata_sdp_info->sdp_err);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+              rc = pjsip_create_multipart_sdp_body(tdata->pool, tdata_sdp_info->sdp, &multipart_body);</span><br><span style="color: hsl(120, 100%, 40%);">+            if (rc != PJ_SUCCESS) {</span><br><span style="color: hsl(120, 100%, 40%);">+                       SCOPE_EXIT_LOG_RTN_VALUE(0, LOG_ERROR, "%s: Unable to create sdp multipart body\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                         session_name);</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%);">+          multipart_body = pjsip_multipart_create(tdata->pool, &pjsip_media_type_multipart_mixed, 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%);">+   pidf_part = pjsip_multipart_create_part(tdata->pool);</span><br><span style="color: hsl(120, 100%, 40%);">+      pj_cstr(&pidf_body_text, final);</span><br><span style="color: hsl(120, 100%, 40%);">+  pidf_part->body = pjsip_msg_body_create(tdata->pool, &pjsip_media_type_application_pidf_xml.type,</span><br><span style="color: hsl(120, 100%, 40%);">+           &pjsip_media_type_application_pidf_xml.subtype, &pidf_body_text);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    pjsip_multipart_add_part(tdata->pool, multipart_body, pidf_part);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       sip_uri = (pjsip_sip_uri *)pjsip_uri_get_uri(from->uri);</span><br><span style="color: hsl(120, 100%, 40%);">+   alloc_size = sizeof(id) + pj_strlen(&sip_uri->host) + 2;</span><br><span style="color: hsl(120, 100%, 40%);">+       base_cid = ast_malloc(alloc_size);</span><br><span style="color: hsl(120, 100%, 40%);">+    sprintf(base_cid, "%s@%.*s",</span><br><span style="color: hsl(120, 100%, 40%);">+                        ast_generate_random_string(id, sizeof(id)),</span><br><span style="color: hsl(120, 100%, 40%);">+                   (int) pj_strlen(&sip_uri->host), pj_strbuf(&sip_uri->host));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  ast_str_set(&buf, 0, "cid:%s", base_cid);</span><br><span style="color: hsl(120, 100%, 40%);">+       ast_trace(4, "cid: '%s' uri: '%s' pidf_index: %d\n", base_cid, ast_str_buffer(buf), pidf_index);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  AST_VECTOR_INSERT_AT(uris, pidf_index, ast_strdup(ast_str_buffer(buf)));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    cid_value.ptr = pj_pool_alloc(tdata->pool, alloc_size);</span><br><span style="color: hsl(120, 100%, 40%);">+    cid_value.slen = sprintf(cid_value.ptr, "<%s>", base_cid);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  cid = pjsip_generic_string_hdr_create(tdata->pool, &cid_name, &cid_value);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       pj_list_insert_after(&pidf_part->hdr, cid);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    tdata->msg->body = multipart_body;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  SCOPE_EXIT_RTN_VALUE(0, "%s: PIDF-LO added with cid '%s'\n", session_name, base_cid);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> static void handle_outgoing_request(struct ast_sip_session *session, struct pjsip_tx_data *tdata)</span><br><span> {</span><br><span style="color: hsl(120, 100%, 40%);">+        const char *session_name = ast_sip_session_get_name(session);</span><br><span style="color: hsl(120, 100%, 40%);">+ struct ast_sip_endpoint *endpoint = session->endpoint;</span><br><span style="color: hsl(120, 100%, 40%);">+     struct ast_channel *channel = session->channel;</span><br><span style="color: hsl(120, 100%, 40%);">+    RAII_VAR(struct ast_geoloc_profile *, config_profile, NULL, ao2_cleanup);</span><br><span style="color: hsl(120, 100%, 40%);">+     RAII_VAR(struct ast_geoloc_eprofile *, config_eprofile, NULL, ao2_cleanup);</span><br><span style="color: hsl(120, 100%, 40%);">+   RAII_VAR(struct ast_str *, buf, ast_str_create(1024), ast_free);</span><br><span style="color: hsl(120, 100%, 40%);">+      RAII_VAR(struct ast_datastore *, tempds, NULL, ast_datastore_free);</span><br><span style="color: hsl(120, 100%, 40%);">+   struct ast_datastore *ds = NULL;  /* The channel cleans up ds */</span><br><span style="color: hsl(120, 100%, 40%);">+      struct ast_vector_string uris;</span><br><span style="color: hsl(120, 100%, 40%);">+        pjsip_msg_body *orig_body;</span><br><span style="color: hsl(120, 100%, 40%);">+    pjsip_generic_string_hdr *geoloc_hdr;</span><br><span style="color: hsl(120, 100%, 40%);">+ int i;</span><br><span style="color: hsl(120, 100%, 40%);">+        int eprofile_count = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+       int pidf_index = -1;</span><br><span style="color: hsl(120, 100%, 40%);">+  int geoloc_routing = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+       int rc = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+   const char *final;</span><br><span style="color: hsl(120, 100%, 40%);">+    SCOPE_ENTER(3, "%s\n", session_name);</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+   if (!buf) {</span><br><span style="color: hsl(120, 100%, 40%);">+           SCOPE_EXIT_LOG_RTN(LOG_WARNING, "%s: Unable to allocate buf\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                     session_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%);">+   if (!endpoint) {</span><br><span style="color: hsl(120, 100%, 40%);">+              SCOPE_EXIT_LOG_RTN(LOG_WARNING, "%s: Session has no endpoint.  Skipping.\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                        session_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%);">+   if (!channel) {</span><br><span style="color: hsl(120, 100%, 40%);">+               SCOPE_EXIT_LOG_RTN(LOG_WARNING, "%s: Session has no channel.  Skipping.\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                 session_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%);">+   if (ast_strlen_zero(endpoint->geoloc_outgoing_call_profile)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                     SCOPE_EXIT_LOG_RTN(LOG_NOTICE, "%s: Endpoint has no geoloc_outgoing_call_profile. "</span><br><span style="color: hsl(120, 100%, 40%);">+                         "Skipping.\n", session_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%);">+   config_profile = ast_geoloc_get_profile(endpoint->geoloc_outgoing_call_profile);</span><br><span style="color: hsl(120, 100%, 40%);">+   if (!config_profile) {</span><br><span style="color: hsl(120, 100%, 40%);">+                SCOPE_EXIT_LOG_RTN(LOG_ERROR, "%s: Endpoint's geoloc_outgoing_call_profile doesn't exist. "</span><br><span style="color: hsl(120, 100%, 40%);">+                 "Geolocation info discarded.\n", session_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%);">+   config_eprofile = ast_geoloc_eprofile_create_from_profile(config_profile);</span><br><span style="color: hsl(120, 100%, 40%);">+    if (!config_eprofile) {</span><br><span style="color: hsl(120, 100%, 40%);">+               SCOPE_EXIT_LOG_RTN(LOG_WARNING, "%s: Unable to create eprofile from "</span><br><span style="color: hsl(120, 100%, 40%);">+                       "profile '%s'\n", session_name, ast_sorcery_object_get_id(config_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%);">+   if (config_profile->action != AST_GEOLOC_ACTION_DISCARD) {</span><br><span style="color: hsl(120, 100%, 40%);">+         ds = ast_geoloc_datastore_find(channel);</span><br><span style="color: hsl(120, 100%, 40%);">+              if (!ds) {</span><br><span style="color: hsl(120, 100%, 40%);">+                    ast_trace(4, "%s: There was no geoloc datastore\n", session_name);</span><br><span style="color: hsl(120, 100%, 40%);">+          } else {</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%);">+                       ast_trace(4, "%s: There are %d geoloc profiles on this channel\n", session_name,</span><br><span style="color: hsl(120, 100%, 40%);">+                            eprofile_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%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   /*</span><br><span style="color: hsl(120, 100%, 40%);">+     * We don't want to alter the datastore that may (or may not) be on</span><br><span style="color: hsl(120, 100%, 40%);">+        * the channel so we're going to create a temporary one to hold the</span><br><span style="color: hsl(120, 100%, 40%);">+        * config eprofile plus any in the channel datastore.  Technically</span><br><span style="color: hsl(120, 100%, 40%);">+     * we could just use a vector but the datastore already has the logic</span><br><span style="color: hsl(120, 100%, 40%);">+  * to release all the eprofile references and the datastore itself.</span><br><span style="color: hsl(120, 100%, 40%);">+    */</span><br><span style="color: hsl(120, 100%, 40%);">+   tempds = ast_geoloc_datastore_create("temp");</span><br><span style="color: hsl(120, 100%, 40%);">+       if (!ds) {</span><br><span style="color: hsl(120, 100%, 40%);">+            ast_trace(4, "%s: There are no geoloc profiles on this channel\n", session_name);</span><br><span style="color: hsl(120, 100%, 40%);">+           ast_geoloc_datastore_add_eprofile(tempds, config_eprofile);</span><br><span style="color: hsl(120, 100%, 40%);">+   } else {</span><br><span style="color: hsl(120, 100%, 40%);">+              if (config_profile->action == AST_GEOLOC_ACTION_APPEND) {</span><br><span style="color: hsl(120, 100%, 40%);">+                  ast_trace(4, "%s: prepending config_eprofile\n", session_name);</span><br><span style="color: hsl(120, 100%, 40%);">+                     ast_geoloc_datastore_add_eprofile(tempds, config_eprofile);</span><br><span style="color: hsl(120, 100%, 40%);">+           }</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_geoloc_datastore_get_eprofile(ds, i);</span><br><span style="color: hsl(120, 100%, 40%);">+                    ast_trace(4, "%s: adding eprofile '%s' from channel\n", session_name, ep->id);</span><br><span style="color: hsl(120, 100%, 40%);">+                   ast_geoloc_datastore_add_eprofile(tempds, ep);</span><br><span style="color: hsl(120, 100%, 40%);">+                }</span><br><span style="color: hsl(120, 100%, 40%);">+             if (config_profile->action == AST_GEOLOC_ACTION_PREPEND) {</span><br><span style="color: hsl(120, 100%, 40%);">+                 ast_trace(4, "%s: appending config_eprofile\n", session_name);</span><br><span style="color: hsl(120, 100%, 40%);">+                      ast_geoloc_datastore_add_eprofile(tempds, config_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%);">+   eprofile_count = ast_geoloc_datastore_size(tempds);</span><br><span style="color: hsl(120, 100%, 40%);">+   if (eprofile_count == 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+            SCOPE_EXIT_RTN("%s: There are no profiles left to send\n", session_name);</span><br><span style="color: hsl(120, 100%, 40%);">+   }</span><br><span style="color: hsl(120, 100%, 40%);">+     ast_trace(4, "%s: There are now %d geoloc profiles to be sent\n", session_name,</span><br><span style="color: hsl(120, 100%, 40%);">+             eprofile_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%);">+     * This vector is going to accumulate all of the URIs that</span><br><span style="color: hsl(120, 100%, 40%);">+     * will need to go on the Geolocation header.</span><br><span style="color: hsl(120, 100%, 40%);">+  */</span><br><span style="color: hsl(120, 100%, 40%);">+   rc = AST_VECTOR_INIT(&uris, 2);</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(LOG_ERROR, "%s: Unable to allocate memory for vector\n", session_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%);">+   /*</span><br><span style="color: hsl(120, 100%, 40%);">+     * It's possible that we have a list of eprofiles that have both "pass-by-reference (external URI)"</span><br><span style="color: hsl(120, 100%, 40%);">+      * and "pass by value (to go in PIDF)" eprofiles.  The ones that just need a URI added to the</span><br><span style="color: hsl(120, 100%, 40%);">+        * Geolocation header get added to the "uris" vector in this loop. The ones that result in a</span><br><span style="color: hsl(120, 100%, 40%);">+         * PIDF though, need to be combined into a single PIDF-LO document so we're just going to</span><br><span style="color: hsl(120, 100%, 40%);">+  * save the first one's index so we can insert the "cid" header in the right place, then</span><br><span style="color: hsl(120, 100%, 40%);">+         * we'll send the whole list off to add_pidf_to_tdata() so they can be combined into a</span><br><span style="color: hsl(120, 100%, 40%);">+     * single 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%);">+ for (i = 0; i < eprofile_count; i++) {</span><br><span style="color: hsl(120, 100%, 40%);">+             struct ast_geoloc_eprofile *ep = ast_geoloc_datastore_get_eprofile(tempds, i);</span><br><span style="color: hsl(120, 100%, 40%);">+                ast_geoloc_eprofile_refresh_location(ep);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+           ast_trace(4, "ep: '%s' EffectiveLoc: %s\n", ep->id, ast_str_buffer(</span><br><span style="color: hsl(120, 100%, 40%);">+                      ast_variable_list_join(ep->effective_location, ",", "=", NULL, &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%);">+         if (ep->format == AST_GEOLOC_FORMAT_URI) {</span><br><span style="color: hsl(120, 100%, 40%);">+                 final = ast_geoloc_eprofile_to_uri(ep, channel, &buf, session_name);</span><br><span style="color: hsl(120, 100%, 40%);">+                      ast_trace(4, "URI: %s\n", final);</span><br><span style="color: hsl(120, 100%, 40%);">+                   AST_VECTOR_APPEND(&uris, ast_strdup(final));</span><br><span style="color: hsl(120, 100%, 40%);">+                      ast_str_reset(buf);</span><br><span style="color: hsl(120, 100%, 40%);">+           } else {</span><br><span style="color: hsl(120, 100%, 40%);">+                      /*</span><br><span style="color: hsl(120, 100%, 40%);">+                     * If there are GML or civicAddress eprofiles, we need to save the position</span><br><span style="color: hsl(120, 100%, 40%);">+                    * of the first one in relation to any URI ones so we can insert the "cid"</span><br><span style="color: hsl(120, 100%, 40%);">+                   * uri for it in the original position.</span><br><span style="color: hsl(120, 100%, 40%);">+                        */</span><br><span style="color: hsl(120, 100%, 40%);">+                   if (pidf_index < 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+                              pidf_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%);">+             /* The LAST eprofile determines routing */</span><br><span style="color: hsl(120, 100%, 40%);">+            geoloc_routing = ep->geolocation_routing;</span><br><span 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%);">+     * If we found at least one eprofile needing PIDF processing, we'll</span><br><span style="color: hsl(120, 100%, 40%);">+        * send the entire list off to add_pidf_to_tdata().  We're going to save</span><br><span style="color: hsl(120, 100%, 40%);">+   * the pointer to the original tdata body in case we need to revert</span><br><span style="color: hsl(120, 100%, 40%);">+    * if we can't add the headers.</span><br><span style="color: hsl(120, 100%, 40%);">+    */</span><br><span style="color: hsl(120, 100%, 40%);">+   orig_body = tdata->msg->body;</span><br><span style="color: hsl(120, 100%, 40%);">+   if (pidf_index >= 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+             rc = add_pidf_to_tdata(tempds, channel, &uris, pidf_index, tdata, session_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%);">+   /*</span><br><span style="color: hsl(120, 100%, 40%);">+     * Now that we have all the URIs in the vector, we'll string them together</span><br><span style="color: hsl(120, 100%, 40%);">+         * to create the data for the Geolocation header.</span><br><span style="color: hsl(120, 100%, 40%);">+      */</span><br><span style="color: hsl(120, 100%, 40%);">+   ast_str_reset(buf);</span><br><span style="color: hsl(120, 100%, 40%);">+   for (i = 0; i < AST_VECTOR_SIZE(&uris); i++) {</span><br><span style="color: hsl(120, 100%, 40%);">+         char *uri = AST_VECTOR_GET(&uris, i);</span><br><span style="color: hsl(120, 100%, 40%);">+             ast_trace(4, "ix: %d of %d LocRef: %s\n", i, (int)AST_VECTOR_SIZE(&uris), uri);</span><br><span style="color: hsl(120, 100%, 40%);">+         ast_str_append(&buf, 0, "%s<%s>", (i > 0 ? "," : ""), 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%);">+   AST_VECTOR_RESET(&uris, ast_free);</span><br><span style="color: hsl(120, 100%, 40%);">+        AST_VECTOR_FREE(&uris);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* It's almost impossible for add header to fail but you never know */</span><br><span style="color: hsl(120, 100%, 40%);">+    geoloc_hdr = ast_sip_add_header2(tdata, "Geolocation", ast_str_buffer(buf));</span><br><span style="color: hsl(120, 100%, 40%);">+        if (geoloc_hdr == NULL) {</span><br><span style="color: hsl(120, 100%, 40%);">+             tdata->msg->body = orig_body;</span><br><span style="color: hsl(120, 100%, 40%);">+           SCOPE_EXIT_LOG_RTN(LOG_ERROR, "%s: Unable to add Geolocation header\n", session_name);</span><br><span style="color: hsl(120, 100%, 40%);">+      }</span><br><span style="color: hsl(120, 100%, 40%);">+     rc = ast_sip_add_header(tdata, "Geolocation-Routing", geoloc_routing ? "yes" : "no");</span><br><span style="color: hsl(120, 100%, 40%);">+   if (rc != 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+                tdata->msg->body = orig_body;</span><br><span style="color: hsl(120, 100%, 40%);">+           pj_list_erase(geoloc_hdr);</span><br><span style="color: hsl(120, 100%, 40%);">+            SCOPE_EXIT_LOG_RTN(LOG_ERROR, "%s: Unable to add Geolocation-Routing header\n", session_name);</span><br><span style="color: hsl(120, 100%, 40%);">+      }</span><br><span style="color: hsl(120, 100%, 40%);">+     SCOPE_EXIT_RTN("%s: Geolocation: %s\n", session_name, ast_str_buffer(buf));</span><br><span> }</span><br><span> </span><br><span> static struct ast_sip_session_supplement geolocation_supplement = {</span><br><span></span><br></pre><p>To view, visit <a href="https://gerrit.asterisk.org/c/asterisk/+/18251">change 18251</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/+/18251"/><meta itemprop="name" content="View Change"/></div></div>

<div style="display:none"> Gerrit-Project: asterisk </div>
<div style="display:none"> Gerrit-Branch: development/16/geolocation </div>
<div style="display:none"> Gerrit-Change-Id: Iccb956dd1800204472a21714d06d3b28486e9490 </div>
<div style="display:none"> Gerrit-Change-Number: 18251 </div>
<div style="display:none"> Gerrit-PatchSet: 1 </div>
<div style="display:none"> Gerrit-Owner: George Joseph <gjoseph@digium.com> </div>
<div style="display:none"> Gerrit-MessageType: newchange </div>