<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><note-well></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>