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

</div><pre style="font-family: monospace,monospace; white-space: pre-wrap;">res_pjsip_geolocation:  Initial commit<br><br>* Added two parameters to endpoint: geoloc_incoming_call_profile<br>  and geoloc_outgoing_call_profile.  Alembic included.  res_pjsip<br>  now has a use/optional dependency on res_geolocation for<br>  validation.<br><br>* Added the res_pjsip_geolocation module with support for incoming<br>  calls.<br><br>* Fixed ast_datastore_free so it's tolerant of being passed a<br>  NULL pointer.  This makes it RAII_VAR compatible.<br><br>* Added PJSTR_PRINTF_SPEC and PJSTR_PRINTF_VAR(_v) convenience<br>  macros to res_pjsip.h.<br>  ast_log(LOG_ERROR, "some pjstr value: " PJSTR_PRINTF_SPEC "\n",<br>      PJSTR_PRINTF_VAR(&some_pjstr));<br><br>* Did more renames of functions and files.<br><br>Change-Id: I6ccb5108a5eec060efb8116502fbff3cc63d7554<br>---<br>M configs/samples/pjsip.conf.sample<br>A contrib/ast-db-manage/config/versions/7197536bb68d_geoloc_endpoint_params.py<br>M include/asterisk/res_geolocation.h<br>M include/asterisk/res_pjsip.h<br>M main/datastore.c<br>M res/res_geolocation.c<br>D res/res_geolocation/geoloc_channel.c<br>M res/res_geolocation/geoloc_config.c<br>A res/res_geolocation/geoloc_datastore.c<br>M res/res_geolocation/geoloc_eprofile.c<br>M res/res_pjsip.c<br>M res/res_pjsip/pjsip_config.xml<br>M res/res_pjsip/pjsip_configuration.c<br>A res/res_pjsip_geolocation.c<br>14 files changed, 777 insertions(+), 121 deletions(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;"><span>diff --git a/configs/samples/pjsip.conf.sample b/configs/samples/pjsip.conf.sample</span><br><span>index 8118086..97d1e73 100644</span><br><span>--- a/configs/samples/pjsip.conf.sample</span><br><span>+++ b/configs/samples/pjsip.conf.sample</span><br><span>@@ -898,6 +898,17 @@</span><br><span>                            ; responses.</span><br><span>                            ; (default: no)</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+;geoloc_incoming_call_profile =</span><br><span style="color: hsl(120, 100%, 40%);">+                ; This geolocation profile will be applied to all calls received</span><br><span style="color: hsl(120, 100%, 40%);">+                ; by the channel driver from the remote endpoint before they're</span><br><span style="color: hsl(120, 100%, 40%);">+                ; forwarded to the dialplan.</span><br><span style="color: hsl(120, 100%, 40%);">+;geoloc_outgoing_call_profile =</span><br><span style="color: hsl(120, 100%, 40%);">+                ; This geolocation profile will be applied to all calls received</span><br><span style="color: hsl(120, 100%, 40%);">+                ; by the channel driver from the dialplan before they're forwarded</span><br><span style="color: hsl(120, 100%, 40%);">+                ; the remote endpoint.</span><br><span 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> ;==========================AUTH SECTION OPTIONS=========================</span><br><span> ;[auth]</span><br><span> ;  SYNOPSIS: Authentication type</span><br><span>diff --git a/contrib/ast-db-manage/config/versions/7197536bb68d_geoloc_endpoint_params.py b/contrib/ast-db-manage/config/versions/7197536bb68d_geoloc_endpoint_params.py</span><br><span>new file mode 100644</span><br><span>index 0000000..bf9de50</span><br><span>--- /dev/null</span><br><span>+++ b/contrib/ast-db-manage/config/versions/7197536bb68d_geoloc_endpoint_params.py</span><br><span>@@ -0,0 +1,22 @@</span><br><span style="color: hsl(120, 100%, 40%);">+"""Geoloc Endpoint Params</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+Revision ID: 7197536bb68d</span><br><span style="color: hsl(120, 100%, 40%);">+Revises: 8f72185e437f</span><br><span style="color: hsl(120, 100%, 40%);">+Create Date: 2022-03-07 05:32:54.909429</span><br><span 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%);">+# revision identifiers, used by Alembic.</span><br><span style="color: hsl(120, 100%, 40%);">+revision = '7197536bb68d'</span><br><span style="color: hsl(120, 100%, 40%);">+down_revision = '8f72185e437f'</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+from alembic import op</span><br><span style="color: hsl(120, 100%, 40%);">+import sqlalchemy as sa</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+def upgrade():</span><br><span style="color: hsl(120, 100%, 40%);">+    op.add_column('ps_endpoints', sa.Column('geoloc_incoming_call_profile', sa.String(80)))</span><br><span style="color: hsl(120, 100%, 40%);">+    op.add_column('ps_endpoints', sa.Column('geoloc_outgoing_call_profile', sa.String(80)))</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+def downgrade():</span><br><span style="color: hsl(120, 100%, 40%);">+    op.drop_column('ps_endpoints', 'geoloc_outgoing_call_profile')</span><br><span style="color: hsl(120, 100%, 40%);">+    op.drop_column('ps_endpoints', 'geoloc_incoming_call_profile')</span><br><span>diff --git a/include/asterisk/res_geolocation.h b/include/asterisk/res_geolocation.h</span><br><span>index 7fae4bf..80f1caf 100644</span><br><span>--- a/include/asterisk/res_geolocation.h</span><br><span>+++ b/include/asterisk/res_geolocation.h</span><br><span>@@ -22,6 +22,7 @@</span><br><span> #include "asterisk/sorcery.h"</span><br><span> #include "asterisk/config.h"</span><br><span> #include "asterisk/xml.h"</span><br><span style="color: hsl(120, 100%, 40%);">+#include "asterisk/optional_api.h"</span><br><span> </span><br><span> enum ast_geoloc_pidf_element {</span><br><span>  AST_PIDF_ELEMENT_NONE = 0,</span><br><span>@@ -67,7 +68,7 @@</span><br><span>       struct ast_variable *usage_rules_vars;</span><br><span> };</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-struct ast_geoloc_effective_profile {</span><br><span style="color: hsl(120, 100%, 40%);">+struct ast_geoloc_eprofile {</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>@@ -85,6 +86,34 @@</span><br><span>   struct ast_variable *usage_rules_vars;</span><br><span> };</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+/*!</span><br><span style="color: hsl(120, 100%, 40%);">+ * \brief Check if res_geolocation is available</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \return 1 if available, 0 otherwise.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+AST_OPTIONAL_API(int, ast_geoloc_is_loaded,   (void), { return 0; });</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*!</span><br><span style="color: hsl(120, 100%, 40%);">+ * \brief Retrieve a geolocation location object by id.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param id Location object id.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \return Location object or NULL if not found.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+AST_OPTIONAL_API(struct ast_geoloc_location *, ast_geoloc_get_location,</span><br><span style="color: hsl(120, 100%, 40%);">+              (const char *id),</span><br><span style="color: hsl(120, 100%, 40%);">+             { return NULL; });</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*!</span><br><span style="color: hsl(120, 100%, 40%);">+ * \brief Retrieve a geolocation profile by id.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param id profile id.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \return Profile or NULL if not found.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+AST_OPTIONAL_API(struct ast_geoloc_profile *, ast_geoloc_get_profile,</span><br><span style="color: hsl(120, 100%, 40%);">+            (const char *id),</span><br><span style="color: hsl(120, 100%, 40%);">+             { return NULL; });</span><br><span> </span><br><span> /*!</span><br><span>  * \brief Given an official civicAddress code, return its friendly name.</span><br><span>@@ -164,7 +193,13 @@</span><br><span>  * \return The datastore.</span><br><span>  */</span><br><span> struct ast_datastore *ast_geoloc_datastore_create_from_eprofile(</span><br><span style="color: hsl(0, 100%, 40%);">-       struct ast_geoloc_effective_profile *eprofile);</span><br><span style="color: hsl(120, 100%, 40%);">+       struct ast_geoloc_eprofile *eprofile);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct ast_datastore *ast_geoloc_datastore_create(const char *id);</span><br><span style="color: hsl(120, 100%, 40%);">+int ast_geoloc_datastore_add_eprofile(struct ast_datastore *ds,</span><br><span style="color: hsl(120, 100%, 40%);">+ struct ast_geoloc_eprofile *eprofile);</span><br><span style="color: hsl(120, 100%, 40%);">+int ast_geoloc_datastore_size(struct ast_datastore *ds);</span><br><span style="color: hsl(120, 100%, 40%);">+struct ast_geoloc_eprofile *ast_geoloc_datastore_get_eprofile(struct ast_datastore *ds, int ix);</span><br><span> </span><br><span> /*!</span><br><span>  * \brief Allocate a new, empty effective profile.</span><br><span>@@ -173,7 +208,7 @@</span><br><span>  *</span><br><span>  * \return The effective profile ao2 object.</span><br><span>  */</span><br><span style="color: hsl(0, 100%, 40%);">-struct ast_geoloc_effective_profile *ast_geoloc_eprofile_alloc(const char *name);</span><br><span style="color: hsl(120, 100%, 40%);">+struct ast_geoloc_eprofile *ast_geoloc_eprofile_alloc(const char *name);</span><br><span> </span><br><span> /*!</span><br><span>  * \brief Allocate a new effective profile from an existing profile.</span><br><span>@@ -182,7 +217,7 @@</span><br><span>  *</span><br><span>  * \return The effective profile ao2 object.</span><br><span>  */</span><br><span style="color: hsl(0, 100%, 40%);">-struct ast_geoloc_effective_profile *ast_geoloc_eprofile_create_from_profile(struct ast_geoloc_profile *profile);</span><br><span style="color: hsl(120, 100%, 40%);">+struct ast_geoloc_eprofile *ast_geoloc_eprofile_create_from_profile(struct ast_geoloc_profile *profile);</span><br><span> </span><br><span> /*!</span><br><span>  * \brief Allocate a new effective profile from an XML PIDF-LO document</span><br><span>@@ -192,7 +227,7 @@</span><br><span>  *</span><br><span>  * \return The effective profile ao2 object.</span><br><span>  */</span><br><span style="color: hsl(0, 100%, 40%);">-struct ast_geoloc_effective_profile *ast_geoloc_eprofile_create_from_pidf(</span><br><span style="color: hsl(120, 100%, 40%);">+struct ast_geoloc_eprofile *ast_geoloc_eprofile_create_from_pidf(</span><br><span>     struct ast_xml_doc *pidf_xmldoc, const char *reference_string);</span><br><span> </span><br><span> /*!</span><br><span>@@ -203,7 +238,7 @@</span><br><span>  *</span><br><span>  * \return The effective profile ao2 object.</span><br><span>  */</span><br><span style="color: hsl(0, 100%, 40%);">-struct ast_geoloc_effective_profile *ast_geoloc_eprofile_create_from_uri(const char *uri,</span><br><span style="color: hsl(120, 100%, 40%);">+struct ast_geoloc_eprofile *ast_geoloc_eprofile_create_from_uri(const char *uri,</span><br><span>     const char *reference_string);</span><br><span> </span><br><span> /*!</span><br><span>@@ -213,6 +248,6 @@</span><br><span>  *</span><br><span>  * \return 0 on success, any other value on error.</span><br><span>  */</span><br><span style="color: hsl(0, 100%, 40%);">-int ast_geoloc_eprofile_refresh_location(struct ast_geoloc_effective_profile *eprofile);</span><br><span style="color: hsl(120, 100%, 40%);">+int ast_geoloc_eprofile_refresh_location(struct ast_geoloc_eprofile *eprofile);</span><br><span> </span><br><span> #endif /* INCLUDE_ASTERISK_RES_GEOLOCATION_H_ */</span><br><span>diff --git a/include/asterisk/res_pjsip.h b/include/asterisk/res_pjsip.h</span><br><span>index a4d0607..40e13e2 100644</span><br><span>--- a/include/asterisk/res_pjsip.h</span><br><span>+++ b/include/asterisk/res_pjsip.h</span><br><span>@@ -62,6 +62,9 @@</span><br><span> #define PJSIP_EXPIRES_NOT_SPECIFIED     ((pj_uint32_t)-1)</span><br><span> #endif</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+#define PJSTR_PRINTF_SPEC "%.*s"</span><br><span style="color: hsl(120, 100%, 40%);">+#define PJSTR_PRINTF_VAR(_v) ((int)(_v).slen), ((_v).ptr)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> /* Response codes from RFC8224 */</span><br><span> #define AST_STIR_SHAKEN_RESPONSE_CODE_STALE_DATE 403</span><br><span> #define AST_STIR_SHAKEN_RESPONSE_CODE_USE_IDENTITY_HEADER 428</span><br><span>@@ -871,6 +874,10 @@</span><br><span>        unsigned int stir_shaken;</span><br><span>    /*! Should we authenticate OPTIONS requests per RFC 3261? */</span><br><span>         unsigned int allow_unauthenticated_options;</span><br><span style="color: hsl(120, 100%, 40%);">+   /*! The name of the geoloc profile to apply when Asterisk receives a call from this endpoint */</span><br><span style="color: hsl(120, 100%, 40%);">+       AST_STRING_FIELD_EXTENDED(geoloc_incoming_call_profile);</span><br><span style="color: hsl(120, 100%, 40%);">+      /*! The name of the geoloc profile to apply when Asterisk sends a call to this endpoint */</span><br><span style="color: hsl(120, 100%, 40%);">+    AST_STRING_FIELD_EXTENDED(geoloc_outgoing_call_profile);</span><br><span> };</span><br><span> </span><br><span> /*! URI parameter for symmetric transport */</span><br><span>diff --git a/main/datastore.c b/main/datastore.c</span><br><span>index f37ee6c..d5adfae 100644</span><br><span>--- a/main/datastore.c</span><br><span>+++ b/main/datastore.c</span><br><span>@@ -69,6 +69,10 @@</span><br><span> {</span><br><span>    int res = 0;</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+      if (!datastore) {</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>  /* Using the destroy function (if present) destroy the data */</span><br><span>       if (datastore->info->destroy != NULL && datastore->data != NULL) {</span><br><span>          datastore->info->destroy(datastore->data);</span><br><span>diff --git a/res/res_geolocation.c b/res/res_geolocation.c</span><br><span>index 9108102..19dd84b 100644</span><br><span>--- a/res/res_geolocation.c</span><br><span>+++ b/res/res_geolocation.c</span><br><span>@@ -24,6 +24,8 @@</span><br><span> </span><br><span> </span><br><span> #include "asterisk.h"</span><br><span style="color: hsl(120, 100%, 40%);">+#define AST_API_MODULE</span><br><span style="color: hsl(120, 100%, 40%);">+#include "asterisk/res_geolocation.h"</span><br><span> #include "res_geolocation/geoloc_private.h"</span><br><span> </span><br><span> static int reload_module(void)</span><br><span>diff --git a/res/res_geolocation/geoloc_channel.c b/res/res_geolocation/geoloc_channel.c</span><br><span>deleted file mode 100644</span><br><span>index aa8ad87..0000000</span><br><span>--- a/res/res_geolocation/geoloc_channel.c</span><br><span>+++ /dev/null</span><br><span>@@ -1,93 +0,0 @@</span><br><span style="color: hsl(0, 100%, 40%);">-/*</span><br><span style="color: hsl(0, 100%, 40%);">- * Asterisk -- An open source telephony toolkit.</span><br><span style="color: hsl(0, 100%, 40%);">- *</span><br><span style="color: hsl(0, 100%, 40%);">- * Copyright (C) 2022, Sangoma Technologies Corporation</span><br><span style="color: hsl(0, 100%, 40%);">- *</span><br><span style="color: hsl(0, 100%, 40%);">- * George Joseph <gjoseph@sangoma.com></span><br><span style="color: hsl(0, 100%, 40%);">- *</span><br><span style="color: hsl(0, 100%, 40%);">- * See http://www.asterisk.org for more information about</span><br><span style="color: hsl(0, 100%, 40%);">- * the Asterisk project. Please do not directly contact</span><br><span style="color: hsl(0, 100%, 40%);">- * any of the maintainers of this project for assistance;</span><br><span style="color: hsl(0, 100%, 40%);">- * the project provides a web site, mailing lists and IRC</span><br><span style="color: hsl(0, 100%, 40%);">- * channels for your use.</span><br><span style="color: hsl(0, 100%, 40%);">- *</span><br><span style="color: hsl(0, 100%, 40%);">- * This program is free software, distributed under the terms of</span><br><span style="color: hsl(0, 100%, 40%);">- * the GNU General Public License Version 2. See the LICENSE file</span><br><span style="color: hsl(0, 100%, 40%);">- * at the top of the source tree.</span><br><span style="color: hsl(0, 100%, 40%);">- */</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-#include "asterisk.h"</span><br><span style="color: hsl(0, 100%, 40%);">-#include "asterisk/datastore.h"</span><br><span style="color: hsl(0, 100%, 40%);">-#include "asterisk/res_geolocation.h"</span><br><span style="color: hsl(0, 100%, 40%);">-#include "geoloc_private.h"</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-struct ast_sorcery *geoloc_sorcery;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-static void geoloc_datastore_destructor(void *obj)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">-       struct ast_geoloc_effective_profile *eprofile = obj;</span><br><span style="color: hsl(0, 100%, 40%);">-    ao2_ref(eprofile, -1);</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-static const struct ast_datastore_info geoloc_datastore_info = {</span><br><span style="color: hsl(0, 100%, 40%);">- .type = "geolocation",</span><br><span style="color: hsl(0, 100%, 40%);">-        .destroy = geoloc_datastore_destructor</span><br><span style="color: hsl(0, 100%, 40%);">-};</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-struct ast_datastore *ast_geoloc_datastore_create_from_profile_name(const char *profile_name)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">-  struct ast_datastore *ds = NULL;</span><br><span style="color: hsl(0, 100%, 40%);">-        struct ast_geoloc_effective_profile *eprofile = NULL;</span><br><span style="color: hsl(0, 100%, 40%);">-   struct ast_geoloc_profile *profile = NULL;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-      if (ast_strlen_zero(profile_name)) {</span><br><span style="color: hsl(0, 100%, 40%);">-            return NULL;</span><br><span style="color: hsl(0, 100%, 40%);">-    }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-       ds = ast_datastore_alloc(&geoloc_datastore_info, NULL);</span><br><span style="color: hsl(0, 100%, 40%);">-     if (!ds) {</span><br><span style="color: hsl(0, 100%, 40%);">-              ast_log(LOG_ERROR, "A datasatore couldn't be allocated for profile '%s'", profile_name);</span><br><span style="color: hsl(0, 100%, 40%);">-          return NULL;</span><br><span style="color: hsl(0, 100%, 40%);">-    }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-       profile = ast_sorcery_retrieve_by_id(geoloc_sorcery, "profile", profile_name);</span><br><span style="color: hsl(0, 100%, 40%);">-        if (!profile) {</span><br><span style="color: hsl(0, 100%, 40%);">-         ast_datastore_free(ds);</span><br><span style="color: hsl(0, 100%, 40%);">-         ast_log(LOG_ERROR, "A profile with the name '%s' was not found", profile_name);</span><br><span style="color: hsl(0, 100%, 40%);">-               return NULL;</span><br><span style="color: hsl(0, 100%, 40%);">-    }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-       eprofile = ast_geoloc_eprofile_create_from_profile(profile);</span><br><span style="color: hsl(0, 100%, 40%);">-    ao2_ref(profile, -1);</span><br><span style="color: hsl(0, 100%, 40%);">-   if (!eprofile) {</span><br><span style="color: hsl(0, 100%, 40%);">-                ast_datastore_free(ds);</span><br><span style="color: hsl(0, 100%, 40%);">-         ast_log(LOG_ERROR, "An effective profile with the name '%s' couldn't be allocated", profile_name);</span><br><span style="color: hsl(0, 100%, 40%);">-                return NULL;</span><br><span style="color: hsl(0, 100%, 40%);">-    }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-       ds->data = eprofile;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- return ds;</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-int geoloc_channel_unload(void)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">-     if (geoloc_sorcery) {</span><br><span style="color: hsl(0, 100%, 40%);">-           ast_sorcery_unref(geoloc_sorcery);</span><br><span style="color: hsl(0, 100%, 40%);">-      }</span><br><span style="color: hsl(0, 100%, 40%);">-       return AST_MODULE_LOAD_SUCCESS;</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-int geoloc_channel_load(void)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">-  geoloc_sorcery = geoloc_get_sorcery();</span><br><span style="color: hsl(0, 100%, 40%);">-  return AST_MODULE_LOAD_SUCCESS;</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-int geoloc_channel_reload(void)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">-        return AST_MODULE_LOAD_SUCCESS;</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span>diff --git a/res/res_geolocation/geoloc_config.c b/res/res_geolocation/geoloc_config.c</span><br><span>index b707c89..309df22 100644</span><br><span>--- a/res/res_geolocation/geoloc_config.c</span><br><span>+++ b/res/res_geolocation/geoloc_config.c</span><br><span>@@ -19,8 +19,8 @@</span><br><span> #include "asterisk.h"</span><br><span> #include "asterisk/module.h"</span><br><span> #include "asterisk/cli.h"</span><br><span style="color: hsl(120, 100%, 40%);">+#define AST_API_MODULE</span><br><span> #include "geoloc_private.h"</span><br><span style="color: hsl(0, 100%, 40%);">-#include "asterisk/res_geolocation.h"</span><br><span> </span><br><span> static struct ast_sorcery *geoloc_sorcery;</span><br><span> </span><br><span>@@ -433,7 +433,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(0, 100%, 40%);">-            struct ast_geoloc_effective_profile *eprofile = ast_geoloc_eprofile_create_from_profile(profile);</span><br><span style="color: hsl(120, 100%, 40%);">+             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>            if (!ast_strlen_zero(eprofile->location_reference)) {</span><br><span>@@ -514,6 +514,24 @@</span><br><span>      AST_CLI_DEFINE(geoloc_config_cli_reload, "Reload Geolocation Configuration"),</span><br><span> };</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+struct ast_geoloc_location * AST_OPTIONAL_API_NAME(ast_geoloc_get_location)(const char *id)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+     if (ast_strlen_zero(id)) {</span><br><span style="color: hsl(120, 100%, 40%);">+            return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+  }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   return ast_sorcery_retrieve_by_id(geoloc_sorcery, "location", id);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct ast_geoloc_profile * AST_OPTIONAL_API_NAME(ast_geoloc_get_profile)(const char *id)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+       if (ast_strlen_zero(id)) {</span><br><span style="color: hsl(120, 100%, 40%);">+            return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+  }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   return ast_sorcery_retrieve_by_id(geoloc_sorcery, "profile", id);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> int geoloc_config_reload(void)</span><br><span> {</span><br><span>      if (geoloc_sorcery) {</span><br><span>@@ -589,3 +607,8 @@</span><br><span>  return AST_MODULE_LOAD_SUCCESS;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+int AST_OPTIONAL_API_NAME(ast_geoloc_is_loaded)(void)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+    return 1;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>diff --git a/res/res_geolocation/geoloc_datastore.c b/res/res_geolocation/geoloc_datastore.c</span><br><span>new file mode 100644</span><br><span>index 0000000..17e2847</span><br><span>--- /dev/null</span><br><span>+++ b/res/res_geolocation/geoloc_datastore.c</span><br><span>@@ -0,0 +1,219 @@</span><br><span style="color: hsl(120, 100%, 40%);">+/*</span><br><span style="color: hsl(120, 100%, 40%);">+ * Asterisk -- An open source telephony toolkit.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * Copyright (C) 2022, Sangoma Technologies Corporation</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * George Joseph <gjoseph@sangoma.com></span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * See http://www.asterisk.org for more information about</span><br><span style="color: hsl(120, 100%, 40%);">+ * the Asterisk project. Please do not directly contact</span><br><span style="color: hsl(120, 100%, 40%);">+ * any of the maintainers of this project for assistance;</span><br><span style="color: hsl(120, 100%, 40%);">+ * the project provides a web site, mailing lists and IRC</span><br><span style="color: hsl(120, 100%, 40%);">+ * channels for your use.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * This program is free software, distributed under the terms of</span><br><span style="color: hsl(120, 100%, 40%);">+ * the GNU General Public License Version 2. See the LICENSE file</span><br><span style="color: hsl(120, 100%, 40%);">+ * at the top of the source tree.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include "asterisk.h"</span><br><span style="color: hsl(120, 100%, 40%);">+#include "asterisk/astobj2.h"</span><br><span style="color: hsl(120, 100%, 40%);">+#include "asterisk/datastore.h"</span><br><span style="color: hsl(120, 100%, 40%);">+#include "asterisk/res_geolocation.h"</span><br><span style="color: hsl(120, 100%, 40%);">+#include "asterisk/vector.h"</span><br><span style="color: hsl(120, 100%, 40%);">+#include "geoloc_private.h"</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#define GEOLOC_DS_TYPE "geoloc_eprofiles"</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct ast_sorcery *geoloc_sorcery;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct eprofiles_datastore {</span><br><span style="color: hsl(120, 100%, 40%);">+  const char *id;</span><br><span style="color: hsl(120, 100%, 40%);">+       AST_VECTOR(geoloc_eprofiles, struct ast_geoloc_eprofile *) eprofiles;</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static void geoloc_datastore_free(void *obj)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  struct eprofiles_datastore *eds = obj;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      AST_VECTOR_RESET(&eds->eprofiles, ao2_cleanup);</span><br><span style="color: hsl(120, 100%, 40%);">+        AST_VECTOR_FREE(&eds->eprofiles);</span><br><span style="color: hsl(120, 100%, 40%);">+      ast_free(eds);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static const struct ast_datastore_info geoloc_datastore_info = {</span><br><span style="color: hsl(120, 100%, 40%);">+ .type = GEOLOC_DS_TYPE,</span><br><span style="color: hsl(120, 100%, 40%);">+       .destroy = geoloc_datastore_free</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct ast_datastore *ast_geoloc_datastore_create(const char *id)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  struct ast_datastore *ds = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+      struct eprofiles_datastore *eds = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+       int rc = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (ast_strlen_zero(id)) {</span><br><span style="color: hsl(120, 100%, 40%);">+            ast_log(LOG_ERROR, "A geoloc datastore can't be allocated with a NULL or empty id\n");</span><br><span style="color: hsl(120, 100%, 40%);">+          return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+  }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   ds = ast_datastore_alloc(&geoloc_datastore_info, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+   if (!ds) {</span><br><span style="color: hsl(120, 100%, 40%);">+            ast_log(LOG_ERROR, "Geoloc datastore '%s' couldn't be allocated\n", id);</span><br><span style="color: hsl(120, 100%, 40%);">+                return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+  }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   eds = ast_calloc(1, sizeof(*eds));</span><br><span style="color: hsl(120, 100%, 40%);">+    if (!eds) {</span><br><span style="color: hsl(120, 100%, 40%);">+           ast_datastore_free(ds);</span><br><span style="color: hsl(120, 100%, 40%);">+               ast_log(LOG_ERROR, "Private structure for geoloc datastore '%s' couldn't be allocated\n", id);</span><br><span style="color: hsl(120, 100%, 40%);">+          return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+  }</span><br><span style="color: hsl(120, 100%, 40%);">+     ds->data = eds;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        rc = AST_VECTOR_INIT(&eds->eprofiles, 2);</span><br><span style="color: hsl(120, 100%, 40%);">+      if (rc != 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+                ast_datastore_free(ds);</span><br><span style="color: hsl(120, 100%, 40%);">+               ast_log(LOG_ERROR, "Vector for geoloc datastore '%s' couldn't be initialized\n", id);</span><br><span style="color: hsl(120, 100%, 40%);">+           return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+  }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   return ds;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+int ast_geoloc_datastore_add_eprofile(struct ast_datastore *ds,</span><br><span style="color: hsl(120, 100%, 40%);">+      struct ast_geoloc_eprofile *eprofile)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+      struct eprofiles_datastore *eds = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+       int rc = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!ds || !ast_strings_equal(ds->info->type, GEOLOC_DS_TYPE) || !ds->data || !eprofile) {</span><br><span style="color: hsl(120, 100%, 40%);">+           return -1;</span><br><span style="color: hsl(120, 100%, 40%);">+    }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   eds = ds->data;</span><br><span style="color: hsl(120, 100%, 40%);">+    rc = AST_VECTOR_APPEND(&eds->eprofiles, eprofile);</span><br><span style="color: hsl(120, 100%, 40%);">+     if (rc != 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+                ast_log(LOG_ERROR, "Couldn't add eprofile '%s' to geoloc datastore '%s'\n", eprofile->id, eds->id);</span><br><span style="color: hsl(120, 100%, 40%);">+       }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   return rc;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+int ast_geoloc_datastore_size(struct ast_datastore *ds)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+   struct eprofiles_datastore *eds = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     if (!ds || !ast_strings_equal(ds->info->type, GEOLOC_DS_TYPE) || !ds->data) {</span><br><span style="color: hsl(120, 100%, 40%);">+                return -1;</span><br><span style="color: hsl(120, 100%, 40%);">+    }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   eds = ds->data;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  return AST_VECTOR_SIZE(&eds->eprofiles);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct ast_geoloc_eprofile *ast_geoloc_datastore_get_eprofile(struct ast_datastore *ds, int ix)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+      struct eprofiles_datastore *eds = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+       struct ast_geoloc_eprofile *eprofile;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       if (!ds || !ast_strings_equal(ds->info->type, GEOLOC_DS_TYPE) || !ds->data) {</span><br><span style="color: hsl(120, 100%, 40%);">+                return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+  }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   eds = ds->data;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  if (ix >= AST_VECTOR_SIZE(&eds->eprofiles)) {</span><br><span style="color: hsl(120, 100%, 40%);">+               return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+  }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   eprofile  = AST_VECTOR_GET(&eds->eprofiles, ix);</span><br><span style="color: hsl(120, 100%, 40%);">+       return ao2_bump(eprofile);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct ast_datastore *ast_geoloc_datastore_create_from_eprofile(</span><br><span style="color: hsl(120, 100%, 40%);">+     struct ast_geoloc_eprofile *eprofile)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+      struct ast_datastore *ds;</span><br><span style="color: hsl(120, 100%, 40%);">+     int rc = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!eprofile) {</span><br><span style="color: hsl(120, 100%, 40%);">+              return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+  }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   ds = ast_geoloc_datastore_create(eprofile->id);</span><br><span style="color: hsl(120, 100%, 40%);">+    if (!ds) {</span><br><span style="color: hsl(120, 100%, 40%);">+            return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+  }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   rc = ast_geoloc_datastore_add_eprofile(ds, eprofile);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (rc != 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+                ast_datastore_free(ds);</span><br><span style="color: hsl(120, 100%, 40%);">+               ds = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+    }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   return ds;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct ast_datastore *ast_geoloc_datastore_create_from_profile_name(const char *profile_name)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+     struct ast_datastore *ds = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+      struct ast_geoloc_eprofile *eprofile = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+  struct ast_geoloc_profile *profile = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+    int rc = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (ast_strlen_zero(profile_name)) {</span><br><span style="color: hsl(120, 100%, 40%);">+          return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+  }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   profile = ast_sorcery_retrieve_by_id(geoloc_sorcery, "profile", profile_name);</span><br><span style="color: hsl(120, 100%, 40%);">+      if (!profile) {</span><br><span style="color: hsl(120, 100%, 40%);">+               ast_log(LOG_ERROR, "A profile with the name '%s' was not found\n", profile_name);</span><br><span style="color: hsl(120, 100%, 40%);">+           return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+  }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   ds = ast_geoloc_datastore_create(profile_name);</span><br><span style="color: hsl(120, 100%, 40%);">+       if (!ds) {</span><br><span style="color: hsl(120, 100%, 40%);">+            ast_log(LOG_ERROR, "A datasatore couldn't be allocated for profile '%s'\n", profile_name);</span><br><span style="color: hsl(120, 100%, 40%);">+              ao2_ref(profile, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+         return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+  }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   eprofile = ast_geoloc_eprofile_create_from_profile(profile);</span><br><span style="color: hsl(120, 100%, 40%);">+  ao2_ref(profile, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!eprofile) {</span><br><span style="color: hsl(120, 100%, 40%);">+              ast_datastore_free(ds);</span><br><span style="color: hsl(120, 100%, 40%);">+               ast_log(LOG_ERROR, "An effective profile with the name '%s' couldn't be allocated\n", profile_name);</span><br><span style="color: hsl(120, 100%, 40%);">+            return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+  }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   rc = ast_geoloc_datastore_add_eprofile(ds, eprofile);</span><br><span style="color: hsl(120, 100%, 40%);">+ ao2_ref(eprofile, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+        if (rc != 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+                ast_datastore_free(ds);</span><br><span style="color: hsl(120, 100%, 40%);">+               ds = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+    }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   return ds;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+int geoloc_channel_unload(void)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+   if (geoloc_sorcery) {</span><br><span style="color: hsl(120, 100%, 40%);">+         ast_sorcery_unref(geoloc_sorcery);</span><br><span style="color: hsl(120, 100%, 40%);">+    }</span><br><span style="color: hsl(120, 100%, 40%);">+     return AST_MODULE_LOAD_SUCCESS;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+int geoloc_channel_load(void)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+        geoloc_sorcery = geoloc_get_sorcery();</span><br><span style="color: hsl(120, 100%, 40%);">+        return AST_MODULE_LOAD_SUCCESS;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+int geoloc_channel_reload(void)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+      return AST_MODULE_LOAD_SUCCESS;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span>diff --git a/res/res_geolocation/geoloc_eprofile.c b/res/res_geolocation/geoloc_eprofile.c</span><br><span>index b6641c7..3ea0d7d 100644</span><br><span>--- a/res/res_geolocation/geoloc_eprofile.c</span><br><span>+++ b/res/res_geolocation/geoloc_eprofile.c</span><br><span>@@ -32,8 +32,8 @@</span><br><span> </span><br><span> static struct ast_sorcery *geoloc_sorcery;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-static void geoloc_effective_profile_destructor(void *obj) {</span><br><span style="color: hsl(0, 100%, 40%);">-       struct ast_geoloc_effective_profile *eprofile = obj;</span><br><span style="color: hsl(120, 100%, 40%);">+static void geoloc_eprofile_destructor(void *obj) {</span><br><span style="color: hsl(120, 100%, 40%);">+     struct ast_geoloc_eprofile *eprofile = obj;</span><br><span> </span><br><span>      ast_string_field_free_memory(eprofile);</span><br><span>      ast_variables_destroy(eprofile->location_vars);</span><br><span>@@ -43,10 +43,10 @@</span><br><span>     ast_variables_destroy(eprofile->usage_rules_vars);</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-struct ast_geoloc_effective_profile *ast_geoloc_eprofile_alloc(const char *name)</span><br><span style="color: hsl(120, 100%, 40%);">+struct ast_geoloc_eprofile *ast_geoloc_eprofile_alloc(const char *name)</span><br><span> {</span><br><span style="color: hsl(0, 100%, 40%);">-    struct ast_geoloc_effective_profile *eprofile = ao2_alloc_options(sizeof(*eprofile),</span><br><span style="color: hsl(0, 100%, 40%);">-            geoloc_effective_profile_destructor, AO2_ALLOC_OPT_LOCK_NOLOCK);</span><br><span style="color: hsl(120, 100%, 40%);">+      struct ast_geoloc_eprofile *eprofile = ao2_alloc_options(sizeof(*eprofile),</span><br><span style="color: hsl(120, 100%, 40%);">+           geoloc_eprofile_destructor, AO2_ALLOC_OPT_LOCK_NOLOCK);</span><br><span> </span><br><span>  ast_string_field_init(eprofile, 256);</span><br><span>        ast_string_field_set(eprofile, id, name); /* SAFE string fields handle NULL */</span><br><span>@@ -54,7 +54,7 @@</span><br><span>   return eprofile;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-int ast_geoloc_eprofile_refresh_location(struct ast_geoloc_effective_profile *eprofile)</span><br><span style="color: hsl(120, 100%, 40%);">+int ast_geoloc_eprofile_refresh_location(struct ast_geoloc_eprofile *eprofile)</span><br><span> {</span><br><span>        struct ast_geoloc_location *loc = NULL;</span><br><span>      struct ast_variable *var;</span><br><span>@@ -68,13 +68,16 @@</span><br><span>              }</span><br><span> </span><br><span>                eprofile->format = loc->format;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>              ast_variables_destroy(eprofile->location_vars);</span><br><span style="color: hsl(0, 100%, 40%);">-              eprofile->location_vars = ast_variables_dup(loc->location_vars);</span><br><span style="color: hsl(120, 100%, 40%);">+                eprofile->location_vars = loc->location_vars ? ast_variables_dup(loc->location_vars) : NULL;</span><br><span>                ao2_ref(loc, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+             loc = NULL;</span><br><span>  }</span><br><span> </span><br><span>        ast_variables_destroy(eprofile->effective_location);</span><br><span style="color: hsl(0, 100%, 40%);">- eprofile->effective_location = ast_variables_dup(eprofile->location_vars);</span><br><span style="color: hsl(120, 100%, 40%);">+      eprofile->effective_location = eprofile->location_vars ? ast_variables_dup(eprofile->location_vars) : NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>       if (eprofile->location_refinement) {</span><br><span>              for (var = eprofile->location_refinement; var; var = var->next) {</span><br><span>                      struct ast_variable *newvar = ast_variable_new(var->name, var->value, "");</span><br><span>@@ -101,9 +104,9 @@</span><br><span>     (_rc); \</span><br><span> })</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-struct ast_geoloc_effective_profile *ast_geoloc_eprofile_create_from_profile(struct ast_geoloc_profile *profile)</span><br><span style="color: hsl(120, 100%, 40%);">+struct ast_geoloc_eprofile *ast_geoloc_eprofile_create_from_profile(struct ast_geoloc_profile *profile)</span><br><span> {</span><br><span style="color: hsl(0, 100%, 40%);">-        struct ast_geoloc_effective_profile *eprofile;</span><br><span style="color: hsl(120, 100%, 40%);">+        struct ast_geoloc_eprofile *eprofile;</span><br><span>        const char *profile_id;</span><br><span>      int rc = 0;</span><br><span> </span><br><span>@@ -148,10 +151,10 @@</span><br><span>      return eprofile;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-struct ast_geoloc_effective_profile *ast_geoloc_eprofile_create_from_uri(const char *uri,</span><br><span style="color: hsl(120, 100%, 40%);">+struct ast_geoloc_eprofile *ast_geoloc_eprofile_create_from_uri(const char *uri,</span><br><span>         const char *reference_string)</span><br><span> {</span><br><span style="color: hsl(0, 100%, 40%);">-      struct ast_geoloc_effective_profile *eprofile = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct ast_geoloc_eprofile *eprofile = NULL;</span><br><span>         char *local_uri;</span><br><span> </span><br><span>         if (ast_strlen_zero(uri)) {</span><br><span>@@ -178,11 +181,11 @@</span><br><span>  return eprofile;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-static struct ast_geoloc_effective_profile *geoloc_eprofile_create_from_xslt_result(</span><br><span style="color: hsl(120, 100%, 40%);">+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> {</span><br><span style="color: hsl(0, 100%, 40%);">-      struct ast_geoloc_effective_profile *eprofile;</span><br><span style="color: hsl(120, 100%, 40%);">+        struct ast_geoloc_eprofile *eprofile;</span><br><span>        struct ast_xml_node *presence = NULL;</span><br><span>        struct ast_xml_node *pidf_element = NULL;</span><br><span>    struct ast_xml_node *location_info = NULL;</span><br><span>@@ -241,11 +244,11 @@</span><br><span>   return eprofile;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-struct ast_geoloc_effective_profile *ast_geoloc_eprofile_create_from_pidf(</span><br><span style="color: hsl(120, 100%, 40%);">+struct ast_geoloc_eprofile *ast_geoloc_eprofile_create_from_pidf(</span><br><span>       struct ast_xml_doc *pidf_xmldoc, const char *reference_string)</span><br><span> {</span><br><span>  RAII_VAR(struct ast_xml_doc *, result_doc, NULL, ast_xml_close);</span><br><span style="color: hsl(0, 100%, 40%);">-        struct ast_geoloc_effective_profile *eprofile;</span><br><span style="color: hsl(120, 100%, 40%);">+        struct ast_geoloc_eprofile *eprofile;</span><br><span> </span><br><span>    /*</span><br><span>    * The namespace prefixes used here (dm, def, gp, etc) don't have to match</span><br><span>@@ -361,7 +364,7 @@</span><br><span> AST_TEST_DEFINE(test_create_from_uri)</span><br><span> {</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-  RAII_VAR(struct ast_geoloc_effective_profile *, eprofile,  NULL, ao2_cleanup);</span><br><span style="color: hsl(120, 100%, 40%);">+        RAII_VAR(struct ast_geoloc_eprofile *, eprofile,  NULL, ao2_cleanup);</span><br><span>        const char *uri = NULL;</span><br><span>      int rc = AST_TEST_PASS;</span><br><span> </span><br><span>@@ -399,7 +402,7 @@</span><br><span>    )</span><br><span> {</span><br><span>       RAII_VAR(struct ast_str *, str, NULL, ast_free);</span><br><span style="color: hsl(0, 100%, 40%);">-        RAII_VAR(struct ast_geoloc_effective_profile *, eprofile,  NULL, ao2_cleanup);</span><br><span style="color: hsl(120, 100%, 40%);">+        RAII_VAR(struct ast_geoloc_eprofile *, eprofile,  NULL, ao2_cleanup);</span><br><span>        RAII_VAR(struct ast_xml_doc *, result_doc, NULL, ast_xml_close);</span><br><span>     const char *search[] = { "path", path, NULL };</span><br><span> </span><br><span>diff --git a/res/res_pjsip.c b/res/res_pjsip.c</span><br><span>index 1e41360..8900964 100644</span><br><span>--- a/res/res_pjsip.c</span><br><span>+++ b/res/res_pjsip.c</span><br><span>@@ -53,6 +53,7 @@</span><br><span>    <depend>res_sorcery_memory</depend></span><br><span>      <depend>res_sorcery_astdb</depend></span><br><span>       <use type="module">res_statsd</use></span><br><span style="color: hsl(120, 100%, 40%);">+     <use type="module">res_geolocation</use></span><br><span>       <support_level>core</support_level></span><br><span>  ***/</span><br><span> </span><br><span>@@ -2714,5 +2715,5 @@</span><br><span>         .reload = reload_module,</span><br><span>     .load_pri = AST_MODPRI_CHANNEL_DEPEND - 5,</span><br><span>   .requires = "dnsmgr,res_pjproject,res_sorcery_config,res_sorcery_memory,res_sorcery_astdb",</span><br><span style="color: hsl(0, 100%, 40%);">-   .optional_modules = "res_statsd",</span><br><span style="color: hsl(120, 100%, 40%);">+   .optional_modules = "res_geolocation,res_statsd",</span><br><span> );</span><br><span>diff --git a/res/res_pjsip/pjsip_config.xml b/res/res_pjsip/pjsip_config.xml</span><br><span>index 6470ab6..0f7b5c5 100644</span><br><span>--- a/res/res_pjsip/pjsip_config.xml</span><br><span>+++ b/res/res_pjsip/pjsip_config.xml</span><br><span>@@ -1135,6 +1135,24 @@</span><br><span>                                              responses.</para></span><br><span>                                      </description></span><br><span>                                 </configOption></span><br><span style="color: hsl(120, 100%, 40%);">+                         <configOption name="geoloc_incoming_call_profile" default=""></span><br><span style="color: hsl(120, 100%, 40%);">+                                       <synopsis>Geolocation profile to apply to incoming calls</synopsis></span><br><span style="color: hsl(120, 100%, 40%);">+                                       <description><para></span><br><span style="color: hsl(120, 100%, 40%);">+                                               This geolocation profile will be applied to all calls received</span><br><span style="color: hsl(120, 100%, 40%);">+                                                by the channel driver from the remote endpoint before they're</span><br><span style="color: hsl(120, 100%, 40%);">+                                             forwarded to the dialplan.</span><br><span style="color: hsl(120, 100%, 40%);">+                                            </para></span><br><span style="color: hsl(120, 100%, 40%);">+                                 </description></span><br><span style="color: hsl(120, 100%, 40%);">+                          </configOption></span><br><span style="color: hsl(120, 100%, 40%);">+                         <configOption name="geoloc_outgoing_call_profile" default=""></span><br><span style="color: hsl(120, 100%, 40%);">+                                       <synopsis>Geolocation profile to apply to outgoing calls</synopsis></span><br><span style="color: hsl(120, 100%, 40%);">+                                       <description><para></span><br><span style="color: hsl(120, 100%, 40%);">+                                               This geolocation profile will be applied to all calls received</span><br><span style="color: hsl(120, 100%, 40%);">+                                                by the channel driver from the dialplan before they're forwarded</span><br><span style="color: hsl(120, 100%, 40%);">+                                          the remote endpoint.</span><br><span style="color: hsl(120, 100%, 40%);">+                                          </para></span><br><span style="color: hsl(120, 100%, 40%);">+                                 </description></span><br><span style="color: hsl(120, 100%, 40%);">+                          </configOption></span><br><span>                        </configObject></span><br><span>                        <configObject name="auth"></span><br><span>                           <synopsis>Authentication type</synopsis></span><br><span>diff --git a/res/res_pjsip/pjsip_configuration.c b/res/res_pjsip/pjsip_configuration.c</span><br><span>index eccc639..70d2a19 100644</span><br><span>--- a/res/res_pjsip/pjsip_configuration.c</span><br><span>+++ b/res/res_pjsip/pjsip_configuration.c</span><br><span>@@ -21,6 +21,7 @@</span><br><span> #include <pjsip.h></span><br><span> #include <pjsip_ua.h></span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+#include "asterisk/res_geolocation.h"</span><br><span> #include "asterisk/res_pjsip.h"</span><br><span> #include "include/res_pjsip_private.h"</span><br><span> #include "asterisk/res_pjsip_cli.h"</span><br><span>@@ -1370,6 +1371,36 @@</span><br><span>                 }</span><br><span>    }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+ if (!ast_strlen_zero(endpoint->geoloc_incoming_call_profile) ||</span><br><span style="color: hsl(120, 100%, 40%);">+            !ast_strlen_zero(endpoint->geoloc_outgoing_call_profile)) {</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+              if (!ast_geoloc_is_loaded()) {</span><br><span style="color: hsl(120, 100%, 40%);">+                        ast_log(LOG_ERROR, "A geoloc incoming and/or outgoing call_profile was specified on endpoint '%s'"</span><br><span style="color: hsl(120, 100%, 40%);">+                          " but res_geolocation is not loaded.\n", ast_sorcery_object_get_id(endpoint));</span><br><span style="color: hsl(120, 100%, 40%);">+                      return -1;</span><br><span style="color: hsl(120, 100%, 40%);">+            }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+           if (!ast_strlen_zero(endpoint->geoloc_incoming_call_profile)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                    struct ast_geoloc_profile *profile = ast_geoloc_get_profile(endpoint->geoloc_incoming_call_profile);</span><br><span style="color: hsl(120, 100%, 40%);">+                       if (!profile) {</span><br><span style="color: hsl(120, 100%, 40%);">+                               ast_log(LOG_ERROR, "geoloc_incoming_call_profile '%s' on endpoint '%s' doesn't exist\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                                        endpoint->geoloc_incoming_call_profile, ast_sorcery_object_get_id(endpoint));</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%);">+                     ao2_cleanup(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 (!ast_strlen_zero(endpoint->geoloc_outgoing_call_profile)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                    struct ast_geoloc_profile *profile = ast_geoloc_get_profile(endpoint->geoloc_outgoing_call_profile);</span><br><span style="color: hsl(120, 100%, 40%);">+                       if (!profile) {</span><br><span style="color: hsl(120, 100%, 40%);">+                               ast_log(LOG_ERROR, "geoloc_outgoing_call_profile '%s' on endpoint '%s' doesn't exist\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                                        endpoint->geoloc_outgoing_call_profile, ast_sorcery_object_get_id(endpoint));</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%);">+                     ao2_cleanup(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%);">+</span><br><span>  return 0;</span><br><span> }</span><br><span> </span><br><span>@@ -2008,6 +2039,8 @@</span><br><span>   ast_sorcery_object_field_register(sip_sorcery, "endpoint", "ignore_183_without_sdp", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, ignore_183_without_sdp));</span><br><span>    ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "stir_shaken", "off", stir_shaken_handler, stir_shaken_to_str, NULL, 0, 0);</span><br><span>  ast_sorcery_object_field_register(sip_sorcery, "endpoint", "allow_unauthenticated_options", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, allow_unauthenticated_options));</span><br><span style="color: hsl(120, 100%, 40%);">+       ast_sorcery_object_field_register(sip_sorcery, "endpoint", "geoloc_incoming_call_profile", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_endpoint, geoloc_incoming_call_profile));</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_sorcery_object_field_register(sip_sorcery, "endpoint", "geoloc_outgoing_call_profile", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_endpoint, geoloc_outgoing_call_profile));</span><br><span> </span><br><span>    if (ast_sip_initialize_sorcery_transport()) {</span><br><span>                ast_log(LOG_ERROR, "Failed to register SIP transport support with sorcery\n");</span><br><span>@@ -2168,6 +2201,12 @@</span><br><span>            return NULL;</span><br><span>         }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+ if (ast_string_field_init_extended(endpoint, geoloc_incoming_call_profile) ||</span><br><span style="color: hsl(120, 100%, 40%);">+         ast_string_field_init_extended(endpoint, geoloc_outgoing_call_profile)) {</span><br><span style="color: hsl(120, 100%, 40%);">+             ao2_cleanup(endpoint);</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>  if (!(endpoint->media.codecs = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT))) {</span><br><span>              ao2_cleanup(endpoint);</span><br><span>               return NULL;</span><br><span>diff --git a/res/res_pjsip_geolocation.c b/res/res_pjsip_geolocation.c</span><br><span>new file mode 100644</span><br><span>index 0000000..cd8ba79</span><br><span>--- /dev/null</span><br><span>+++ b/res/res_pjsip_geolocation.c</span><br><span>@@ -0,0 +1,365 @@</span><br><span style="color: hsl(120, 100%, 40%);">+/*</span><br><span style="color: hsl(120, 100%, 40%);">+ * Asterisk -- An open source telephony toolkit.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * Copyright (C) 2022, Sangoma Technologies Corporation</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * George Joseph <gjoseph@sangoma.com></span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * See http://www.asterisk.org for more information about</span><br><span style="color: hsl(120, 100%, 40%);">+ * the Asterisk project. Please do not directly contact</span><br><span style="color: hsl(120, 100%, 40%);">+ * any of the maintainers of this project for assistance;</span><br><span style="color: hsl(120, 100%, 40%);">+ * the project provides a web site, mailing lists and IRC</span><br><span style="color: hsl(120, 100%, 40%);">+ * channels for your use.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * This program is free software, distributed under the terms of</span><br><span style="color: hsl(120, 100%, 40%);">+ * the GNU General Public License Version 2. See the LICENSE file</span><br><span style="color: hsl(120, 100%, 40%);">+ * at the top of the source tree.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*** MODULEINFO</span><br><span style="color: hsl(120, 100%, 40%);">+       <depend>res_geolocation</depend></span><br><span style="color: hsl(120, 100%, 40%);">+  <depend>pjproject</depend></span><br><span style="color: hsl(120, 100%, 40%);">+        <depend>res_pjsip</depend></span><br><span style="color: hsl(120, 100%, 40%);">+        <depend>res_pjsip_session</depend></span><br><span style="color: hsl(120, 100%, 40%);">+        <depend>chan_pjsip</depend></span><br><span style="color: hsl(120, 100%, 40%);">+       <depend>libxml2</depend></span><br><span style="color: hsl(120, 100%, 40%);">+  <support_level>core</support_level></span><br><span style="color: hsl(120, 100%, 40%);">+ ***/</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include "asterisk.h"</span><br><span style="color: hsl(120, 100%, 40%);">+#include "asterisk/module.h"</span><br><span style="color: hsl(120, 100%, 40%);">+#include "asterisk/xml.h"</span><br><span style="color: hsl(120, 100%, 40%);">+#include "asterisk/res_geolocation.h"</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include <pjsip_ua.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include "asterisk/res_pjsip.h"</span><br><span style="color: hsl(120, 100%, 40%);">+#include "asterisk/res_pjsip_session.h"</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static pj_str_t GEOLOCATION_HDR;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static int find_pidf(const char *session_name, struct pjsip_rx_data *rdata, char *geoloc_uri,</span><br><span style="color: hsl(120, 100%, 40%);">+     char **pidf_body, unsigned int *pidf_len)</span><br><span 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 the URI is "cid" then we're going to search for a pidf document</span><br><span style="color: hsl(120, 100%, 40%);">+    * in the body of the message.  If there's no body, there's no point.</span><br><span style="color: hsl(120, 100%, 40%);">+  */</span><br><span style="color: hsl(120, 100%, 40%);">+   if (!rdata->msg_info.msg->body) {</span><br><span style="color: hsl(120, 100%, 40%);">+               ast_log(LOG_WARNING, "%s: There's no message body in which to search for '%s'.  Skipping\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                    session_name, geoloc_uri);</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%);">+     * If the message content type is 'application/pidf+xml', then the pidf is</span><br><span style="color: hsl(120, 100%, 40%);">+     * the only document in the message and we'll just parse the entire body</span><br><span style="color: hsl(120, 100%, 40%);">+   * as xml.  If it's 'multipart/mixed' then we have to find the part that</span><br><span style="color: hsl(120, 100%, 40%);">+   * has a Content-ID heder value matching the URI.</span><br><span style="color: hsl(120, 100%, 40%);">+      */</span><br><span style="color: hsl(120, 100%, 40%);">+   if (ast_sip_are_media_types_equal(&rdata->msg_info.ctype->media,</span><br><span style="color: hsl(120, 100%, 40%);">+            &pjsip_media_type_application_pidf_xml)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                *pidf_body = rdata->msg_info.msg->body->data;</span><br><span style="color: hsl(120, 100%, 40%);">+                *pidf_len = rdata->msg_info.msg->body->len;</span><br><span style="color: hsl(120, 100%, 40%);">+  } else if (ast_sip_are_media_types_equal(&rdata->msg_info.ctype->media,</span><br><span style="color: hsl(120, 100%, 40%);">+             &pjsip_media_type_multipart_mixed)) {</span><br><span style="color: hsl(120, 100%, 40%);">+             pj_str_t cid = pj_str(geoloc_uri);</span><br><span style="color: hsl(120, 100%, 40%);">+            pjsip_multipart_part *mp = pjsip_multipart_find_part_by_cid_str(</span><br><span style="color: hsl(120, 100%, 40%);">+                      rdata->tp_info.pool, rdata->msg_info.msg->body, &cid);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+         if (!mp) {</span><br><span style="color: hsl(120, 100%, 40%);">+                    ast_log(LOG_WARNING, "%s: A Geolocation header was found with URI '%s'"</span><br><span style="color: hsl(120, 100%, 40%);">+                             " but the associated multipart part was not found in the message body.  Skipping URI",</span><br><span style="color: hsl(120, 100%, 40%);">+                              session_name, geoloc_uri);</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%);">+             *pidf_body = mp->body->data;</span><br><span style="color: hsl(120, 100%, 40%);">+            *pidf_len = mp->body->len;</span><br><span style="color: hsl(120, 100%, 40%);">+      } else {</span><br><span style="color: hsl(120, 100%, 40%);">+              ast_log(LOG_WARNING, "%s: A Geolocation header was found with URI '%s'"</span><br><span style="color: hsl(120, 100%, 40%);">+                     " but no pidf document with that content id was found.  Skipping URI",</span><br><span style="color: hsl(120, 100%, 40%);">+                      session_name, geoloc_uri);</span><br><span style="color: hsl(120, 100%, 40%);">+            return -1;</span><br><span style="color: hsl(120, 100%, 40%);">+    }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static int handle_incoming_request(struct ast_sip_session *session, struct pjsip_rx_data *rdata)</span><br><span style="color: hsl(120, 100%, 40%);">+{</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_datastore *, ds, NULL, ast_datastore_free);</span><br><span style="color: hsl(120, 100%, 40%);">+       size_t eprofile_count = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+    char *geoloc_hdr_value = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+        char *duped_geoloc_hdr_value = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+  char *geoloc_uri = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+      int rc = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+   pjsip_generic_string_hdr *geoloc_hdr =</span><br><span style="color: hsl(120, 100%, 40%);">+                pjsip_msg_find_hdr_by_name(rdata->msg_info.msg, &GEOLOCATION_HDR, NULL);</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%);">+     if (!endpoint) {</span><br><span style="color: hsl(120, 100%, 40%);">+              SCOPE_EXIT_LOG_RTN_VALUE(0, 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_VALUE(0, 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 (!geoloc_hdr) {</span><br><span style="color: hsl(120, 100%, 40%);">+            ast_trace(4, "%s: Message has no Geolocation header\n", session_name);</span><br><span style="color: hsl(120, 100%, 40%);">+      } else {</span><br><span style="color: hsl(120, 100%, 40%);">+              ast_trace(4, "%s: Geolocation: " PJSTR_PRINTF_SPEC, session_name,</span><br><span style="color: hsl(120, 100%, 40%);">+                   PJSTR_PRINTF_VAR(geoloc_hdr->hvalue));</span><br><span 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_incoming_call_profile)) {</span><br><span style="color: hsl(120, 100%, 40%);">+             if (geoloc_hdr) {</span><br><span style="color: hsl(120, 100%, 40%);">+                     SCOPE_EXIT_LOG_RTN_VALUE(0, LOG_NOTICE, "%s: Message has Geolocation header '"</span><br><span style="color: hsl(120, 100%, 40%);">+                          PJSTR_PRINTF_SPEC "' but endpoint has no geoloc_incoming_call_profile. "</span><br><span style="color: hsl(120, 100%, 40%);">+                                "Geolocation info discarded.\n", session_name,</span><br><span style="color: hsl(120, 100%, 40%);">+                              PJSTR_PRINTF_VAR(geoloc_hdr->hvalue));</span><br><span style="color: hsl(120, 100%, 40%);">+             } else {</span><br><span style="color: hsl(120, 100%, 40%);">+                      SCOPE_EXIT_LOG_RTN_VALUE(0, LOG_NOTICE, "%s: Endpoint has no geoloc_incoming_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%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   config_profile = ast_geoloc_get_profile(endpoint->geoloc_incoming_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_VALUE(0, LOG_NOTICE, "%s: Message has Geolocation header '"</span><br><span style="color: hsl(120, 100%, 40%);">+                  PJSTR_PRINTF_SPEC "' but endpoint's geoloc_incoming_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%);">+                      PJSTR_PRINTF_VAR(geoloc_hdr->hvalue));</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   ds = ast_geoloc_datastore_create(session_name);</span><br><span style="color: hsl(120, 100%, 40%);">+       if (!ds) {</span><br><span style="color: hsl(120, 100%, 40%);">+            SCOPE_EXIT_LOG_RTN_VALUE(0, LOG_WARNING,</span><br><span style="color: hsl(120, 100%, 40%);">+                      "%s: Couldn't allocate a geoloc datastore\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%);">+   if (config_profile->location_disposition == AST_GEOLOC_LOC_DISP_DISCARD) {</span><br><span style="color: hsl(120, 100%, 40%);">+         ast_trace(4, "%s: Profile '%s' location_disposition is 'discard' so "</span><br><span style="color: hsl(120, 100%, 40%);">+                       "discarding Geolocation: " PJSTR_PRINTF_SPEC, session_name,</span><br><span style="color: hsl(120, 100%, 40%);">+                 ast_sorcery_object_get_id(config_profile),</span><br><span style="color: hsl(120, 100%, 40%);">+                    PJSTR_PRINTF_VAR(geoloc_hdr->hvalue));</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_VALUE(0, 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%);">+           rc = ast_geoloc_datastore_add_eprofile(ds, config_eprofile);</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(0, LOG_WARNING,</span><br><span style="color: hsl(120, 100%, 40%);">+                              "%s: Couldn't add eprofile '%s' to datastore\n", session_name,</span><br><span style="color: hsl(120, 100%, 40%);">+                          config_eprofile->id);</span><br><span style="color: hsl(120, 100%, 40%);">+              }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+           ast_channel_datastore_add(channel, ds);</span><br><span style="color: hsl(120, 100%, 40%);">+               /*</span><br><span style="color: hsl(120, 100%, 40%);">+             * We gave our eprofile reference to the datastore and the</span><br><span style="color: hsl(120, 100%, 40%);">+             * datastore to the channel so don't let RAII_VAR clean them up.</span><br><span style="color: hsl(120, 100%, 40%);">+           */</span><br><span style="color: hsl(120, 100%, 40%);">+           config_eprofile = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+               ds = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+          SCOPE_EXIT_RTN_VALUE(0, "%s: Added geoloc datastore with 1 eprofile\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                     session_name);</span><br><span style="color: hsl(120, 100%, 40%);">+        } else if (config_profile->location_disposition == AST_GEOLOC_LOC_DISP_PREPEND) {</span><br><span style="color: hsl(120, 100%, 40%);">+          ast_trace(4, "%s: Profile '%s' location_disposition is 'prepend' so "</span><br><span style="color: hsl(120, 100%, 40%);">+                       "adding to datastore first", 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%);">+            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_VALUE(0, 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%);">+           rc = ast_geoloc_datastore_add_eprofile(ds, config_eprofile);</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(0, LOG_WARNING,</span><br><span style="color: hsl(120, 100%, 40%);">+                              "%s: Couldn't add eprofile '%s' to datastore\n", session_name,</span><br><span style="color: hsl(120, 100%, 40%);">+                          config_eprofile->id);</span><br><span style="color: hsl(120, 100%, 40%);">+              }</span><br><span style="color: hsl(120, 100%, 40%);">+             config_eprofile = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+             if (!geoloc_hdr) {</span><br><span style="color: hsl(120, 100%, 40%);">+                    ast_channel_datastore_add(channel, ds);</span><br><span style="color: hsl(120, 100%, 40%);">+                       ds = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+                  SCOPE_EXIT_RTN_VALUE(0, "%s: No Geolocation header so just adding config profile "</span><br><span style="color: hsl(120, 100%, 40%);">+                          "'%s' to datastore\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%);">+     } else if (config_profile->location_disposition == AST_GEOLOC_LOC_DISP_REPLACE) {</span><br><span style="color: hsl(120, 100%, 40%);">+          if (geoloc_hdr) {</span><br><span style="color: hsl(120, 100%, 40%);">+                     ast_trace(4, "%s: Profile '%s' location_disposition is 'replace' so "</span><br><span style="color: hsl(120, 100%, 40%);">+                               "we don't need to do anything with the configured profile", session_name,</span><br><span style="color: hsl(120, 100%, 40%);">+                               ast_sorcery_object_get_id(config_profile));</span><br><span style="color: hsl(120, 100%, 40%);">+           } else {</span><br><span style="color: hsl(120, 100%, 40%);">+                      SCOPE_EXIT_LOG_RTN_VALUE(0, LOG_WARNING,</span><br><span style="color: hsl(120, 100%, 40%);">+                              "%s: Profile '%s' location_disposition is 'replace' but there's"</span><br><span style="color: hsl(120, 100%, 40%);">+                                "no Geolocation header and therefore no location info to replace"</span><br><span style="color: hsl(120, 100%, 40%);">+                           "it with\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%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   geoloc_hdr_value = ast_alloca(geoloc_hdr->hvalue.slen + 1);</span><br><span style="color: hsl(120, 100%, 40%);">+        ast_copy_pj_str(geoloc_hdr_value, &geoloc_hdr->hvalue, geoloc_hdr->hvalue.slen + 1);</span><br><span style="color: hsl(120, 100%, 40%);">+        duped_geoloc_hdr_value = ast_strdupa(geoloc_hdr_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%);">+     * From RFC-6442:</span><br><span style="color: hsl(120, 100%, 40%);">+      * Geolocation-header = "Geolocation" HCOLON locationValue</span><br><span style="color: hsl(120, 100%, 40%);">+   *                      *( COMMA locationValue )</span><br><span style="color: hsl(120, 100%, 40%);">+       * locationValue      = LAQUOT locationURI RAQUOT</span><br><span style="color: hsl(120, 100%, 40%);">+      *                      *(SEMI geoloc-param)</span><br><span style="color: hsl(120, 100%, 40%);">+   * locationURI        = sip-URI / sips-URI / pres-URI</span><br><span style="color: hsl(120, 100%, 40%);">+  *                        / http-URI / https-URI</span><br><span style="color: hsl(120, 100%, 40%);">+       *                            / cid-url ; (from RFC 2392)</span><br><span style="color: hsl(120, 100%, 40%);">+      *                        / absoluteURI ; (from RFC 3261)</span><br><span style="color: hsl(120, 100%, 40%);">+      */</span><br><span style="color: hsl(120, 100%, 40%);">+   while((geoloc_uri = ast_strsep(&duped_geoloc_hdr_value, ',', AST_STRSEP_TRIM))) {</span><br><span style="color: hsl(120, 100%, 40%);">+         /* geoloc_uri should now be <scheme:location> */</span><br><span style="color: hsl(120, 100%, 40%);">+                int uri_len = strlen(geoloc_uri);</span><br><span style="color: hsl(120, 100%, 40%);">+             char *pidf_body = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+               unsigned int pidf_len = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+            struct ast_xml_doc *incoming_doc = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+            struct ast_geoloc_eprofile *eprofile = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+          int rc = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+         ast_trace(4, "Processing URI '%s'\n", geoloc_uri);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+                if (geoloc_uri[0] != '<' || geoloc_uri[uri_len - 1] != '>') {</span><br><span style="color: hsl(120, 100%, 40%);">+                   ast_log(LOG_WARNING, "%s: Geolocation header has bad URI '%s'.  Skipping\n", session_name,</span><br><span style="color: hsl(120, 100%, 40%);">+                          geoloc_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%);">+             /* Trim the trailing '>' and skip the leading '<' */</span><br><span style="color: hsl(120, 100%, 40%);">+            geoloc_uri[uri_len - 1] = '\0';</span><br><span style="color: hsl(120, 100%, 40%);">+               geoloc_uri++;</span><br><span style="color: hsl(120, 100%, 40%);">+         /*</span><br><span style="color: hsl(120, 100%, 40%);">+             * If the URI isn't "cid" then we're just going to pass it through.</span><br><span style="color: hsl(120, 100%, 40%);">+          */</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'.  Reference\n", geoloc_uri);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+                    eprofile = ast_geoloc_eprofile_create_from_uri(geoloc_uri, session_name);</span><br><span style="color: hsl(120, 100%, 40%);">+                     if (!eprofile) {</span><br><span style="color: hsl(120, 100%, 40%);">+                              ast_log(LOG_WARNING, "%s: Unable to create effective profile for URI '%s'.  Skipping\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                                    session_name, geoloc_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%);">+             } else {</span><br><span style="color: hsl(120, 100%, 40%);">+                      ast_trace(4, "Processing URI '%s'.  PIDF\n", geoloc_uri);</span><br><span style="color: hsl(120, 100%, 40%);">+                   rc = find_pidf(session_name, rdata, geoloc_uri, &pidf_body, &pidf_len);</span><br><span style="color: hsl(120, 100%, 40%);">+                       if (rc != 0 || !pidf_body || pidf_len == 0) {</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%);">+                   incoming_doc = ast_xml_read_memory(pidf_body, pidf_len);</span><br><span style="color: hsl(120, 100%, 40%);">+                      if (!incoming_doc) {</span><br><span style="color: hsl(120, 100%, 40%);">+                          ast_log(LOG_WARNING, "%s: Unable to parse pidf document for URI '%s'\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                                    session_name, geoloc_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%);">+                   eprofile = ast_geoloc_eprofile_create_from_pidf(incoming_doc, session_name);</span><br><span style="color: hsl(120, 100%, 40%);">+          }</span><br><span style="color: hsl(120, 100%, 40%);">+             eprofile->location_disposition = config_profile->location_disposition;</span><br><span style="color: hsl(120, 100%, 40%);">+          eprofile->send_location = config_profile->send_location;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+              ast_trace(4, "Processing URI '%s'.  Adding to datastore\n", geoloc_uri);</span><br><span style="color: hsl(120, 100%, 40%);">+            rc = ast_geoloc_datastore_add_eprofile(ds, eprofile);</span><br><span style="color: hsl(120, 100%, 40%);">+         if (rc != 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+                        ao2_ref(eprofile, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+                        ast_log(LOG_WARNING, "%s: Unable to add effective profile for URI '%s' to datastore.  Skipping\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                          session_name, geoloc_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%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   if (config_profile->location_disposition == AST_GEOLOC_LOC_DISP_APPEND) {</span><br><span style="color: hsl(120, 100%, 40%);">+          ast_trace(4, "%s: Profile '%s' location_disposition is 'prepend' so "</span><br><span style="color: hsl(120, 100%, 40%);">+                       "adding to datastore first", 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%);">+            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_VALUE(0, 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%);">+           rc = ast_geoloc_datastore_add_eprofile(ds, config_eprofile);</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(0, LOG_WARNING,</span><br><span style="color: hsl(120, 100%, 40%);">+                              "%s: Couldn't add eprofile '%s' to datastore\n", session_name,</span><br><span style="color: hsl(120, 100%, 40%);">+                          config_eprofile->id);</span><br><span style="color: hsl(120, 100%, 40%);">+              }</span><br><span style="color: hsl(120, 100%, 40%);">+             config_eprofile = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+       }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   eprofile_count = ast_geoloc_datastore_size(ds);</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_VALUE(0,</span><br><span style="color: hsl(120, 100%, 40%);">+                       "%s: Unable to add any effective profiles.  Not adding datastore to channel.\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%);">+   ast_channel_datastore_add(channel, ds);</span><br><span style="color: hsl(120, 100%, 40%);">+       ds = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  SCOPE_EXIT_RTN_VALUE(0, "%s: Added geoloc datastore with %" PRIu64 " eprofiles\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                session_name, 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%);">+static void handle_outgoing_request(struct ast_sip_session *session, struct pjsip_tx_data *tdata)</span><br><span 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%);">+static struct ast_sip_session_supplement geolocation_supplement = {</span><br><span style="color: hsl(120, 100%, 40%);">+ .method = "INVITE",</span><br><span style="color: hsl(120, 100%, 40%);">+ .priority = AST_SIP_SUPPLEMENT_PRIORITY_CHANNEL + 10,</span><br><span style="color: hsl(120, 100%, 40%);">+ .incoming_request = handle_incoming_request,</span><br><span style="color: hsl(120, 100%, 40%);">+  .outgoing_request = handle_outgoing_request,</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static int reload_module(void)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static int unload_module(void)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+     int res = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+  ast_sip_session_unregister_supplement(&geolocation_supplement);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ return res;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static int load_module(void)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+     int res = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+  GEOLOCATION_HDR = pj_str("Geolocation");</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  ast_sip_session_register_supplement(&geolocation_supplement);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   return res;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS | AST_MODFLAG_LOAD_ORDER, "res_pjsip_geolocation Module for Asterisk",</span><br><span style="color: hsl(120, 100%, 40%);">+       .support_level = AST_MODULE_SUPPORT_CORE,</span><br><span style="color: hsl(120, 100%, 40%);">+     .load = load_module,</span><br><span style="color: hsl(120, 100%, 40%);">+  .unload = unload_module,</span><br><span style="color: hsl(120, 100%, 40%);">+      .reload = reload_module,</span><br><span style="color: hsl(120, 100%, 40%);">+      .load_pri = AST_MODPRI_CHANNEL_DEPEND - 1,</span><br><span style="color: hsl(120, 100%, 40%);">+    .requires = "res_geolocation,res_pjsip,res_pjsip_session,chan_pjsip",</span><br><span style="color: hsl(120, 100%, 40%);">+);</span><br><span></span><br></pre><div style="white-space:pre-wrap"></div><p>To view, visit <a href="https://gerrit.asterisk.org/c/asterisk/+/18191">change 18191</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/+/18191"/><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: I6ccb5108a5eec060efb8116502fbff3cc63d7554 </div>
<div style="display:none"> Gerrit-Change-Number: 18191 </div>
<div style="display:none"> Gerrit-PatchSet: 4 </div>
<div style="display:none"> Gerrit-Owner: George Joseph <gjoseph@digium.com> </div>
<div style="display:none"> Gerrit-Reviewer: Friendly Automation </div>
<div style="display:none"> Gerrit-Reviewer: George Joseph <gjoseph@digium.com> </div>
<div style="display:none"> Gerrit-Reviewer: Joshua Colp <jcolp@sangoma.com> </div>
<div style="display:none"> Gerrit-Reviewer: Kevin Harwell <kharwell@digium.com> </div>
<div style="display:none"> Gerrit-Reviewer: Michael Bradeen <mbradeen@sangoma.com> </div>
<div style="display:none"> Gerrit-MessageType: merged </div>