<p>George Joseph has uploaded this change for <strong>review</strong>.</p><p><a href="https://gerrit.asterisk.org/c/asterisk/+/19193">View Change</a></p><pre style="font-family: monospace,monospace; white-space: pre-wrap;">res_geolocation: Add two new options to GEOLOC_PROFILE<br><br>Added an 'a' option to the GEOLOC_PROFILE function to allow<br>variable lists like location_info_refinement to be appended<br>to instead of replacing the entire list.<br><br>Added an 'r' option to the GEOLOC_PROFILE function to resolve all<br>variables before a read operation and after a Set operation.<br><br>Added a few missing parameters to the ones allowed for writing<br>with GEOLOC_PROFILE.<br><br>Fixed a bug where calling GEOLOC_PROFILE to read a parameter<br>might actually update the profile object.<br><br>Cleaned up XML documentation a bit.<br><br>ASTERISK-30190<br><br>Change-Id: I75f541db43345509a2e86225bfa4cf8e242e5b6c<br>---<br>M doc/CHANGES-staging/res_geolocation.txt<br>M include/asterisk/res_geolocation.h<br>M res/res_geolocation/geoloc_dialplan.c<br>M res/res_geolocation/geoloc_doc.xml<br>M res/res_geolocation/geoloc_eprofile.c<br>M res/res_geolocation/geoloc_private.h<br>M res/res_pjsip_geolocation.c<br>7 files changed, 287 insertions(+), 37 deletions(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;">git pull ssh://gerrit.asterisk.org:29418/asterisk refs/changes/93/19193/1</pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;"><span>diff --git a/doc/CHANGES-staging/res_geolocation.txt b/doc/CHANGES-staging/res_geolocation.txt</span><br><span>index b543c6e..4d290ba 100644</span><br><span>--- a/doc/CHANGES-staging/res_geolocation.txt</span><br><span>+++ b/doc/CHANGES-staging/res_geolocation.txt</span><br><span>@@ -40,3 +40,10 @@</span><br><span> information isn't common with any other profiles.  This is</span><br><span> mutually exclusive with setting location_reference on the</span><br><span> profile.</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+Added an 'a' option to the GEOLOC_PROFILE function to allow</span><br><span style="color: hsl(120, 100%, 40%);">+variable lists like location_info_refinement to be appended</span><br><span style="color: hsl(120, 100%, 40%);">+to instead of replacing the entire list.</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+Added an 'r' option to the GEOLOC_PROFILE function to resolve all</span><br><span style="color: hsl(120, 100%, 40%);">+variables before a read operation and after a Set operation.</span><br><span>diff --git a/include/asterisk/res_geolocation.h b/include/asterisk/res_geolocation.h</span><br><span>index 378a6c7..0a5a61d 100644</span><br><span>--- a/include/asterisk/res_geolocation.h</span><br><span>+++ b/include/asterisk/res_geolocation.h</span><br><span>@@ -318,6 +318,15 @@</span><br><span> struct ast_geoloc_eprofile *ast_geoloc_eprofile_alloc(const char *name);</span><br><span> </span><br><span> /*!</span><br><span style="color: hsl(120, 100%, 40%);">+ * \brief Duplicate an effective profile.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param src The eprofile to duplicate.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \return The duplicated effective profile ao2 object.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+struct ast_geoloc_eprofile *ast_geoloc_eprofile_dup(struct ast_geoloc_eprofile *src);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*!</span><br><span>  * \brief Allocate a new effective profile from an existing profile.</span><br><span>  *</span><br><span>  * \param profile The profile to use.</span><br><span>diff --git a/res/res_geolocation/geoloc_dialplan.c b/res/res_geolocation/geoloc_dialplan.c</span><br><span>index 710daa6..1d1346a 100644</span><br><span>--- a/res/res_geolocation/geoloc_dialplan.c</span><br><span>+++ b/res/res_geolocation/geoloc_dialplan.c</span><br><span>@@ -25,7 +25,6 @@</span><br><span> #include "asterisk/strings.h"</span><br><span> #include "asterisk/utils.h"</span><br><span> #include "asterisk/app.h"</span><br><span style="color: hsl(0, 100%, 40%);">-#include "asterisk/res_geolocation.h"</span><br><span> #include "geoloc_private.h"</span><br><span> </span><br><span> static void varlist_to_str(struct ast_variable *list, struct ast_str** buf, size_t len)</span><br><span>@@ -37,20 +36,52 @@</span><br><span>   }</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+#define RESOLVE_FOR_READ(_param) \</span><br><span style="color: hsl(120, 100%, 40%);">+({ \</span><br><span style="color: hsl(120, 100%, 40%);">+  if (ast_test_flag(&opts, OPT_GEOLOC_RESOLVE)) { \</span><br><span style="color: hsl(120, 100%, 40%);">+         struct ast_variable *resolved = geoloc_eprofile_resolve_varlist( \</span><br><span style="color: hsl(120, 100%, 40%);">+                    eprofile->_param, eprofile->location_variables, chan); \</span><br><span style="color: hsl(120, 100%, 40%);">+                if (!resolved) { \</span><br><span style="color: hsl(120, 100%, 40%);">+                    ast_log(LOG_ERROR, "%s: Unable to resolve " #_param "\n", chan_name); \</span><br><span style="color: hsl(120, 100%, 40%);">+                   pbx_builtin_setvar_helper(chan, "GEOLOCPROFILESTATUS", "-3"); \</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%);">+           varlist_to_str(resolved, buf, len); \</span><br><span style="color: hsl(120, 100%, 40%);">+         ast_variables_destroy(resolved); \</span><br><span style="color: hsl(120, 100%, 40%);">+    } else { \</span><br><span style="color: hsl(120, 100%, 40%);">+            varlist_to_str(eprofile->_param, buf, 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%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+enum my_app_option_flags {</span><br><span style="color: hsl(120, 100%, 40%);">+ OPT_GEOLOC_RESOLVE = (1 << 0),</span><br><span style="color: hsl(120, 100%, 40%);">+  OPT_GEOLOC_APPEND = (1 << 1),</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+AST_APP_OPTIONS(action_options, {</span><br><span style="color: hsl(120, 100%, 40%);">+  AST_APP_OPTION('r', OPT_GEOLOC_RESOLVE),</span><br><span style="color: hsl(120, 100%, 40%);">+      AST_APP_OPTION('a', OPT_GEOLOC_APPEND),</span><br><span 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> static int geoloc_profile_read(struct ast_channel *chan,</span><br><span>         const char *cmd, char *data, struct ast_str **buf, ssize_t len)</span><br><span> {</span><br><span>         char *parsed_data = ast_strdupa(data);</span><br><span style="color: hsl(120, 100%, 40%);">+        const char *chan_name = ast_channel_name(chan);</span><br><span>      struct ast_datastore *ds;</span><br><span style="color: hsl(120, 100%, 40%);">+     struct ast_geoloc_eprofile *orig_eprofile = NULL;</span><br><span>    struct ast_geoloc_eprofile *eprofile = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+  struct ast_flags opts = { 0, };</span><br><span> </span><br><span>  AST_DECLARE_APP_ARGS(args,</span><br><span>           AST_APP_ARG(field);</span><br><span style="color: hsl(120, 100%, 40%);">+           AST_APP_ARG(options);</span><br><span>        );</span><br><span> </span><br><span>       /* Check for zero arguments */</span><br><span>       if (ast_strlen_zero(parsed_data)) {</span><br><span style="color: hsl(0, 100%, 40%);">-             ast_log(LOG_ERROR, "%s: Cannot call without arguments\n", cmd);</span><br><span style="color: hsl(120, 100%, 40%);">+             ast_log(LOG_ERROR, "%s: Cannot call without arguments\n", chan_name);</span><br><span>              pbx_builtin_setvar_helper(chan, "GEOLOCPROFILESTATUS", "-1");</span><br><span>            return 0;</span><br><span>    }</span><br><span>@@ -58,25 +89,45 @@</span><br><span>      AST_STANDARD_APP_ARGS(args, parsed_data);</span><br><span> </span><br><span>        if (ast_strlen_zero(args.field)) {</span><br><span style="color: hsl(0, 100%, 40%);">-              ast_log(LOG_ERROR, "%s: Cannot call without a field to query\n", cmd);</span><br><span style="color: hsl(120, 100%, 40%);">+              ast_log(LOG_ERROR, "%s: Cannot call without a field to query\n", chan_name);</span><br><span>               pbx_builtin_setvar_helper(chan, "GEOLOCPROFILESTATUS", "-1");</span><br><span>            return 0;</span><br><span>    }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+ if (!ast_strlen_zero(args.options)) {</span><br><span style="color: hsl(120, 100%, 40%);">+         if (ast_app_parse_options(action_options, &opts, NULL, args.options)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                   ast_log(LOG_ERROR, "%s: Invalid options: %s\n", chan_name, args.options);</span><br><span style="color: hsl(120, 100%, 40%);">+                   pbx_builtin_setvar_helper(chan, "GEOLOCPROFILESTATUS", "-1");</span><br><span style="color: hsl(120, 100%, 40%);">+                     return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+             }</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>  ds = ast_geoloc_datastore_find(chan);</span><br><span>        if (!ds) {</span><br><span style="color: hsl(0, 100%, 40%);">-              ast_log(LOG_NOTICE, "%s: There is no geoloc profile on this channel\n", cmd);</span><br><span style="color: hsl(120, 100%, 40%);">+               ast_log(LOG_NOTICE, "%s: There is no geoloc profile on this channel\n", chan_name);</span><br><span>                pbx_builtin_setvar_helper(chan, "GEOLOCPROFILESTATUS", "-2");</span><br><span>            return 0;</span><br><span>    }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-   eprofile = ast_geoloc_datastore_get_eprofile(ds, 0);</span><br><span style="color: hsl(0, 100%, 40%);">-    if (!eprofile) {</span><br><span style="color: hsl(0, 100%, 40%);">-                ast_log(LOG_NOTICE, "%s: There is no geoloc profile on this channel\n", cmd);</span><br><span style="color: hsl(120, 100%, 40%);">+       orig_eprofile = ast_geoloc_datastore_get_eprofile(ds, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+     if (!orig_eprofile) {</span><br><span style="color: hsl(120, 100%, 40%);">+         ast_log(LOG_NOTICE, "%s: There is no geoloc profile on this channel\n", chan_name);</span><br><span>                pbx_builtin_setvar_helper(chan, "GEOLOCPROFILESTATUS", "-2");</span><br><span>            return 0;</span><br><span>    }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+ eprofile = ast_geoloc_eprofile_dup(orig_eprofile);</span><br><span style="color: hsl(120, 100%, 40%);">+    ao2_ref(orig_eprofile, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+   if (!eprofile) {</span><br><span style="color: hsl(120, 100%, 40%);">+              ast_log(LOG_ERROR, "%s: Unable to duplicate eprofile\n", chan_name);</span><br><span style="color: hsl(120, 100%, 40%);">+                pbx_builtin_setvar_helper(chan, "GEOLOCPROFILESTATUS", "-2");</span><br><span style="color: hsl(120, 100%, 40%);">+             return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   if (!eprofile->effective_location) {</span><br><span style="color: hsl(120, 100%, 40%);">+               ast_geoloc_eprofile_refresh_location(eprofile);</span><br><span style="color: hsl(120, 100%, 40%);">+       }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>  pbx_builtin_setvar_helper(chan, "GEOLOCPROFILESTATUS", "0");</span><br><span>     if (ast_strings_equal(args.field, "inheritable")) {</span><br><span>                ast_str_append(buf, len, "%s", ds->inheritance ? "true" : "false");</span><br><span>@@ -101,19 +152,19 @@</span><br><span>         } else if (ast_strings_equal(args.field, "notes")) {</span><br><span>               ast_str_append(buf, len, "%s", eprofile->notes);</span><br><span>        } else if (ast_strings_equal(args.field, "location_info")) {</span><br><span style="color: hsl(0, 100%, 40%);">-          varlist_to_str(eprofile->location_info, buf, len);</span><br><span style="color: hsl(120, 100%, 40%);">+         RESOLVE_FOR_READ(location_info);</span><br><span>     } else if (ast_strings_equal(args.field, "location_info_refinement")) {</span><br><span style="color: hsl(0, 100%, 40%);">-               varlist_to_str(eprofile->location_refinement, buf, len);</span><br><span style="color: hsl(120, 100%, 40%);">+           RESOLVE_FOR_READ(location_refinement);</span><br><span>       } else if (ast_strings_equal(args.field, "location_variables")) {</span><br><span style="color: hsl(0, 100%, 40%);">-             varlist_to_str(eprofile->location_variables, buf, len);</span><br><span style="color: hsl(120, 100%, 40%);">+            RESOLVE_FOR_READ(location_variables);</span><br><span>        } else if (ast_strings_equal(args.field, "effective_location")) {</span><br><span style="color: hsl(0, 100%, 40%);">-             varlist_to_str(eprofile->effective_location, buf, len);</span><br><span style="color: hsl(120, 100%, 40%);">+            RESOLVE_FOR_READ(effective_location);</span><br><span>        } else if (ast_strings_equal(args.field, "usage_rules")) {</span><br><span style="color: hsl(0, 100%, 40%);">-            varlist_to_str(eprofile->usage_rules, buf, len);</span><br><span style="color: hsl(120, 100%, 40%);">+           RESOLVE_FOR_READ(usage_rules);</span><br><span>       } else if (ast_strings_equal(args.field, "confidence")) {</span><br><span>          varlist_to_str(eprofile->confidence, buf, len);</span><br><span>   } else {</span><br><span style="color: hsl(0, 100%, 40%);">-                ast_log(LOG_ERROR, "%s: Field '%s' is not valid\n", cmd, args.field);</span><br><span style="color: hsl(120, 100%, 40%);">+               ast_log(LOG_ERROR, "%s: Field '%s' is not valid\n", chan_name, args.field);</span><br><span>                pbx_builtin_setvar_helper(chan, "GEOLOCPROFILESTATUS", "-3");</span><br><span>    }</span><br><span> </span><br><span>@@ -121,6 +172,10 @@</span><br><span>         return 0;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+#define VAR_LIST_REPLACE(_old, _new) \</span><br><span style="color: hsl(120, 100%, 40%);">+    ast_variables_destroy(_old); \</span><br><span style="color: hsl(120, 100%, 40%);">+        _old = _new;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> #define TEST_ENUM_VALUE(_chan_name, _ep, _field, _value) \</span><br><span> ({ \</span><br><span>         enum ast_geoloc_ ## _field v; \</span><br><span>@@ -142,8 +197,26 @@</span><br><span>               pbx_builtin_setvar_helper(chan, "GEOLOCPROFILESTATUS", "-3"); \</span><br><span>          return 0; \</span><br><span>  } \</span><br><span style="color: hsl(0, 100%, 40%);">-     ast_variables_destroy(_ep->_field); \</span><br><span style="color: hsl(0, 100%, 40%);">-        _ep->_field = _list; \</span><br><span style="color: hsl(120, 100%, 40%);">+     if (ast_test_flag(&opts, OPT_GEOLOC_APPEND)) { \</span><br><span style="color: hsl(120, 100%, 40%);">+          ast_variable_list_append(&_ep->_field, _list); \</span><br><span style="color: hsl(120, 100%, 40%);">+       } else {\</span><br><span style="color: hsl(120, 100%, 40%);">+             VAR_LIST_REPLACE(_ep->_field, _list); \</span><br><span style="color: hsl(120, 100%, 40%);">+    } \</span><br><span style="color: hsl(120, 100%, 40%);">+})</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#define RESOLVE_FOR_WRITE(_param) \</span><br><span style="color: hsl(120, 100%, 40%);">+({ \</span><br><span style="color: hsl(120, 100%, 40%);">+if (ast_test_flag(&opts, OPT_GEOLOC_RESOLVE)) { \</span><br><span style="color: hsl(120, 100%, 40%);">+ struct ast_variable *resolved = geoloc_eprofile_resolve_varlist( \</span><br><span style="color: hsl(120, 100%, 40%);">+            eprofile->_param, eprofile->location_variables, chan); \</span><br><span style="color: hsl(120, 100%, 40%);">+        if (!resolved) { \</span><br><span style="color: hsl(120, 100%, 40%);">+            ast_log(LOG_ERROR, "%s: Unable to resolve " #_param " %p %p\n", chan_name, eprofile->_param, eprofile->location_variables); \</span><br><span style="color: hsl(120, 100%, 40%);">+               pbx_builtin_setvar_helper(chan, "GEOLOCPROFILESTATUS", "-3"); \</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%);">+   VAR_LIST_REPLACE(eprofile->_param, resolved); \</span><br><span style="color: hsl(120, 100%, 40%);">+} \</span><br><span> })</span><br><span> </span><br><span> static int geoloc_profile_write(struct ast_channel *chan, const char *cmd, char *data,</span><br><span>@@ -153,9 +226,11 @@</span><br><span>   const char *chan_name = ast_channel_name(chan);</span><br><span>      struct ast_datastore *ds; /* Reminder: datastores aren't ao2 objects */</span><br><span>  RAII_VAR(struct ast_geoloc_eprofile *, eprofile, NULL, ao2_cleanup);</span><br><span style="color: hsl(120, 100%, 40%);">+  struct ast_flags opts = { 0, };</span><br><span> </span><br><span>  AST_DECLARE_APP_ARGS(args,</span><br><span>           AST_APP_ARG(field);</span><br><span style="color: hsl(120, 100%, 40%);">+           AST_APP_ARG(options);</span><br><span>        );</span><br><span> </span><br><span>       /* Check for zero arguments */</span><br><span>@@ -173,6 +248,18 @@</span><br><span>                return 0;</span><br><span>    }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+ if (!ast_strlen_zero(args.options)) {</span><br><span style="color: hsl(120, 100%, 40%);">+         if (ast_app_parse_options(action_options, &opts, NULL, args.options)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                   ast_log(LOG_ERROR, "%s: Invalid options: %s\n", chan_name, args.options);</span><br><span style="color: hsl(120, 100%, 40%);">+                   pbx_builtin_setvar_helper(chan, "GEOLOCPROFILESTATUS", "-1");</span><br><span style="color: hsl(120, 100%, 40%);">+                     return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+             }</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   ast_debug(1, "%s: name: %s value: %s  options: %s append: %s resolve: %s\n", chan_name,</span><br><span style="color: hsl(120, 100%, 40%);">+             args.field, value, args.options, ast_test_flag(&opts, OPT_GEOLOC_APPEND) ? "yes" : "no",</span><br><span style="color: hsl(120, 100%, 40%);">+                      ast_test_flag(&opts, OPT_GEOLOC_RESOLVE) ? "yes" : "no");</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>  ds = ast_geoloc_datastore_find(chan);</span><br><span>        if (!ds) {</span><br><span>           ds = ast_geoloc_datastore_create(ast_channel_name(chan));</span><br><span>@@ -203,6 +290,8 @@</span><br><span> </span><br><span>  if (ast_strings_equal(args.field, "inheritable")) {</span><br><span>                ast_geoloc_datastore_set_inheritance(ds, ast_true(value));</span><br><span style="color: hsl(120, 100%, 40%);">+    } else if (ast_strings_equal(args.field, "id")) {</span><br><span style="color: hsl(120, 100%, 40%);">+           ast_string_field_set(eprofile, id, value);</span><br><span>   } else if (ast_strings_equal(args.field, "location_reference")) {</span><br><span>          struct ast_geoloc_location *loc = ast_geoloc_get_location(value);</span><br><span>            ao2_cleanup(loc);</span><br><span>@@ -224,18 +313,25 @@</span><br><span>            TEST_ENUM_VALUE(chan_name, eprofile, format, value);</span><br><span>         } else if (ast_strings_equal(args.field, "pidf_element")) {</span><br><span>                TEST_ENUM_VALUE(chan_name, eprofile, pidf_element, value);</span><br><span style="color: hsl(0, 100%, 40%);">-      } else if (ast_strings_equal(args.field, "location_info")) {</span><br><span style="color: hsl(0, 100%, 40%);">-          TEST_VARLIST(chan_name, eprofile, location_info, value);</span><br><span>     } else if (ast_strings_equal(args.field, "location_source")) {</span><br><span>             ast_string_field_set(eprofile, location_source, value);</span><br><span style="color: hsl(120, 100%, 40%);">+       } else if (ast_strings_equal(args.field, "notes")) {</span><br><span style="color: hsl(120, 100%, 40%);">+                ast_string_field_set(eprofile, notes, value);</span><br><span style="color: hsl(120, 100%, 40%);">+ } else if (ast_strings_equal(args.field, "location_info")) {</span><br><span style="color: hsl(120, 100%, 40%);">+                TEST_VARLIST(chan_name, eprofile, location_info, value);</span><br><span style="color: hsl(120, 100%, 40%);">+              RESOLVE_FOR_WRITE(location_info);</span><br><span>    } else if (ast_strings_equal(args.field, "location_info_refinement")) {</span><br><span>            TEST_VARLIST(chan_name, eprofile, location_refinement, value);</span><br><span style="color: hsl(120, 100%, 40%);">+                RESOLVE_FOR_WRITE(location_refinement);</span><br><span>      } else if (ast_strings_equal(args.field, "location_variables")) {</span><br><span>          TEST_VARLIST(chan_name, eprofile, location_variables, value);</span><br><span style="color: hsl(120, 100%, 40%);">+         RESOLVE_FOR_WRITE(location_variables);</span><br><span>       } else if (ast_strings_equal(args.field, "effective_location")) {</span><br><span>          TEST_VARLIST(chan_name, eprofile, effective_location, value);</span><br><span style="color: hsl(120, 100%, 40%);">+         RESOLVE_FOR_WRITE(effective_location);</span><br><span>       } else if (ast_strings_equal(args.field, "usage_rules")) {</span><br><span>                 TEST_VARLIST(chan_name, eprofile, usage_rules, value);</span><br><span style="color: hsl(120, 100%, 40%);">+                RESOLVE_FOR_WRITE(usage_rules);</span><br><span>      } else if (ast_strings_equal(args.field, "confidence")) {</span><br><span>          TEST_VARLIST(chan_name, eprofile, confidence, value);</span><br><span>        } else {</span><br><span>@@ -245,6 +341,7 @@</span><br><span>       }</span><br><span> </span><br><span>        ast_geoloc_eprofile_refresh_location(eprofile);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>    pbx_builtin_setvar_helper(chan, "GEOLOCPROFILESTATUS", "0");</span><br><span> </span><br><span>         return 0;</span><br><span>diff --git a/res/res_geolocation/geoloc_doc.xml b/res/res_geolocation/geoloc_doc.xml</span><br><span>index 4f7cdc2..b571336 100644</span><br><span>--- a/res/res_geolocation/geoloc_doc.xml</span><br><span>+++ b/res/res_geolocation/geoloc_doc.xml</span><br><span>@@ -7,12 +7,14 @@</span><br><span>                   <configObject name="location"></span><br><span>                               <synopsis>Location</synopsis></span><br><span>                            <description></span><br><span style="color: hsl(0, 100%, 40%);">-                                     <para>cffdffff</para></span><br><span style="color: hsl(120, 100%, 40%);">+                                     <para>Parameters for defining a Location object</para></span><br><span>                           </description></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>                               <configOption name="type"></span><br><span>                                   <synopsis>Must be of type 'location'.</synopsis></span><br><span>                                 </configOption></span><br><span style="color: hsl(0, 100%, 40%);">-                           <configOption name="format" default=""></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+                           <configOption name="format" default="none"></span><br><span>                                        <synopsis>Location specification type</synopsis></span><br><span>                                         <description></span><br><span>                                          <enumlist></span><br><span>@@ -42,7 +44,8 @@</span><br><span>                                                 </enumlist></span><br><span>                                    </description></span><br><span>                                 </configOption></span><br><span style="color: hsl(0, 100%, 40%);">-                           <configOption name="location_info" default=""></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+                            <configOption name="location_info" default="none"></span><br><span>                                         <synopsis>Location information</synopsis></span><br><span>                                        <description></span><br><span>                                          <para>The contents of this parameter are specific to the</span><br><span>@@ -68,7 +71,8 @@</span><br><span>                                           </enumlist></span><br><span>                                    </description></span><br><span>                                 </configOption></span><br><span style="color: hsl(0, 100%, 40%);">-                           <configOption name="location_source" default=""></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+                          <configOption name="location_source" default="none"></span><br><span>                                       <synopsis>Fully qualified host name</synopsis></span><br><span>                                   <description></span><br><span>                                          <para>This parameter isn't required but if provided, RFC8787 says it MUST be a fully</span><br><span>@@ -77,7 +81,8 @@</span><br><span>                                           Geolocation</literal> header.</para></span><br><span>                                     </description></span><br><span>                                 </configOption></span><br><span style="color: hsl(0, 100%, 40%);">-                           <configOption name="method" default=""></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+                           <configOption name="method" default="none"></span><br><span>                                        <synopsis>Location determination method</synopsis></span><br><span>                                       <description></span><br><span>                                          <para>This is a rarely used field in the specification that would</span><br><span>@@ -94,7 +99,8 @@</span><br><span>                                          </enumlist></span><br><span>                                    </description></span><br><span>                                 </configOption></span><br><span style="color: hsl(0, 100%, 40%);">-                           <configOption name="confidence" default=""></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+                               <configOption name="confidence" default="none"></span><br><span>                                    <synopsis>Level of confidence</synopsis></span><br><span>                                         <description></span><br><span>                                          <para>This is a rarely used field in the specification that would</span><br><span>@@ -123,14 +129,16 @@</span><br><span>                                      </see-also></span><br><span>                            </configOption></span><br><span>                        </configObject></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>                      <configObject name="profile"></span><br><span>                                <synopsis>Profile</synopsis></span><br><span>                             <description></span><br><span style="color: hsl(0, 100%, 40%);">-                                     <para>cffdffff</para></span><br><span style="color: hsl(120, 100%, 40%);">+                                     <para>Parameters for defining a Profile object</para></span><br><span>                            </description></span><br><span>                                 <configOption name="type"></span><br><span>                                   <synopsis>Must be of type 'profile'.</synopsis></span><br><span>                          </configOption></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>                              <configOption name="pidf_element" default="device"></span><br><span>                                        <synopsis>PIDF-LO element to place this profile in</synopsis></span><br><span>                                    <description></span><br><span>@@ -148,21 +156,25 @@</span><br><span>                                          <ref type="link">https://www.rfc-editor.org/rfc/rfc5491.html#section-3.4</ref></span><br><span>                                         </see-also></span><br><span>                            </configOption></span><br><span style="color: hsl(0, 100%, 40%);">-                           <configOption name="location_reference" default=""></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+                               <configOption name="location_reference" default="none"></span><br><span>                                    <synopsis>Reference to a location object</synopsis></span><br><span>                              </configOption></span><br><span style="color: hsl(0, 100%, 40%);">-                           <configOption name="location_info_refinement" default=""></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+                         <configOption name="location_info_refinement" default="none"></span><br><span>                                      <synopsis>Reference to a location object</synopsis></span><br><span>                              </configOption></span><br><span style="color: hsl(0, 100%, 40%);">-                           <configOption name="location_variables" default=""></span><br><span style="color: hsl(120, 100%, 40%);">+                         <configOption name="location_variables" default="none"></span><br><span>                                    <synopsis>Reference to a location object</synopsis></span><br><span>                              </configOption></span><br><span style="color: hsl(0, 100%, 40%);">-                           <configOption name="usage_rules" default="yes"></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+                           <configOption name="usage_rules" default="empty &lt;usage_rules&gt; element"></span><br><span>                                      <synopsis>location specification type</synopsis></span><br><span>                                         <description></span><br><span>                                          <para>xxxx</para></span><br><span>                                        </description></span><br><span>                                 </configOption></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>                              <configOption name="notes" default=""></span><br><span>                                     <synopsis>Notes to be added to the outgoing PIDF-LO document</synopsis></span><br><span>                                  <description></span><br><span>@@ -171,11 +183,13 @@</span><br><span>                                          outgoing PIDF-LO document.  Its usage should be pre-negotiated with</span><br><span>                                          any recipients.</para></span><br><span>                                         </description></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>                               </configOption></span><br><span style="color: hsl(0, 100%, 40%);">-                           <configOption name="allow_routing_use"></span><br><span style="color: hsl(120, 100%, 40%);">+                               <configOption name="allow_routing_use" default="no"></span><br><span>                                       <synopsis>Sets the value of the Geolocation-Routing header.</synopsis></span><br><span>                           </configOption></span><br><span style="color: hsl(0, 100%, 40%);">-                           <configOption name="suppress_empty_ca_elements"></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+                            <configOption name="suppress_empty_ca_elements" default="no"></span><br><span>                                      <synopsis>Sets if empty Civic Address elements should be suppressed</span><br><span>                                    from the PIDF-LO document.</synopsis></span><br><span>                          </configOption></span><br><span>@@ -207,6 +221,7 @@</span><br><span>                                          </enumlist></span><br><span>                                    </description></span><br><span>                                 </configOption></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>                              <xi:include xpointer="xpointer(/docs/configInfo[@name='res_geolocation']/configFile[@name='geolocation.conf']/configObject[@name='location']/configOption[@name='format'])"/></span><br><span>                                <xi:include xpointer="xpointer(/docs/configInfo[@name='res_geolocation']/configFile[@name='geolocation.conf']/configObject[@name='location']/configOption[@name='location_info'])"/></span><br><span>                                 <xi:include xpointer="xpointer(/docs/configInfo[@name='res_geolocation']/configFile[@name='geolocation.conf']/configObject[@name='location']/configOption[@name='confidence'])"/></span><br><span>@@ -220,8 +235,8 @@</span><br><span>                      Get or Set a field in a geolocation profile</span><br><span>          </synopsis></span><br><span>            <syntax></span><br><span style="color: hsl(0, 100%, 40%);">-                  <parameter name="field" required="true"></span><br><span style="color: hsl(0, 100%, 40%);">-                              <para>The profile field to operate on. The following fields from the</span><br><span style="color: hsl(120, 100%, 40%);">+                    <parameter name="parameter" required="true"></span><br><span style="color: hsl(120, 100%, 40%);">+                                <para>The profile parameter to operate on. The following fields from the</span><br><span>                               Location and Profile objects are supported.</para></span><br><span>                             <enumlist></span><br><span>                                     <enum name="id"/></span><br><span>@@ -244,10 +259,38 @@</span><br><span>                            set to <literal>true</literal> or <literal>false</literal> to control</span><br><span>                                whether the profile will be passed to the outgoing channel.</span><br><span>                          </para></span><br><span style="color: hsl(120, 100%, 40%);">+                         <para></span><br><span style="color: hsl(120, 100%, 40%);">+                          </para></span><br><span style="color: hsl(120, 100%, 40%);">+                 </parameter></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+                  <parameter name="options" required="false"></span><br><span style="color: hsl(120, 100%, 40%);">+                         <optionlist></span><br><span style="color: hsl(120, 100%, 40%);">+                            <option name="a"></span><br><span style="color: hsl(120, 100%, 40%);">+                                     <para>Append provided value to the specified parameter</span><br><span style="color: hsl(120, 100%, 40%);">+                                  instead of replacing the existing value.  This only applies</span><br><span style="color: hsl(120, 100%, 40%);">+                                   to variable list parameters like</span><br><span style="color: hsl(120, 100%, 40%);">+                                      <literal>location_info_refinement</literal>.</span><br><span style="color: hsl(120, 100%, 40%);">+                                      </para></span><br><span style="color: hsl(120, 100%, 40%);">+                         </option></span><br><span style="color: hsl(120, 100%, 40%);">+                               <option name="r"></span><br><span style="color: hsl(120, 100%, 40%);">+                                     <para>Before reading or after writing the specified parameter,</span><br><span style="color: hsl(120, 100%, 40%);">+                                  re-resolve the <literal>effective_location</literal> and</span><br><span style="color: hsl(120, 100%, 40%);">+                                  <literal>usage_rules</literal> parameters using the</span><br><span style="color: hsl(120, 100%, 40%);">+                                       <literal>location_variables</literal> parameter and the variables</span><br><span style="color: hsl(120, 100%, 40%);">+                                 set on the channel in effect at the time this function is called.</span><br><span style="color: hsl(120, 100%, 40%);">+                                     </para></span><br><span style="color: hsl(120, 100%, 40%);">+                                 <note><para>On a read operation, this does not alter the actual profile</span><br><span style="color: hsl(120, 100%, 40%);">+                                           in any way.  On a write operation however, the</span><br><span style="color: hsl(120, 100%, 40%);">+                                                <literal>effective_location</literal> and/or <literal>usage_rules</literal></span><br><span style="color: hsl(120, 100%, 40%);">+                                           parameters may indeed change and those changes will be passed on</span><br><span style="color: hsl(120, 100%, 40%);">+                                              to any outgoing channel.</span><br><span style="color: hsl(120, 100%, 40%);">+                                      </para></note></span><br><span style="color: hsl(120, 100%, 40%);">+                            </option></span><br><span style="color: hsl(120, 100%, 40%);">+                               </optionlist></span><br><span>                  </parameter></span><br><span>           </syntax></span><br><span>              <description><para></span><br><span style="color: hsl(0, 100%, 40%);">-         When used to set a field on a profile, if the profile doesn't already exist, a new</span><br><span style="color: hsl(120, 100%, 40%);">+                When used to set a parameter on a profile, if the profile doesn't already exist, a new</span><br><span>           one will be created automatically.</span><br><span>           </para></span><br><span>                <para></span><br><span>@@ -258,8 +301,8 @@</span><br><span>                   <enum name="0"><para>Success</para></enum></span><br><span>                         <enum name="-1"><para>No or not enough parameters were supplied</para></enum></span><br><span>                      <enum name="-2"><para>There was an internal error finding or creating a profile</para></enum></span><br><span style="color: hsl(0, 100%, 40%);">-                 <enum name="-3"><para>There was an issue specific to the field specified</span><br><span style="color: hsl(0, 100%, 40%);">-                  (value not valid or field name not found)</para></enum></span><br><span style="color: hsl(120, 100%, 40%);">+                   <enum name="-3"><para>There was an issue specific to the parameter specified</span><br><span style="color: hsl(120, 100%, 40%);">+                    (value not valid or parameter name not found, etc.)</para></enum></span><br><span>                </enumlist></span><br><span>            </description></span><br><span>         </function></span><br><span>diff --git a/res/res_geolocation/geoloc_eprofile.c b/res/res_geolocation/geoloc_eprofile.c</span><br><span>index 1deb76e..864dd23 100644</span><br><span>--- a/res/res_geolocation/geoloc_eprofile.c</span><br><span>+++ b/res/res_geolocation/geoloc_eprofile.c</span><br><span>@@ -156,6 +156,67 @@</span><br><span>    return 0;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+struct ast_geoloc_eprofile *ast_geoloc_eprofile_dup(struct ast_geoloc_eprofile *src)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+   struct ast_geoloc_eprofile *eprofile;</span><br><span style="color: hsl(120, 100%, 40%);">+ const char *profile_id;</span><br><span style="color: hsl(120, 100%, 40%);">+       int rc = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!src) {</span><br><span style="color: hsl(120, 100%, 40%);">+           return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+  }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   profile_id = ast_strdupa(src->id);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       eprofile = ast_geoloc_eprofile_alloc(profile_id);</span><br><span style="color: hsl(120, 100%, 40%);">+     if (!eprofile) {</span><br><span style="color: hsl(120, 100%, 40%);">+              return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+  }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   eprofile->allow_routing_use = src->allow_routing_use;</span><br><span style="color: hsl(120, 100%, 40%);">+   eprofile->pidf_element = src->pidf_element;</span><br><span style="color: hsl(120, 100%, 40%);">+     eprofile->suppress_empty_ca_elements = src->suppress_empty_ca_elements;</span><br><span style="color: hsl(120, 100%, 40%);">+ eprofile->format = src->format;</span><br><span style="color: hsl(120, 100%, 40%);">+ eprofile->precedence = src->precedence;</span><br><span 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_string_field_set(eprofile, location_reference, src->location_reference);</span><br><span style="color: hsl(120, 100%, 40%);">+  if (rc == 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+                ast_string_field_set(eprofile, notes, src->notes);</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+     if (rc == 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+                ast_string_field_set(eprofile, method, src->method);</span><br><span style="color: hsl(120, 100%, 40%);">+       }</span><br><span style="color: hsl(120, 100%, 40%);">+     if (rc == 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+                ast_string_field_set(eprofile, location_source, src->location_source);</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+     if (rc == 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+                rc = DUP_VARS(eprofile->location_info, src->location_info);</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+     if (rc == 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+                rc = DUP_VARS(eprofile->effective_location, src->effective_location);</span><br><span style="color: hsl(120, 100%, 40%);">+   }</span><br><span style="color: hsl(120, 100%, 40%);">+     if (rc == 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+                rc = DUP_VARS(eprofile->location_refinement, src->location_refinement);</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+     if (rc == 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+                rc = DUP_VARS(eprofile->location_variables, src->location_variables);</span><br><span style="color: hsl(120, 100%, 40%);">+   }</span><br><span style="color: hsl(120, 100%, 40%);">+     if (rc == 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+                rc = DUP_VARS(eprofile->usage_rules, src->usage_rules);</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+     if (rc == 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+                rc = DUP_VARS(eprofile->confidence, src->confidence);</span><br><span style="color: hsl(120, 100%, 40%);">+   }</span><br><span style="color: hsl(120, 100%, 40%);">+     if (rc != 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+                ao2_ref(eprofile, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+                return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+  }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ return eprofile;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> struct ast_geoloc_eprofile *ast_geoloc_eprofile_create_from_profile(struct ast_geoloc_profile *profile)</span><br><span> {</span><br><span>        struct ast_geoloc_eprofile *eprofile;</span><br><span>@@ -287,7 +348,7 @@</span><br><span>  return eprofile;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-static struct ast_variable *geoloc_eprofile_resolve_varlist(struct ast_variable *source,</span><br><span style="color: hsl(120, 100%, 40%);">+struct ast_variable *geoloc_eprofile_resolve_varlist(struct ast_variable *source,</span><br><span>         struct ast_variable *variables, struct ast_channel *chan)</span><br><span> {</span><br><span>       struct ast_variable *dest = NULL;</span><br><span>diff --git a/res/res_geolocation/geoloc_private.h b/res/res_geolocation/geoloc_private.h</span><br><span>index 910dbc5..0bd0797 100644</span><br><span>--- a/res/res_geolocation/geoloc_private.h</span><br><span>+++ b/res/res_geolocation/geoloc_private.h</span><br><span>@@ -155,4 +155,8 @@</span><br><span> </span><br><span> struct ast_sorcery *geoloc_get_sorcery(void);</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+struct ast_variable *geoloc_eprofile_resolve_varlist(struct ast_variable *source,</span><br><span style="color: hsl(120, 100%, 40%);">+      struct ast_variable *variables, struct ast_channel *chan);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> #endif /* GEOLOC_PRIVATE_H_ */</span><br><span>diff --git a/res/res_pjsip_geolocation.c b/res/res_pjsip_geolocation.c</span><br><span>index 0ca1e58..d0e8d46 100644</span><br><span>--- a/res/res_pjsip_geolocation.c</span><br><span>+++ b/res/res_pjsip_geolocation.c</span><br><span>@@ -574,7 +574,10 @@</span><br><span>                     session_name);</span><br><span>       }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-   ast_geoloc_eprofile_refresh_location(final_eprofile);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!final_eprofile->effective_location) {</span><br><span style="color: hsl(120, 100%, 40%);">+         ast_geoloc_eprofile_refresh_location(final_eprofile);</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>  if (final_eprofile->format == AST_GEOLOC_FORMAT_URI) {</span><br><span>            uri = ast_geoloc_eprofile_to_uri(final_eprofile, channel, &buf, session_name);</span><br><span>           if (!uri) {</span><br><span></span><br></pre><p>To view, visit <a href="https://gerrit.asterisk.org/c/asterisk/+/19193">change 19193</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/+/19193"/><meta itemprop="name" content="View Change"/></div></div>

<div style="display:none"> Gerrit-Project: asterisk </div>
<div style="display:none"> Gerrit-Branch: master </div>
<div style="display:none"> Gerrit-Change-Id: I75f541db43345509a2e86225bfa4cf8e242e5b6c </div>
<div style="display:none"> Gerrit-Change-Number: 19193 </div>
<div style="display:none"> Gerrit-PatchSet: 1 </div>
<div style="display:none"> Gerrit-Owner: George Joseph <gjoseph@digium.com> </div>
<div style="display:none"> Gerrit-MessageType: newchange </div>