[Asterisk-code-review] res_geolocation: Dialplan function initial commit (asterisk[development/16/geolocation])

George Joseph asteriskteam at digium.com
Wed Mar 9 11:46:49 CST 2022


George Joseph has uploaded this change for review. ( https://gerrit.asterisk.org/c/asterisk/+/18192 )


Change subject: res_geolocation: Dialplan function initial commit
......................................................................

res_geolocation: Dialplan function initial commit

Also did more renames and added additional error checking
to ast_geoloc_eprofile_refresh_location().

Change-Id: Ibbf9bebaf510fd2fc1f535d17cda5d3bb1fa2009
---
M include/asterisk/res_geolocation.h
M main/config.c
M res/res_geolocation/geoloc_config.c
M res/res_geolocation/geoloc_datastore.c
M res/res_geolocation/geoloc_dialplan.c
M res/res_geolocation/geoloc_doc.xml
M res/res_geolocation/geoloc_eprofile.c
M res/res_geolocation/geoloc_private.h
M res/res_pjsip_geolocation.c
9 files changed, 590 insertions(+), 94 deletions(-)



  git pull ssh://gerrit.asterisk.org:29418/asterisk refs/changes/92/18192/1

diff --git a/include/asterisk/res_geolocation.h b/include/asterisk/res_geolocation.h
index 80f1caf..139eb74 100644
--- a/include/asterisk/res_geolocation.h
+++ b/include/asterisk/res_geolocation.h
@@ -24,6 +24,8 @@
 #include "asterisk/xml.h"
 #include "asterisk/optional_api.h"
 
+#define AST_GEOLOC_INVALID_VALUE -1
+
 enum ast_geoloc_pidf_element {
 	AST_PIDF_ELEMENT_NONE = 0,
 	AST_PIDF_ELEMENT_TUPLE,
@@ -38,11 +40,11 @@
 	AST_GEOLOC_FORMAT_URI,
 };
 
-enum ast_geoloc_location_disposition {
-	AST_GEOLOC_LOC_DISP_DISCARD = 0,
-	AST_GEOLOC_LOC_DISP_APPEND,
-	AST_GEOLOC_LOC_DISP_PREPEND,
-	AST_GEOLOC_LOC_DISP_REPLACE,
+enum ast_geoloc_action {
+	AST_GEOLOC_ACTION_DISCARD = 0,
+	AST_GEOLOC_ACTION_APPEND,
+	AST_GEOLOC_ACTION_PREPEND,
+	AST_GEOLOC_ACTION_REPLACE,
 };
 
 struct ast_geoloc_location {
@@ -51,7 +53,7 @@
 		AST_STRING_FIELD(method);
 	);
 	enum ast_geoloc_format format;
-	struct ast_variable *location_vars;
+	struct ast_variable *location_info;
 };
 
 struct ast_geoloc_profile {
@@ -60,12 +62,12 @@
 		AST_STRING_FIELD(location_reference);
 	);
 	enum ast_geoloc_pidf_element pidf_element;
-	enum ast_geoloc_location_disposition location_disposition;
+	enum ast_geoloc_action action;
 	int geolocation_routing;
 	int send_location;
 	struct ast_variable *location_refinement;
 	struct ast_variable *location_variables;
-	struct ast_variable *usage_rules_vars;
+	struct ast_variable *usage_rules;
 };
 
 struct ast_geoloc_eprofile {
@@ -75,15 +77,15 @@
 		AST_STRING_FIELD(method);
 	);
 	enum ast_geoloc_pidf_element pidf_element;
-	enum ast_geoloc_location_disposition location_disposition;
+	enum ast_geoloc_action action;
 	int geolocation_routing;
 	int send_location;
 	enum ast_geoloc_format format;
-	struct ast_variable *location_vars;
+	struct ast_variable *location_info;
 	struct ast_variable *location_refinement;
 	struct ast_variable *location_variables;
 	struct ast_variable *effective_location;
-	struct ast_variable *usage_rules_vars;
+	struct ast_variable *usage_rules;
 };
 
 /*!
@@ -143,13 +145,13 @@
 const char *ast_geoloc_civicaddr_resolve_variable(const char *variable);
 
 enum ast_geoloc_validate_result {
+	AST_GEOLOC_VALIDATE_INVALID_VALUE = -1,
 	AST_GEOLOC_VALIDATE_SUCCESS = 0,
 	AST_GEOLOC_VALIDATE_MISSING_TYPE,
 	AST_GEOLOC_VALIDATE_INVALID_TYPE,
 	AST_GEOLOC_VALIDATE_INVALID_VARNAME,
 	AST_GEOLOC_VALIDATE_NOT_ENOUGH_VARNAMES,
 	AST_GEOLOC_VALIDATE_TOO_MANY_VARNAMES,
-	AST_GEOLOC_VALIDATE_INVALID_VALUE,
 };
 
 const char *ast_geoloc_validate_result_to_str(enum ast_geoloc_validate_result result);
@@ -176,6 +178,12 @@
 enum ast_geoloc_validate_result ast_geoloc_gml_validate_varlist(const struct ast_variable *varlist,
 	const char **result);
 
+
+/*!
+ * \brief Geolocation datastore Functions
+ * @{
+ */
+
 /*!
  * \brief Create a geoloc datastore from a profile name
  *
@@ -195,13 +203,94 @@
 struct ast_datastore *ast_geoloc_datastore_create_from_eprofile(
 	struct ast_geoloc_eprofile *eprofile);
 
+/*!
+ * \brief Create an empty geoloc datastore.
+ *
+ * \param id  An id to use for the datastore.
+ *
+ * \return The datastore.
+ */
 struct ast_datastore *ast_geoloc_datastore_create(const char *id);
+
+/*!
+ * \brief Retrieve a geoloc datastore's id.
+ *
+ * \param ds The datastore
+ *
+ * \return The datastore's id.
+ */
+const char *ast_geoloc_datastore_get_id(struct ast_datastore *ds);
+
+/*!
+ * \brief Add an eprofile to a datastore
+ *
+ * \param ds       The datastore
+ * \param eprofile The eprofile to add.
+ *
+ * \return The number of eprofiles.
+ */
 int ast_geoloc_datastore_add_eprofile(struct ast_datastore *ds,
 	struct ast_geoloc_eprofile *eprofile);
+
+/*!
+ * \brief Retrieves the number of eprofiles in the datastore
+ *
+ * \param ds The datastore
+ *
+ * \return The number of eprofiles.
+ */
 int ast_geoloc_datastore_size(struct ast_datastore *ds);
+
+/*!
+ * \brief Sets the inheritance flag on the datastore
+ *
+ * \param ds      The datastore
+ * \param inherit 1 to allow the datastore to be inherited by other channels
+ *                0 to prevent the datastore to be inherited by other channels
+ *
+ * \return 0 if successful, -1 otherwise.
+ */
+int ast_geoloc_datastore_set_inheritance(struct ast_datastore *ds, int inherit);
+
+/*!
+ * \brief Retrieve a specific eprofile from a datastore by index
+ *
+ * \param ds The datastore
+ * \param ix The index
+ *
+ * \return The effective profile ao2 object with its reference count bumped.
+ */
 struct ast_geoloc_eprofile *ast_geoloc_datastore_get_eprofile(struct ast_datastore *ds, int ix);
 
 /*!
+ * \brief Delete a specific eprofile from a datastore by index
+ *
+ * \param ds The datastore
+ * \param ix The index
+ *
+ * \return 0 if succesful, -1 otherwise.
+ */
+int ast_geoloc_datastore_delete_eprofile(struct ast_datastore *ds, int ix);
+
+/*!
+ * \brief Retrieves the geoloc datastore from a channel, if any
+ *
+ * \param chan Channel
+ *
+ * \return datastore if found, NULL otherwise.
+ */
+struct ast_datastore *ast_geoloc_datastore_find(struct ast_channel *chan);
+
+/*!
+ *  @}
+ */
+
+/*!
+ * \brief Geolocation Effective Profile Functions
+ * @{
+ */
+
+/*!
  * \brief Allocate a new, empty effective profile.
  *
  * \param name The profile's name
@@ -250,4 +339,8 @@
  */
 int ast_geoloc_eprofile_refresh_location(struct ast_geoloc_eprofile *eprofile);
 
+/*!
+ *  @}
+ */
+
 #endif /* INCLUDE_ASTERISK_RES_GEOLOCATION_H_ */
diff --git a/main/config.c b/main/config.c
index 07925bd..dcf1b9a 100644
--- a/main/config.c
+++ b/main/config.c
@@ -746,8 +746,16 @@
 
 	while ((item = ast_strsep_strict(&item_string, item_sep, quote, AST_STRSEP_ALL))) {
 		item_name = ast_strsep_strict(&item, nv_sep, quote, AST_STRSEP_ALL);
+		if (!item_name) {
+			ast_variables_destroy(new_list);
+			return NULL;
+		}
 
 		item_value = ast_strsep_strict(&item, nv_sep, quote, AST_STRSEP_ALL);
+		if (!item_value) {
+			ast_variables_destroy(new_list);
+			return NULL;
+		}
 
 		new_var = ast_variable_new(item_name, item_value, "");
 		if (!new_var) {
diff --git a/res/res_geolocation/geoloc_config.c b/res/res_geolocation/geoloc_config.c
index 309df22..2350463 100644
--- a/res/res_geolocation/geoloc_config.c
+++ b/res/res_geolocation/geoloc_config.c
@@ -38,7 +38,7 @@
 	"URI",
 };
 
-static const char * location_disposition_names[] = {
+static const char * action_names[] = {
 	"discard",
 	"append",
 	"prepend",
@@ -46,13 +46,13 @@
 };
 
 CONFIG_ENUM(location, format)
-CONFIG_VAR_LIST(location, location_vars)
+CONFIG_VAR_LIST(location, location_info)
 
 static void geoloc_location_destructor(void *obj) {
 	struct ast_geoloc_location *location = obj;
 
 	ast_string_field_free_memory(location);
-	ast_variables_destroy(location->location_vars);
+	ast_variables_destroy(location->location_info);
 }
 
 static void *geoloc_location_alloc(const char *name)
@@ -67,10 +67,10 @@
 
 
 CONFIG_ENUM(profile, pidf_element)
-CONFIG_ENUM(profile, location_disposition)
+CONFIG_ENUM(profile, action)
 CONFIG_VAR_LIST(profile, location_refinement)
 CONFIG_VAR_LIST(profile, location_variables)
-CONFIG_VAR_LIST(profile, usage_rules_vars)
+CONFIG_VAR_LIST(profile, usage_rules)
 
 
 static void geoloc_profile_destructor(void *obj) {
@@ -79,7 +79,7 @@
 	ast_string_field_free_memory(profile);
 	ast_variables_destroy(profile->location_refinement);
 	ast_variables_destroy(profile->location_variables);
-	ast_variables_destroy(profile->usage_rules_vars);
+	ast_variables_destroy(profile->usage_rules);
 }
 
 static void *geoloc_profile_alloc(const char *name)
@@ -105,7 +105,7 @@
 		ast_log(LOG_ERROR, "Location '%s' must have a format\n", location_id);
 		return -1;
 	case AST_GEOLOC_FORMAT_CIVIC_ADDRESS:
-		result = ast_geoloc_civicaddr_validate_varlist(location->location_vars, &failed);
+		result = ast_geoloc_civicaddr_validate_varlist(location->location_info, &failed);
 		if (result != AST_GEOLOC_VALIDATE_SUCCESS) {
 			ast_log(LOG_ERROR, "Location '%s' has invalid item '%s' in the location\n",
 				location_id, failed);
@@ -113,7 +113,7 @@
 		}
 		break;
 	case AST_GEOLOC_FORMAT_GML:
-		result = ast_geoloc_gml_validate_varlist(location->location_vars, &failed);
+		result = ast_geoloc_gml_validate_varlist(location->location_info, &failed);
 		if (result != AST_GEOLOC_VALIDATE_SUCCESS) {
 			ast_log(LOG_ERROR, "%s for item '%s' in location '%s'\n",
 				ast_geoloc_validate_result_to_str(result),	failed, location_id);
@@ -122,9 +122,9 @@
 
 		break;
 	case AST_GEOLOC_FORMAT_URI:
-		uri = ast_variable_find_in_list(location->location_vars, "URI");
+		uri = ast_variable_find_in_list(location->location_info, "URI");
 		if (!uri) {
-			struct ast_str *str = ast_variable_list_join(location->location_vars, ",", "=", "\"", NULL);
+			struct ast_str *str = ast_variable_list_join(location->location_info, ",", "=", "\"", NULL);
 
 			ast_log(LOG_ERROR, "Geolocation location '%s' format is set to '%s' but no 'URI' was found in location parameter '%s'\n",
 				location_id, format_names[AST_GEOLOC_FORMAT_URI], ast_str_buffer(str));
@@ -259,7 +259,7 @@
 		struct ast_str *str;
 
 		ao2_lock(loc);
-		str = ast_variable_list_join(loc->location_vars, ",", "=", "\"", NULL);
+		str = ast_variable_list_join(loc->location_info, ",", "=", "\"", NULL);
 		if (!str) {
 			ao2_unlock(loc);
 			ao2_ref(loc, -1);
@@ -295,7 +295,7 @@
 	int using_regex = 0;
 	char *result = CLI_SUCCESS;
 	int ret = 0;
-	char *disposition;
+	char *action;
 	int count = 0;
 
 	switch (cmd) {
@@ -352,14 +352,14 @@
 	for (; (profile = ao2_iterator_next(&iter)); ao2_ref(profile, -1)) {
 		ao2_lock(profile);
 
-		location_disposition_to_str(profile, NULL, &disposition);
+		action_to_str(profile, NULL, &action);
 		ast_cli(a->fd, "%-46.46s %-13s %-6s %-s\n",
 			ast_sorcery_object_get_id(profile),
-			disposition,
+			action,
 			profile->send_location ? "yes" : "no",
 			profile->location_reference);
 		ao2_unlock(profile);
-		ast_free(disposition);
+		ast_free(action);
 		count++;
 	}
 	ao2_iterator_destroy(&iter);
@@ -428,7 +428,7 @@
 
 	iter = ao2_iterator_init(sorted_container, AO2_ITERATOR_UNLINK);
 	for (; (profile = ao2_iterator_next(&iter)); ) {
-		char *disposition = NULL;
+		char *action = NULL;
 		struct ast_str *loc_str = NULL;
 		struct ast_str *refinement_str = NULL;
 		struct ast_str *variables_str = NULL;
@@ -437,14 +437,14 @@
 		ao2_ref(profile, -1);
 
 		if (!ast_strlen_zero(eprofile->location_reference)) {
-			loc_str = ast_variable_list_join(eprofile->location_vars, ",", "=", "\"", NULL);
+			loc_str = ast_variable_list_join(eprofile->location_info, ",", "=", "\"", NULL);
 			resolved_str = ast_variable_list_join(eprofile->effective_location, ",", "=", "\"", NULL);
 		}
 
 		refinement_str = ast_variable_list_join(eprofile->location_refinement, ",", "=", "\"", NULL);
 		variables_str = ast_variable_list_join(eprofile->location_variables, ",", "=", "\"", NULL);
 
-		location_disposition_to_str(eprofile, NULL, &disposition);
+		action_to_str(eprofile, NULL, &action);
 
 		ast_cli(a->fd,
 			"id:                            %-s\n"
@@ -458,7 +458,7 @@
 			"location_variables:            %-s\n"
 			"effective_location:            %-s\n\n",
 			eprofile->id,
-			disposition,
+			action,
 			eprofile->send_location ? "yes" : "no",
 			pidf_element_names[eprofile->pidf_element],
 			S_OR(eprofile->location_reference, "<none>"),
@@ -469,7 +469,7 @@
 			S_COR(resolved_str, ast_str_buffer(resolved_str), "<none>"));
 		ao2_ref(eprofile, -1);
 
-		ast_free(disposition);
+		ast_free(action);
 		ast_free(loc_str);
 		ast_free(refinement_str);
 		ast_free(variables_str);
@@ -573,8 +573,8 @@
 	ast_sorcery_object_field_register(geoloc_sorcery, "location", "type", "", OPT_NOOP_T, 0, 0);
 	ast_sorcery_object_field_register_custom(geoloc_sorcery, "location", "format", AST_GEOLOC_FORMAT_NONE,
 		format_handler, format_to_str, NULL, 0, 0);
-	ast_sorcery_object_field_register_custom(geoloc_sorcery, "location", "location", NULL,
-		location_vars_handler, location_vars_to_str, location_vars_dup, 0, 0);
+	ast_sorcery_object_field_register_custom(geoloc_sorcery, "location", "location_info", NULL,
+		location_info_handler, location_info_to_str, location_info_dup, 0, 0);
 
 	ast_sorcery_apply_default(geoloc_sorcery, "profile", "config", "geolocation.conf,criteria=type=profile");
 	if (ast_sorcery_object_register(geoloc_sorcery, "profile", geoloc_profile_alloc, NULL, geoloc_profile_apply_handler)) {
@@ -589,12 +589,12 @@
 		pidf_element_handler, pidf_element_to_str, NULL, 0, 0);
 	ast_sorcery_object_field_register(geoloc_sorcery, "profile", "location_reference", "", OPT_STRINGFIELD_T,
 		0, STRFLDSET(struct ast_geoloc_profile, location_reference));
-	ast_sorcery_object_field_register_custom(geoloc_sorcery, "profile", "received_location_disposition", "discard",
-		location_disposition_handler, location_disposition_to_str, NULL, 0, 0);
+	ast_sorcery_object_field_register_custom(geoloc_sorcery, "profile", "action", "discard",
+		action_handler, action_to_str, NULL, 0, 0);
 	ast_sorcery_object_field_register(geoloc_sorcery, "profile", "send_location", "no",
 		OPT_BOOL_T, 1, FLDSET(struct ast_geoloc_profile, send_location));
 	ast_sorcery_object_field_register_custom(geoloc_sorcery, "profile", "usage_rules", NULL,
-		usage_rules_vars_handler, usage_rules_vars_to_str, usage_rules_vars_dup, 0, 0);
+		usage_rules_handler, usage_rules_to_str, usage_rules_dup, 0, 0);
 	ast_sorcery_object_field_register_custom(geoloc_sorcery, "profile", "location_refinement", NULL,
 		location_refinement_handler, location_refinement_to_str, location_refinement_dup, 0, 0);
 	ast_sorcery_object_field_register_custom(geoloc_sorcery, "profile", "location_variables", NULL,
diff --git a/res/res_geolocation/geoloc_datastore.c b/res/res_geolocation/geoloc_datastore.c
index 17e2847..e920659 100644
--- a/res/res_geolocation/geoloc_datastore.c
+++ b/res/res_geolocation/geoloc_datastore.c
@@ -19,6 +19,7 @@
 #include "asterisk.h"
 #include "asterisk/astobj2.h"
 #include "asterisk/datastore.h"
+#include "asterisk/channel.h"
 #include "asterisk/res_geolocation.h"
 #include "asterisk/vector.h"
 #include "geoloc_private.h"
@@ -41,11 +42,58 @@
 	ast_free(eds);
 }
 
+static void *geoloc_datastore_duplicate(void *obj)
+{
+	struct eprofiles_datastore *in_eds = obj;
+	struct eprofiles_datastore *out_eds;
+	int rc = 0;
+	int i = 0;
+	int eprofile_count = 0;
+
+	out_eds = ast_calloc(1, sizeof(*out_eds));
+	if (!out_eds) {
+		return NULL;
+	}
+
+	rc = AST_VECTOR_INIT(&out_eds->eprofiles, 2);
+	if (rc != 0) {
+		ast_free(out_eds);
+		return NULL;
+	}
+
+	eprofile_count = AST_VECTOR_SIZE(&in_eds->eprofiles);
+	for (i = 0; i < eprofile_count; i++) {
+		rc = AST_VECTOR_APPEND(&out_eds->eprofiles, ao2_bump(AST_VECTOR_GET(&in_eds->eprofiles, i)));
+		if (rc != 0) {
+			geoloc_datastore_free(out_eds);
+			return NULL;
+		}
+	}
+
+	return out_eds;
+}
+
 static const struct ast_datastore_info geoloc_datastore_info = {
 	.type = GEOLOC_DS_TYPE,
-	.destroy = geoloc_datastore_free
+	.destroy = geoloc_datastore_free,
+	.duplicate = geoloc_datastore_duplicate,
 };
 
+#define IS_GEOLOC_DS(_ds) (_ds && _ds->data && ast_strings_equal(_ds->info->type, GEOLOC_DS_TYPE))
+
+const char *ast_geoloc_datastore_get_id(struct ast_datastore *ds)
+{
+	struct eprofiles_datastore *eds = NULL;
+
+	if (!IS_GEOLOC_DS(ds)) {
+		return NULL;
+	}
+
+	eds = (struct eprofiles_datastore *)ds->data;
+
+	return eds->id;
+}
+
 struct ast_datastore *ast_geoloc_datastore_create(const char *id)
 {
 	struct ast_datastore *ds = NULL;
@@ -88,12 +136,12 @@
 	struct eprofiles_datastore *eds = NULL;
 	int rc = 0;
 
-	if (!ds || !ast_strings_equal(ds->info->type, GEOLOC_DS_TYPE) || !ds->data || !eprofile) {
+	if (!IS_GEOLOC_DS(ds) || !eprofile) {
 		return -1;
 	}
 
 	eds = ds->data;
-	rc = AST_VECTOR_APPEND(&eds->eprofiles, eprofile);
+	rc = AST_VECTOR_APPEND(&eds->eprofiles, ao2_bump(eprofile));
 	if (rc != 0) {
 		ast_log(LOG_ERROR, "Couldn't add eprofile '%s' to geoloc datastore '%s'\n", eprofile->id, eds->id);
 	}
@@ -105,7 +153,7 @@
 {
 	struct eprofiles_datastore *eds = NULL;
 
-	if (!ds || !ast_strings_equal(ds->info->type, GEOLOC_DS_TYPE) || !ds->data) {
+	if (!IS_GEOLOC_DS(ds)) {
 		return -1;
 	}
 
@@ -114,12 +162,21 @@
 	return AST_VECTOR_SIZE(&eds->eprofiles);
 }
 
+int ast_geoloc_datastore_set_inheritance(struct ast_datastore *ds, int inherit)
+{
+	if (!IS_GEOLOC_DS(ds)) {
+		return -1;
+	}
+	ds->inheritance = inherit ? DATASTORE_INHERIT_FOREVER : 0;
+	return 0;
+}
+
 struct ast_geoloc_eprofile *ast_geoloc_datastore_get_eprofile(struct ast_datastore *ds, int ix)
 {
 	struct eprofiles_datastore *eds = NULL;
 	struct ast_geoloc_eprofile *eprofile;
 
-	if (!ds || !ast_strings_equal(ds->info->type, GEOLOC_DS_TYPE) || !ds->data) {
+	if (!IS_GEOLOC_DS(ds)) {
 		return NULL;
 	}
 
@@ -133,6 +190,29 @@
 	return ao2_bump(eprofile);
 }
 
+struct ast_datastore *ast_geoloc_datastore_find(struct ast_channel *chan)
+{
+	return ast_channel_datastore_find(chan, &geoloc_datastore_info, NULL);
+}
+
+int ast_geoloc_datastore_delete_eprofile(struct ast_datastore *ds, int ix)
+{
+	struct eprofiles_datastore *eds = NULL;
+
+	if (!IS_GEOLOC_DS(ds)) {
+		return -1;
+	}
+
+	eds = ds->data;
+
+	if (ix >= AST_VECTOR_SIZE(&eds->eprofiles)) {
+		return -1;
+	}
+
+	AST_VECTOR_REMOVE(&eds->eprofiles, ix, 1);
+	return 0;
+}
+
 struct ast_datastore *ast_geoloc_datastore_create_from_eprofile(
 	struct ast_geoloc_eprofile *eprofile)
 {
diff --git a/res/res_geolocation/geoloc_dialplan.c b/res/res_geolocation/geoloc_dialplan.c
index 776441c..5f5e507 100644
--- a/res/res_geolocation/geoloc_dialplan.c
+++ b/res/res_geolocation/geoloc_dialplan.c
@@ -19,20 +19,297 @@
 #include "asterisk.h"
 #include "asterisk/config.h"
 #include "asterisk/cli.h"
+#include "asterisk/module.h"
+#include "asterisk/channel.h"
+#include "asterisk/pbx.h"
+#include "asterisk/strings.h"
+#include "asterisk/utils.h"
+#include "asterisk/app.h"
 #include "asterisk/res_geolocation.h"
 #include "geoloc_private.h"
 
+static void varlist_to_str(struct ast_variable *list, struct ast_str** buf, size_t len)
+{
+	struct ast_variable *var = list;
+
+	for (; var; var = var->next) {
+		ast_str_append(buf, len, "%s=\"%s\"%s", var->name, var->value, var->next ? "," : "");
+	}
+}
+
+static int geoloc_profile_read(struct ast_channel *chan,
+	const char *cmd, char *data, struct ast_str **buf, ssize_t len)
+{
+	char *parsed_data = ast_strdupa(data);
+	int index = -1;
+	struct ast_datastore *ds;
+	struct ast_geoloc_eprofile *eprofile = NULL;
+	int profile_count = 0;
+
+	AST_DECLARE_APP_ARGS(args,
+		AST_APP_ARG(field);
+		AST_APP_ARG(index);
+	);
+
+	/* Check for zero arguments */
+	if (ast_strlen_zero(parsed_data)) {
+		ast_log(LOG_ERROR, "%s: Cannot call without arguments\n", cmd);
+		return -1;
+	}
+
+	AST_STANDARD_APP_ARGS(args, parsed_data);
+
+	if (ast_strlen_zero(args.field)) {
+		ast_log(LOG_ERROR, "%s: Cannot call without a field to query\n", cmd);
+		return -1;
+	}
+
+	if (!ast_strlen_zero(args.index)) {
+		if (sscanf(args.index, "%30d", &index) != 1) {
+			ast_log(LOG_ERROR, "%s: profile_index '%s' is invalid\n", cmd, args.index);
+			return -1;
+		}
+	}
+
+	ds = ast_geoloc_datastore_find(chan);
+	if (!ds) {
+		ast_log(LOG_NOTICE, "%s: There are no geoloc profiles on this channel\n", cmd);
+		return -1;
+	}
+
+	profile_count = ast_geoloc_datastore_size(ds);
+
+	if (index < 0) {
+		if (ast_strings_equal(args.field, "count")) {
+			ast_str_append(buf, len, "%d", profile_count);
+		} else if (ast_strings_equal(args.field, "inheritable")) {
+			ast_str_append(buf, len, "%d", ds->inheritance ? 1 : 0);
+		} else {
+			ast_log(LOG_ERROR, "%s: Field '%s' is not valid\n", cmd, args.field);
+			return -1;
+		}
+
+		return 0;
+	}
+
+	if (index >= profile_count) {
+		ast_log(LOG_ERROR, "%s: index %d is out of range 0 -> %d\n", cmd, index, profile_count);
+		return -1;
+	}
+
+	eprofile = ast_geoloc_datastore_get_eprofile(ds, index);
+	if (!eprofile) {
+		ast_log(LOG_ERROR, "%s: Internal Error.  Profile at index %d couldn't be retrieved.\n", cmd, index);
+		return -1;
+	}
+
+	if (ast_strings_equal(args.field, "id")) {
+		ast_str_append(buf, len, "%s", eprofile->id);
+	} else if (ast_strings_equal(args.field, "location_reference")) {
+		ast_str_append(buf, len, "%s", eprofile->location_reference);
+	} else if (ast_strings_equal(args.field, "method")) {
+		ast_str_append(buf, len, "%s", eprofile->method);
+	} else if (ast_strings_equal(args.field, "geolocation_routing")) {
+		ast_str_append(buf, len, "%s", eprofile->geolocation_routing ? "yes" : "no");
+	} else if (ast_strings_equal(args.field, "send_location")) {
+		ast_str_append(buf, len, "%s", eprofile->send_location ? "yes" : "no");
+	} else if (ast_strings_equal(args.field, "action")) {
+		ast_str_append(buf, len, "%s", geoloc_action_to_name(eprofile->action));
+	} else if (ast_strings_equal(args.field, "format")) {
+		ast_str_append(buf, len, "%s", geoloc_format_to_name(eprofile->format));
+	} else if (ast_strings_equal(args.field, "pidf_element")) {
+		ast_str_append(buf, len, "%s", geoloc_pidf_element_to_name(eprofile->pidf_element));
+	} else if (ast_strings_equal(args.field, "location_info")) {
+		varlist_to_str(eprofile->location_info, buf, len);
+	} else if (ast_strings_equal(args.field, "location_refinement")) {
+		varlist_to_str(eprofile->location_refinement, buf, len);
+	} else if (ast_strings_equal(args.field, "location_variables")) {
+		varlist_to_str(eprofile->location_variables, buf, len);
+	} else if (ast_strings_equal(args.field, "effective_location")) {
+		varlist_to_str(eprofile->effective_location, buf, len);
+	} else if (ast_strings_equal(args.field, "usage_rules")) {
+		varlist_to_str(eprofile->usage_rules, buf, len);
+	} else {
+		ast_log(LOG_ERROR, "%s: Field '%s' is not valid\n", cmd, args.field);
+		return -1;
+	}
+
+	ao2_ref(eprofile, -1);
+	return 0;
+}
+
+#define TEST_ENUM_VALUE(_cmd, _ep, _field, _value) \
+({ \
+	enum ast_geoloc_ ## _field v; \
+	if (!_ep) { \
+		ast_log(LOG_ERROR, "%s: Field %s requires a valid index\n", _cmd, #_field); \
+		return -1; \
+	} \
+	v = geoloc_ ## _field ## _str_to_enum(_value); \
+	if (v == AST_GEOLOC_INVALID_VALUE) { \
+		ast_log(LOG_ERROR, "%s: %s '%s' is invalid\n", _cmd, #_field, value); \
+		return -1; \
+	} \
+	_ep->_field = v; \
+})
+
+#define TEST_VARLIST(_cmd, _ep, _field, _value) \
+({ \
+	struct ast_variable *_list; \
+	if (!_ep) { \
+		ast_log(LOG_ERROR, "%s: Field %s requires a valid index\n", _cmd, #_field); \
+		return -1; \
+	} \
+	_list = ast_variable_list_from_string(_value, ",", "=", "\"" ); \
+	if (!_list) { \
+		ast_log(LOG_ERROR, "%s: %s '%s' is malformed or contains invalid values", _cmd, #_field, _value); \
+		return -1; \
+	} \
+	ast_variables_destroy(_ep->_field); \
+	_ep->_field = _list; \
+})
+
+static int geoloc_profile_write(struct ast_channel *chan, const char *cmd, char *data,
+	 const char *value)
+{
+	char *parsed_data = ast_strdupa(data);
+	struct ast_datastore *ds;
+	RAII_VAR(struct ast_geoloc_eprofile *, eprofile, NULL, ao2_cleanup);
+	int profile_count = 0;
+	int index = -1;
+
+	AST_DECLARE_APP_ARGS(args,
+		AST_APP_ARG(field);
+		AST_APP_ARG(index);
+	);
+
+	/* Check for zero arguments */
+	if (ast_strlen_zero(parsed_data)) {
+		ast_log(LOG_ERROR, "%s: Cannot call without arguments\n", cmd);
+		return -1;
+	}
+
+	AST_STANDARD_APP_ARGS(args, parsed_data);
+
+	if (ast_strlen_zero(args.field)) {
+		ast_log(LOG_ERROR, "%s: Cannot call without a field to set\n", cmd);
+		return -1;
+	}
+
+	if (!ast_strlen_zero(args.index)) {
+		if (sscanf(args.index, "%30d", &index) != 1) {
+			ast_log(LOG_ERROR, "%s: profile_index '%s' is invalid\n", cmd, args.index);
+			return -1;
+		}
+	}
+
+	ds = ast_geoloc_datastore_find(chan);
+	if (!ds) {
+		ast_log(LOG_WARNING, "%s: There are no geoloc profiles on this channel\n", cmd);
+		return -1;
+	}
+
+	profile_count = ast_geoloc_datastore_size(ds);
+
+	if (index >= 0 && index < profile_count) {
+		eprofile = ast_geoloc_datastore_get_eprofile(ds, index);
+		if (!eprofile) {
+			ast_log(LOG_ERROR, "%s: Internal Error.  Profile at index %d couldn't be retrieved.\n", cmd, index);
+			return -1;
+		}
+	} else if (index >= profile_count) {
+		ast_log(LOG_ERROR, "%s: index %d is out of range 0 -> %d\n", cmd, index, profile_count);
+		return -1;
+	} else {
+		if (ast_strings_equal(args.field, "inheritable")) {
+			ast_geoloc_datastore_set_inheritance(ds, ast_true(value));
+ 		} else {
+			ast_log(LOG_ERROR, "%s: Field '%s' is not valid or requires a profile index\n", cmd, args.field);
+			return -1;
+		}
+
+		return 0;
+	}
+
+	if (ast_strings_equal(args.field, "all")) {
+		char *v = ast_strdupa(value);
+		if (ast_strlen_zero(ast_strip_quoted(v, "'\"", "'\""))) {
+			ast_geoloc_datastore_delete_eprofile(ds, index);
+			return 0;
+		} else {
+			ast_log(LOG_ERROR, "%s: Only an empty string is valid for field 'all'\n", cmd);
+			return -1;
+		}
+
+	} else if (ast_strings_equal(args.field, "location_reference")) {
+		struct ast_geoloc_location *loc = ast_geoloc_get_location(value);
+		ao2_cleanup(loc);
+		if (!loc) {
+			ast_log(LOG_ERROR, "%s: Location reference '%s' doesn't exist\n", cmd, value);
+			return -1;
+		}
+		ast_string_field_set(eprofile, location_reference, value);
+	} else if (ast_strings_equal(args.field, "method")) {
+		ast_string_field_set(eprofile, method, value);
+
+	} else if (ast_strings_equal(args.field, "geolocation_routing")) {
+		eprofile->geolocation_routing = ast_true(value);
+
+	} else if (ast_strings_equal(args.field, "send_location")) {
+		eprofile->send_location = ast_true(value);
+
+	} else if (ast_strings_equal(args.field, "action")) {
+		TEST_ENUM_VALUE(cmd, eprofile, action, value);
+
+	} else if (ast_strings_equal(args.field, "format")) {
+		TEST_ENUM_VALUE(cmd, eprofile, format, value);
+
+	} else if (ast_strings_equal(args.field, "pidf_element")) {
+		TEST_ENUM_VALUE(cmd, eprofile, pidf_element, value);
+
+	} else if (ast_strings_equal(args.field, "location_info")) {
+		TEST_VARLIST(cmd, eprofile, location_info, value);
+	} else if (ast_strings_equal(args.field, "location_refinement")) {
+		TEST_VARLIST(cmd, eprofile, location_refinement, value);
+	} else if (ast_strings_equal(args.field, "location_variables")) {
+		TEST_VARLIST(cmd, eprofile, location_variables, value);
+	} else if (ast_strings_equal(args.field, "effective_location")) {
+		TEST_VARLIST(cmd, eprofile, effective_location, value);
+	} else if (ast_strings_equal(args.field, "usage_rules")) {
+		TEST_VARLIST(cmd, eprofile, usage_rules, value);
+	} else {
+		ast_log(LOG_ERROR, "%s: Field '%s' is not valid\n", cmd, args.field);
+		return -1;
+	}
+
+	ast_geoloc_eprofile_refresh_location(eprofile);
+	return 0;
+}
+
+static struct ast_custom_function geoloc_function = {
+	.name = "GEOLOC_PROFILE",
+	.read2 = geoloc_profile_read,
+	.write = geoloc_profile_write,
+};
+
 int geoloc_dialplan_unload(void)
 {
+	ast_custom_function_unregister(&geoloc_function);
+
 	return AST_MODULE_LOAD_SUCCESS;
 }
 
 int geoloc_dialplan_load(void)
 {
-	return AST_MODULE_LOAD_SUCCESS;
+	int res = 0;
+
+	res = ast_custom_function_register(&geoloc_function);
+
+	return res == 0 ? AST_MODULE_LOAD_SUCCESS : AST_MODULE_LOAD_DECLINE;
 }
 
 int geoloc_dialplan_reload(void)
 {
 	return AST_MODULE_LOAD_SUCCESS;
 }
+
diff --git a/res/res_geolocation/geoloc_doc.xml b/res/res_geolocation/geoloc_doc.xml
index 8322585..45f1fc9 100644
--- a/res/res_geolocation/geoloc_doc.xml
+++ b/res/res_geolocation/geoloc_doc.xml
@@ -41,8 +41,8 @@
 						</enumlist>
 					</description>
 				</configOption>
-				<configOption name="location" default="">
-					<synopsis>Location Data</synopsis>
+				<configOption name="location_info" default="">
+					<synopsis>Location information</synopsis>
 					<description>
 						<para>The contents of this parameter are specific to the
 							specification type.</para>
@@ -89,7 +89,7 @@
 						<para>xxxx</para>
 					</description>
 				</configOption>
-				<configOption name="received_location_disposition" default="no">
+				<configOption name="action" default="no">
 					<synopsis>Determine whether the location information supplied to a
 						channel should be used</synopsis>
 					<description>
@@ -134,5 +134,18 @@
 			</configObject>
 		</configFile>
 	</configInfo>
+	<function name="GEOLOC_PROFILE" language="en_US">
+		<synopsis>
+			Get or Set a field in a geolocation profile
+		</synopsis>
+		<syntax>
+			<parameter name="field" required="true">
+				<para>The profile field to operate on.</para>
+			</parameter>
+			<parameter name="index" required="false">
+				<para>The index of the profile to operate on.  Not required for the special fields.</para>
+			</parameter>
+		</syntax>
+	</function>
 </docs>
 
diff --git a/res/res_geolocation/geoloc_eprofile.c b/res/res_geolocation/geoloc_eprofile.c
index 2fecd62..0c09d9d 100644
--- a/res/res_geolocation/geoloc_eprofile.c
+++ b/res/res_geolocation/geoloc_eprofile.c
@@ -32,15 +32,29 @@
 
 static struct ast_sorcery *geoloc_sorcery;
 
+#define DUP_VARS(_dest, _source) \
+({ \
+	int _rc = 0; \
+	if (_source) { \
+		struct ast_variable *_vars = ast_variables_dup(_source); \
+		if (!_vars) { \
+			_rc = -1; \
+		} else { \
+			_dest = _vars; \
+		} \
+	} \
+	(_rc); \
+})
+
 static void geoloc_effective_profile_destructor(void *obj) {
 	struct ast_geoloc_eprofile *eprofile = obj;
 
 	ast_string_field_free_memory(eprofile);
-	ast_variables_destroy(eprofile->location_vars);
+	ast_variables_destroy(eprofile->location_info);
 	ast_variables_destroy(eprofile->location_refinement);
 	ast_variables_destroy(eprofile->location_variables);
 	ast_variables_destroy(eprofile->effective_location);
-	ast_variables_destroy(eprofile->usage_rules_vars);
+	ast_variables_destroy(eprofile->usage_rules);
 }
 
 struct ast_geoloc_eprofile *ast_geoloc_eprofile_alloc(const char *name)
@@ -57,7 +71,14 @@
 int ast_geoloc_eprofile_refresh_location(struct ast_geoloc_eprofile *eprofile)
 {
 	struct ast_geoloc_location *loc = NULL;
+	struct ast_variable *temp_locinfo = NULL;
+	struct ast_variable *temp_effloc = NULL;
 	struct ast_variable *var;
+	int rc = 0;
+
+	if (!eprofile) {
+		return -1;
+	}
 
 	if (!ast_strlen_zero(eprofile->location_reference)) {
 		loc = ast_sorcery_retrieve_by_id(geoloc_sorcery, "location", eprofile->location_reference);
@@ -68,45 +89,46 @@
 		}
 
 		eprofile->format = loc->format;
-
-		ast_variables_destroy(eprofile->location_vars);
-		eprofile->location_vars = loc->location_vars ? ast_variables_dup(loc->location_vars) : NULL;
+		rc = DUP_VARS(temp_locinfo, loc->location_info);
 		ao2_ref(loc, -1);
-		loc = NULL;
+		if (rc != 0) {
+			return -1;
+		}
+	} else {
+		temp_locinfo = eprofile->location_info;
 	}
 
-	ast_variables_destroy(eprofile->effective_location);
-	eprofile->effective_location = eprofile->location_vars ? ast_variables_dup(eprofile->location_vars) : NULL;
+	rc = DUP_VARS(temp_effloc, temp_locinfo);
+	if (rc != 0) {
+		ast_variables_destroy(temp_locinfo);
+		return -1;
+	}
 
 	if (eprofile->location_refinement) {
 		for (var = eprofile->location_refinement; var; var = var->next) {
 			struct ast_variable *newvar = ast_variable_new(var->name, var->value, "");
-			if (ast_variable_list_replace(&eprofile->effective_location, newvar)) {
-				ast_variable_list_append(&eprofile->effective_location, newvar);
+			if (!newvar) {
+				ast_variables_destroy(temp_locinfo);
+				ast_variables_destroy(temp_effloc);
+				return -1;
+			}
+			if (ast_variable_list_replace(&temp_effloc, newvar)) {
+				ast_variable_list_append(&temp_effloc, newvar);
 			}
 		}
 	}
 
+	ast_variables_destroy(eprofile->location_info);
+	eprofile->location_info = temp_locinfo;
+	ast_variables_destroy(eprofile->effective_location);
+	eprofile->effective_location = temp_effloc;
+
 	return 0;
 }
 
-#define DUP_VARS(_dest, _source) \
-({ \
-	int _rc = 0; \
-	if (_source) { \
-		struct ast_variable *_vars = ast_variables_dup(_source); \
-		if (!_vars) { \
-			_rc = -1; \
-		} else { \
-			_dest = _vars; \
-		} \
-	} \
-	(_rc); \
-})
-
-struct ast_geoloc_effective_profile *ast_geoloc_eprofile_create_from_profile(struct ast_geoloc_profile *profile)
+struct ast_geoloc_eprofile *ast_geoloc_eprofile_create_from_profile(struct ast_geoloc_profile *profile)
 {
-	struct ast_geoloc_effective_profile *eprofile;
+	struct ast_geoloc_eprofile *eprofile;
 	const char *profile_id;
 	int rc = 0;
 
@@ -131,7 +153,7 @@
 		rc = DUP_VARS(eprofile->location_variables, profile->location_variables);
 	}
 	if (rc == 0) {
-		rc = DUP_VARS(eprofile->usage_rules_vars, profile->usage_rules_vars);
+		rc = DUP_VARS(eprofile->usage_rules, profile->usage_rules);
 	}
 	if (rc != 0) {
 		ao2_unlock(profile);
@@ -139,7 +161,7 @@
 		return NULL;
 	}
 
-	eprofile->location_disposition = profile->location_disposition;
+	eprofile->action = profile->action;
 	eprofile->send_location = profile->send_location;
 	ao2_unlock(profile);
 
@@ -176,7 +198,7 @@
 	}
 
 	eprofile->format = AST_GEOLOC_FORMAT_URI;
-	eprofile->location_vars = ast_variable_new("URI", local_uri, "");
+	eprofile->location_info = ast_variable_new("URI", local_uri, "");
 
 	return eprofile;
 }
@@ -227,8 +249,8 @@
 
 	location_str = ast_xml_get_text(location_info);
 	duped = ast_strdupa(location_str);
-	eprofile->location_vars = ast_variable_list_from_string(duped, ",", "=", "\"");
-	if (!eprofile->location_vars) {
+	eprofile->location_info = ast_variable_list_from_string(duped, ",", "=", "\"");
+	if (!eprofile->location_info) {
 		ao2_ref(eprofile, -1);
 		ast_log(LOG_ERROR, "%s: Unable to create location variables from '%s'\n", reference_string, location_str);
 		return NULL;
@@ -236,7 +258,7 @@
 
 	usage_str = ast_xml_get_text(usage_rules);
 	duped = ast_strdupa(usage_str);
-	eprofile->usage_rules_vars = ast_variable_list_from_string(duped, ",", "=", "\"");
+	eprofile->usage_rules = ast_variable_list_from_string(duped, ",", "=", "\"");
 
 	method_str = ast_xml_get_text(method);
 	ast_string_field_set(eprofile, method, method_str);
@@ -382,8 +404,8 @@
 	eprofile = ast_geoloc_eprofile_create_from_uri("http://some_uri&a=b", __func__);
 	ast_test_validate(test, eprofile != NULL);
 	ast_test_validate(test, eprofile->format == AST_GEOLOC_FORMAT_URI);
-	ast_test_validate(test, eprofile->location_vars != NULL);
-	uri = ast_variable_find_in_list(eprofile->location_vars, "URI");
+	ast_test_validate(test, eprofile->location_info != NULL);
+	uri = ast_variable_find_in_list(eprofile->location_info, "URI");
 	ast_test_validate(test, uri != NULL);
 	ast_test_validate(test, strcmp(uri, "http://some_uri&a=b") == 0);
 
@@ -426,13 +448,13 @@
 	ast_test_validate(test, eprofile->format == format);
 	ast_test_validate(test, ast_strings_equal(eprofile->method, method));
 
-	str = ast_variable_list_join(eprofile->location_vars, ",", "=", NULL, NULL);
+	str = ast_variable_list_join(eprofile->location_info, ",", "=", NULL, NULL);
 	ast_test_validate(test, str != NULL);
 	ast_test_status_update(test, "location_vars: %s\n", ast_str_buffer(str));
 	ast_test_validate(test, ast_strings_equal(ast_str_buffer(str), location));
 	ast_free(str);
 
-	str = ast_variable_list_join(eprofile->usage_rules_vars, ",", "=", "'", NULL);
+	str = ast_variable_list_join(eprofile->usage_rules, ",", "=", "'", NULL);
 	ast_test_validate(test, str != NULL);
 	ast_test_status_update(test, "usage_rules: %s\n", ast_str_buffer(str));
 	ast_test_validate(test, ast_strings_equal(ast_str_buffer(str), usage));
diff --git a/res/res_geolocation/geoloc_private.h b/res/res_geolocation/geoloc_private.h
index c5ea981..18b51a7 100644
--- a/res/res_geolocation/geoloc_private.h
+++ b/res/res_geolocation/geoloc_private.h
@@ -28,11 +28,11 @@
 #define CONFIG_STR_TO_ENUM_DECL(_stem) int geoloc_ ## _stem ## _str_to_enum(const char *str);
 CONFIG_STR_TO_ENUM_DECL(pidf_element)
 CONFIG_STR_TO_ENUM_DECL(format);
-CONFIG_STR_TO_ENUM_DECL(location_disposition);
+CONFIG_STR_TO_ENUM_DECL(action);
 #define GEOLOC_ENUM_TO_NAME_DECL(_stem) const char * geoloc_ ## _stem ## _to_name(int ix);
 GEOLOC_ENUM_TO_NAME_DECL(pidf_element)
 GEOLOC_ENUM_TO_NAME_DECL(format);
-GEOLOC_ENUM_TO_NAME_DECL(location_disposition);
+GEOLOC_ENUM_TO_NAME_DECL(action);
 
 
 #define CONFIG_STR_TO_ENUM(_stem) \
diff --git a/res/res_pjsip_geolocation.c b/res/res_pjsip_geolocation.c
index cd8ba79..8e3156b 100644
--- a/res/res_pjsip_geolocation.c
+++ b/res/res_pjsip_geolocation.c
@@ -145,7 +145,7 @@
 			"%s: Couldn't allocate a geoloc datastore\n", session_name);
 	}
 
-	if (config_profile->location_disposition == AST_GEOLOC_LOC_DISP_DISCARD) {
+	if (config_profile->action == AST_GEOLOC_ACTION_DISCARD) {
 		ast_trace(4, "%s: Profile '%s' location_disposition is 'discard' so "
 			"discarding Geolocation: " PJSTR_PRINTF_SPEC, session_name,
 			ast_sorcery_object_get_id(config_profile),
@@ -164,17 +164,17 @@
 				config_eprofile->id);
 		}
 
+		ast_channel_lock(channel);
 		ast_channel_datastore_add(channel, ds);
+		ast_channel_unlock(channel);
 		/*
-		 * We gave our eprofile reference to the datastore and the
-		 * datastore to the channel so don't let RAII_VAR clean them up.
+		 * We gave the datastore to the channel so don't let RAII_VAR clean it up.
 		 */
-		config_eprofile = NULL;
 		ds = NULL;
 
 		SCOPE_EXIT_RTN_VALUE(0, "%s: Added geoloc datastore with 1 eprofile\n",
 			session_name);
-	} else if (config_profile->location_disposition == AST_GEOLOC_LOC_DISP_PREPEND) {
+	} else if (config_profile->action == AST_GEOLOC_ACTION_PREPEND) {
 		ast_trace(4, "%s: Profile '%s' location_disposition is 'prepend' so "
 			"adding to datastore first", session_name, ast_sorcery_object_get_id(config_profile));
 
@@ -190,16 +190,17 @@
 				"%s: Couldn't add eprofile '%s' to datastore\n", session_name,
 				config_eprofile->id);
 		}
-		config_eprofile = NULL;
 
 		if (!geoloc_hdr) {
+			ast_channel_lock(channel);
 			ast_channel_datastore_add(channel, ds);
+			ast_channel_unlock(channel);
 			ds = NULL;
 
 			SCOPE_EXIT_RTN_VALUE(0, "%s: No Geolocation header so just adding config profile "
 				"'%s' to datastore\n", session_name, ast_sorcery_object_get_id(config_profile));
 		}
-	} else if (config_profile->location_disposition == AST_GEOLOC_LOC_DISP_REPLACE) {
+	} else if (config_profile->action == AST_GEOLOC_ACTION_REPLACE) {
 		if (geoloc_hdr) {
 			ast_trace(4, "%s: Profile '%s' location_disposition is 'replace' so "
 				"we don't need to do anything with the configured profile", session_name,
@@ -275,19 +276,19 @@
 
 			eprofile = ast_geoloc_eprofile_create_from_pidf(incoming_doc, session_name);
 		}
-		eprofile->location_disposition = config_profile->location_disposition;
+		eprofile->action = config_profile->action;
 		eprofile->send_location = config_profile->send_location;
 
 		ast_trace(4, "Processing URI '%s'.  Adding to datastore\n", geoloc_uri);
 		rc = ast_geoloc_datastore_add_eprofile(ds, eprofile);
+		ao2_ref(eprofile, -1);
 		if (rc != 0) {
-			ao2_ref(eprofile, -1);
 			ast_log(LOG_WARNING, "%s: Unable to add effective profile for URI '%s' to datastore.  Skipping\n",
 				session_name, geoloc_uri);
 		}
 	}
 
-	if (config_profile->location_disposition == AST_GEOLOC_LOC_DISP_APPEND) {
+	if (config_profile->action == AST_GEOLOC_ACTION_APPEND) {
 		ast_trace(4, "%s: Profile '%s' location_disposition is 'prepend' so "
 			"adding to datastore first", session_name, ast_sorcery_object_get_id(config_profile));
 
@@ -313,7 +314,9 @@
 			session_name);
 	}
 
+	ast_channel_lock(channel);
 	ast_channel_datastore_add(channel, ds);
+	ast_channel_unlock(channel);
 	ds = NULL;
 
 	SCOPE_EXIT_RTN_VALUE(0, "%s: Added geoloc datastore with %" PRIu64 " eprofiles\n",

-- 
To view, visit https://gerrit.asterisk.org/c/asterisk/+/18192
To unsubscribe, or for help writing mail filters, visit https://gerrit.asterisk.org/settings

Gerrit-Project: asterisk
Gerrit-Branch: development/16/geolocation
Gerrit-Change-Id: Ibbf9bebaf510fd2fc1f535d17cda5d3bb1fa2009
Gerrit-Change-Number: 18192
Gerrit-PatchSet: 1
Gerrit-Owner: George Joseph <gjoseph at digium.com>
Gerrit-MessageType: newchange
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.digium.com/pipermail/asterisk-code-review/attachments/20220309/367d6375/attachment-0001.html>


More information about the asterisk-code-review mailing list