From 261051ecec4468e7bab5840946327b40872fcdaa Mon Sep 17 00:00:00 2001 From: George Joseph Date: Thu, 18 Aug 2022 06:29:09 -0600 Subject: [PATCH] res_geolocation: Allow location parameters on the profile object You can now specify the location object's format, location_info, method, location_source and confidence parameters directly on a profile object for simple scenarios where the location information isn't common with any other profiles. This is mutually exclusive with setting location_reference on the profile. Updated appdocsxml.dtd to allow xi:include in a configObject element. This makes it easier to link to complete configOptions in another object. This is used to add the above fields to the profile object without having to maintain the option descriptions in two places. ASTERISK-30185 Change-Id: Ifd5f05be0a76f0a6ad49fa28d17c394027677569 --- configs/samples/geolocation.conf.sample | 7 + doc/CHANGES-staging/res_geolocation.txt | 7 + doc/appdocsxml.dtd | 4 +- include/asterisk/res_geolocation.h | 5 + res/res_geolocation/geoloc_config.c | 191 +++++++++++++++--------- res/res_geolocation/geoloc_doc.xml | 5 + res/res_geolocation/geoloc_eprofile.c | 14 ++ res/res_geolocation/geoloc_private.h | 10 +- 8 files changed, 162 insertions(+), 81 deletions(-) diff --git a/configs/samples/geolocation.conf.sample b/configs/samples/geolocation.conf.sample index 305f087fb2..5b0052f115 100644 --- a/configs/samples/geolocation.conf.sample +++ b/configs/samples/geolocation.conf.sample @@ -285,6 +285,13 @@ would have an empty element in it. If suppress_empty_ca_elements were set to "yes", the FLR element would be dropped from the PIDF-LO document altogether. +-- format, location_info, location_source, method, confidence --------- +You can specify the location object's format, location_info, +method, location_source and confidence parameters directly on +a profile object for simple scenarios where the location +information isn't common with any other profiles. This is +mutually exclusive with setting location_reference on the +profile. -- Profile Example ---------------------------------------------------- diff --git a/doc/CHANGES-staging/res_geolocation.txt b/doc/CHANGES-staging/res_geolocation.txt index 837b09a03b..deda71ce5e 100644 --- a/doc/CHANGES-staging/res_geolocation.txt +++ b/doc/CHANGES-staging/res_geolocation.txt @@ -11,3 +11,10 @@ set. Added profile parameter "suppress_empty_ca_elements" that will cause Civic Address elements that are empty to be suppressed from the outgoing PIDF-LO document. + +You can now specify the location object's format, location_info, +method, location_source and confidence parameters directly on +a profile object for simple scenarios where the location +information isn't common with any other profiles. This is +mutually exclusive with setting location_reference on the +profile. diff --git a/doc/appdocsxml.dtd b/doc/appdocsxml.dtd index fbcad6ddfe..426d959466 100644 --- a/doc/appdocsxml.dtd +++ b/doc/appdocsxml.dtd @@ -69,10 +69,10 @@ - + - + diff --git a/include/asterisk/res_geolocation.h b/include/asterisk/res_geolocation.h index 87f89a2cdd..378a6c736a 100644 --- a/include/asterisk/res_geolocation.h +++ b/include/asterisk/res_geolocation.h @@ -75,6 +75,8 @@ struct ast_geoloc_profile { AST_DECLARE_STRING_FIELDS( AST_STRING_FIELD(location_reference); AST_STRING_FIELD(notes); + AST_STRING_FIELD(method); + AST_STRING_FIELD(location_source); ); enum ast_geoloc_pidf_element pidf_element; enum ast_geoloc_precedence precedence; @@ -83,6 +85,9 @@ struct ast_geoloc_profile { struct ast_variable *location_variables; struct ast_variable *usage_rules; int suppress_empty_ca_elements; + enum ast_geoloc_format format; + struct ast_variable *location_info; + struct ast_variable *confidence; }; struct ast_geoloc_eprofile { diff --git a/res/res_geolocation/geoloc_config.c b/res/res_geolocation/geoloc_config.c index ee542f046b..dea7a22050 100644 --- a/res/res_geolocation/geoloc_config.c +++ b/res/res_geolocation/geoloc_config.c @@ -67,13 +67,17 @@ static void *geoloc_location_alloc(const char *name) return location; } - CONFIG_ENUM(profile, pidf_element) CONFIG_ENUM(profile, precedence) CONFIG_VAR_LIST(profile, location_refinement) CONFIG_VAR_LIST(profile, location_variables) CONFIG_VAR_LIST(profile, usage_rules) +CONFIG_ENUM_HANDLER(profile, format) +CONFIG_ENUM_TO_STR(profile, format) +CONFIG_VAR_LIST(profile, location_info) +CONFIG_VAR_LIST(profile, confidence) + static void geoloc_profile_destructor(void *obj) { struct ast_geoloc_profile *profile = obj; @@ -81,6 +85,8 @@ static void geoloc_profile_destructor(void *obj) { ast_variables_destroy(profile->location_refinement); ast_variables_destroy(profile->location_variables); ast_variables_destroy(profile->usage_rules); + ast_variables_destroy(profile->location_info); + ast_variables_destroy(profile->confidence); } static void *geoloc_profile_alloc(const char *name) @@ -94,60 +100,83 @@ static void *geoloc_profile_alloc(const char *name) return profile; } -static int geoloc_location_apply_handler(const struct ast_sorcery *sorcery, void *obj) +static enum ast_geoloc_validate_result validate_location_info(const char *id, + enum ast_geoloc_format format, struct ast_variable *location_info) { - struct ast_geoloc_location *location = obj; - const char *location_id = ast_sorcery_object_get_id(location); + enum ast_geoloc_validate_result result; const char *failed; const char *uri; - enum ast_geoloc_validate_result result; - switch (location->format) { + switch (format) { case AST_GEOLOC_FORMAT_NONE: case AST_GEOLOC_FORMAT_LAST: - ast_log(LOG_ERROR, "Location '%s' must have a format\n", location_id); + ast_log(LOG_ERROR, "Location '%s' must have a format\n", id); return -1; case AST_GEOLOC_FORMAT_CIVIC_ADDRESS: - result = ast_geoloc_civicaddr_validate_varlist(location->location_info, &failed); + result = ast_geoloc_civicaddr_validate_varlist(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); - return -1; + id, failed); + return result; } break; case AST_GEOLOC_FORMAT_GML: - result = ast_geoloc_gml_validate_varlist(location->location_info, &failed); + result = ast_geoloc_gml_validate_varlist(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); - return -1; + ast_geoloc_validate_result_to_str(result), failed, id); + return result; } break; case AST_GEOLOC_FORMAT_URI: - uri = ast_variable_find_in_list(location->location_info, "URI"); + uri = ast_variable_find_in_list(location_info, "URI"); if (!uri) { - struct ast_str *str = ast_variable_list_join(location->location_info, ",", "=", "\"", NULL); + struct ast_str *str = ast_variable_list_join(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)); + id, format_names[AST_GEOLOC_FORMAT_URI], ast_str_buffer(str)); ast_free(str); - return -1; + return AST_GEOLOC_VALIDATE_NOT_ENOUGH_VARNAMES; } break; } - if (!ast_strlen_zero(location->location_source)) { + return AST_GEOLOC_VALIDATE_SUCCESS; +} + +static int validate_location_source(const char *id, const char *location_source) +{ + if (!ast_strlen_zero(location_source)) { struct ast_sockaddr loc_source_addr; - int rc = ast_sockaddr_parse(&loc_source_addr, location->location_source, PARSE_PORT_FORBID); + int rc = ast_sockaddr_parse(&loc_source_addr, location_source, PARSE_PORT_FORBID); if (rc == 1) { ast_log(LOG_ERROR, "Geolocation location '%s' location_source '%s' must be a FQDN." " RFC8787 expressly forbids IP addresses.\n", - location_id, location->location_source); + id, location_source); return -1; } } + return 0; +} + +static int geoloc_location_apply_handler(const struct ast_sorcery *sorcery, void *obj) +{ + struct ast_geoloc_location *location = obj; + const char *location_id = ast_sorcery_object_get_id(location); + enum ast_geoloc_validate_result result; + int rc = 0; + + result = validate_location_info(location_id, location->format, location->location_info); + if (result != AST_GEOLOC_VALIDATE_SUCCESS) { + return -1; + } + + rc = validate_location_source(location_id, location->location_source); + if (rc != 0) { + return -1; + } return 0; } @@ -156,48 +185,52 @@ static int geoloc_profile_apply_handler(const struct ast_sorcery *sorcery, void { struct ast_geoloc_profile *profile = obj; struct ast_geoloc_location *location; - const char *profile_id = ast_sorcery_object_get_id(profile); - const char *failed; + const char *id = ast_sorcery_object_get_id(profile); enum ast_geoloc_validate_result result; + enum ast_geoloc_format format; + int rc = 0; - if (ast_strlen_zero(profile->location_reference)) { - if (profile->location_refinement || - profile->location_variables) { - ast_log(LOG_ERROR, "Profile '%s' can't have location_refinement or location_variables without a location_reference", - profile_id); + if (!ast_strlen_zero(profile->location_reference)) { + if (profile->location_info || + profile->format != AST_GEOLOC_FORMAT_NONE) { + ast_log(LOG_ERROR, "Profile '%s' can't have location_reference and location_info or format at the same time", + id); return -1; } return 0; } - location = ast_sorcery_retrieve_by_id(geoloc_sorcery, "location", profile->location_reference); - if (!location) { - ast_log(LOG_ERROR, "Profile '%s' has a location_reference '%s' that doesn't exist", - profile_id, profile->location_reference); - return -1; + if (profile->location_info) { + result = validate_location_info(id, profile->format, profile->location_info); + if (result != AST_GEOLOC_VALIDATE_SUCCESS) { + return -1; + } + + rc = validate_location_source(id, profile->location_source); + if (rc != 0) { + return -1; + } + + return 0; + } + + if (!ast_strlen_zero(profile->location_reference)) { + location = ast_sorcery_retrieve_by_id(geoloc_sorcery, "location", profile->location_reference); + if (!location) { + ast_log(LOG_ERROR, "Profile '%s' has a location_reference '%s' that doesn't exist", + id, profile->location_reference); + return -1; + } + format = location->format; + ao2_ref(location, -1); } if (profile->location_refinement) { - switch (location->format) { - case AST_GEOLOC_FORMAT_NONE: - case AST_GEOLOC_FORMAT_LAST: - break; - case AST_GEOLOC_FORMAT_CIVIC_ADDRESS: - result = ast_geoloc_civicaddr_validate_varlist(profile->location_refinement, &failed); - if (result != AST_GEOLOC_VALIDATE_SUCCESS) { - ast_log(LOG_ERROR, "Profile '%s' error: %s: for item '%s' in the location_refinement\n", - profile_id, ast_geoloc_validate_result_to_str(result), failed); - ao2_ref(location, -1); - return -1; - } - break; - case AST_GEOLOC_FORMAT_GML: - break; - case AST_GEOLOC_FORMAT_URI: - break; + result = validate_location_info(id, format, profile->location_refinement); + if (result != AST_GEOLOC_VALIDATE_SUCCESS) { + return -1; } } - ao2_ref(location, -1); return 0; } @@ -217,7 +250,6 @@ static char *geoloc_config_list_locations(struct ast_cli_entry *e, int cmd, stru int using_regex = 0; char *result = CLI_SUCCESS; int ret = 0; - char *format_name; int count = 0; switch (cmd) { @@ -285,14 +317,12 @@ static char *geoloc_config_list_locations(struct ast_cli_entry *e, int cmd, stru break; } - format_to_str(loc, NULL, &format_name); ast_cli(a->fd, "%-46.46s %-13s %-s\n", ast_sorcery_object_get_id(loc), - format_name, + format_names[loc->format], ast_str_buffer(str)); ao2_unlock(loc); ast_free(str); - ast_free(format_name); count++; } ao2_iterator_destroy(&iter); @@ -311,7 +341,6 @@ static char *geoloc_config_list_profiles(struct ast_cli_entry *e, int cmd, struc int using_regex = 0; char *result = CLI_SUCCESS; int ret = 0; - char *precedence; int count = 0; switch (cmd) { @@ -368,13 +397,11 @@ static char *geoloc_config_list_profiles(struct ast_cli_entry *e, int cmd, struc for (; (profile = ao2_iterator_next(&iter)); ao2_ref(profile, -1)) { ao2_lock(profile); - precedence_to_str(profile, NULL, &precedence); ast_cli(a->fd, "%-46.46s %-16s %-s\n", ast_sorcery_object_get_id(profile), - precedence, + precedence_names[profile->precedence], profile->location_reference); ao2_unlock(profile); - ast_free(precedence); count++; } ao2_iterator_destroy(&iter); @@ -441,7 +468,7 @@ static char *geoloc_config_show_profiles(struct ast_cli_entry *e, int cmd, struc return CLI_FAILURE; } - ast_cli(a->fd, "Geolocation Profile Objects:\n\n"); + ast_cli(a->fd, "Geolocation Profile Objects:\n"); iter = ao2_iterator_init(sorted_container, AO2_ITERATOR_UNLINK); for (; (profile = ao2_iterator_next(&iter)); ) { @@ -450,26 +477,28 @@ static char *geoloc_config_show_profiles(struct ast_cli_entry *e, int cmd, struc struct ast_str *variables_str = NULL; struct ast_str *resolved_str = NULL; struct ast_str *usage_rules_str = NULL; + struct ast_str *confidence_str = NULL; struct ast_geoloc_eprofile *eprofile = ast_geoloc_eprofile_create_from_profile(profile); ao2_ref(profile, -1); - if (!ast_strlen_zero(eprofile->location_reference)) { - loc_str = ast_variable_list_join(eprofile->location_info, ",", "=", "\"", NULL); - resolved_str = ast_variable_list_join(eprofile->effective_location, ",", "=", "\"", 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); usage_rules_str = ast_variable_list_join(eprofile->usage_rules, ",", "=", "\"", NULL); + confidence_str = ast_variable_list_join(eprofile->confidence, ",", "=", "\"", NULL); - ast_cli(a->fd, + ast_cli(a->fd,"\n" "id: %-s\n" "profile_precedence: %-s\n" "pidf_element: %-s\n" "location_reference: %-s\n" - "Location_format: %-s\n" - "location_details: %-s\n" + "location_format: %-s\n" + "location_info: %-s\n" "location_method: %-s\n" + "location_source: %-s\n" + "location_confidence: %-s\n" "location_refinement: %-s\n" "location_variables: %-s\n" "allow_routing_use: %-s\n" @@ -484,6 +513,8 @@ static char *geoloc_config_show_profiles(struct ast_cli_entry *e, int cmd, struc format_names[eprofile->format], S_COR(loc_str, ast_str_buffer(loc_str), ""), S_OR(eprofile->method, ""), + S_OR(eprofile->location_source, ""), + S_COR(confidence_str, ast_str_buffer(confidence_str), ""), S_COR(refinement_str, ast_str_buffer(refinement_str), ""), S_COR(variables_str, ast_str_buffer(variables_str), ""), S_COR(eprofile->allow_routing_use, "yes", "no"), @@ -499,6 +530,7 @@ static char *geoloc_config_show_profiles(struct ast_cli_entry *e, int cmd, struc ast_free(variables_str); ast_free(resolved_str); ast_free(usage_rules_str); + ast_free(confidence_str); count++; } ao2_iterator_destroy(&iter); @@ -643,11 +675,11 @@ int geoloc_config_load(void) 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); + location_format_handler, location_format_to_str, NULL, 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); + location_location_info_handler, location_location_info_to_str, location_location_info_dup, 0, 0); ast_sorcery_object_field_register_custom(geoloc_sorcery, "location", "confidence", NULL, - confidence_handler, confidence_to_str, confidence_dup, 0, 0); + location_confidence_handler, location_confidence_to_str, location_confidence_dup, 0, 0); ast_sorcery_object_field_register(geoloc_sorcery, "location", "location_source", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_geoloc_location, location_source)); ast_sorcery_object_field_register(geoloc_sorcery, "location", "method", "", OPT_STRINGFIELD_T, @@ -678,17 +710,17 @@ int geoloc_config_load(void) ast_sorcery_object_field_register(geoloc_sorcery, "profile", "type", "", OPT_NOOP_T, 0, 0); ast_sorcery_object_field_register_custom(geoloc_sorcery, "profile", "pidf_element", - pidf_element_names[AST_PIDF_ELEMENT_DEVICE], pidf_element_handler, pidf_element_to_str, NULL, 0, 0); + pidf_element_names[AST_PIDF_ELEMENT_DEVICE], profile_pidf_element_handler, profile_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", "profile_precedence", "discard_incoming", - precedence_handler, precedence_to_str, NULL, 0, 0); + profile_precedence_handler, profile_precedence_to_str, NULL, 0, 0); ast_sorcery_object_field_register_custom(geoloc_sorcery, "profile", "usage_rules", NULL, - usage_rules_handler, usage_rules_to_str, usage_rules_dup, 0, 0); + profile_usage_rules_handler, profile_usage_rules_to_str, profile_usage_rules_dup, 0, 0); ast_sorcery_object_field_register_custom(geoloc_sorcery, "profile", "location_info_refinement", NULL, - location_refinement_handler, location_refinement_to_str, location_refinement_dup, 0, 0); + profile_location_refinement_handler, profile_location_refinement_to_str, profile_location_refinement_dup, 0, 0); ast_sorcery_object_field_register_custom(geoloc_sorcery, "profile", "location_variables", NULL, - location_variables_handler, location_variables_to_str, location_variables_dup, 0, 0); + profile_location_variables_handler, profile_location_variables_to_str, profile_location_variables_dup, 0, 0); ast_sorcery_object_field_register(geoloc_sorcery, "profile", "notes", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_geoloc_profile, notes)); ast_sorcery_object_field_register(geoloc_sorcery, "profile", "allow_routing_use", @@ -696,6 +728,17 @@ int geoloc_config_load(void) ast_sorcery_object_field_register(geoloc_sorcery, "profile", "suppress_empty_ca_elements", "no", OPT_BOOL_T, 1, FLDSET(struct ast_geoloc_profile, suppress_empty_ca_elements)); + ast_sorcery_object_field_register_custom(geoloc_sorcery, "profile", "format", AST_GEOLOC_FORMAT_NONE, + profile_format_handler, profile_format_to_str, NULL, 0, 0); + ast_sorcery_object_field_register_custom(geoloc_sorcery, "profile", "location_info", NULL, + profile_location_info_handler, profile_location_info_to_str, profile_location_info_dup, 0, 0); + ast_sorcery_object_field_register_custom(geoloc_sorcery, "profile", "confidence", NULL, + profile_confidence_handler, profile_confidence_to_str, profile_confidence_dup, 0, 0); + ast_sorcery_object_field_register(geoloc_sorcery, "profile", "location_source", "", OPT_STRINGFIELD_T, + 0, STRFLDSET(struct ast_geoloc_profile, location_source)); + ast_sorcery_object_field_register(geoloc_sorcery, "profile", "method", "", OPT_STRINGFIELD_T, + 0, STRFLDSET(struct ast_geoloc_profile, method)); + ast_sorcery_load(geoloc_sorcery); diff --git a/res/res_geolocation/geoloc_doc.xml b/res/res_geolocation/geoloc_doc.xml index 0e1b31dbfc..4f7cdc2339 100644 --- a/res/res_geolocation/geoloc_doc.xml +++ b/res/res_geolocation/geoloc_doc.xml @@ -207,6 +207,11 @@ + + + + + diff --git a/res/res_geolocation/geoloc_eprofile.c b/res/res_geolocation/geoloc_eprofile.c index 5f20612cde..1deb76e654 100644 --- a/res/res_geolocation/geoloc_eprofile.c +++ b/res/res_geolocation/geoloc_eprofile.c @@ -177,11 +177,22 @@ struct ast_geoloc_eprofile *ast_geoloc_eprofile_create_from_profile(struct ast_g eprofile->allow_routing_use = profile->allow_routing_use; eprofile->pidf_element = profile->pidf_element; eprofile->suppress_empty_ca_elements = profile->suppress_empty_ca_elements; + eprofile->format = profile->format; + rc = ast_string_field_set(eprofile, location_reference, profile->location_reference); if (rc == 0) { ast_string_field_set(eprofile, notes, profile->notes); } + if (rc == 0) { + ast_string_field_set(eprofile, method, profile->method); + } + if (rc == 0) { + ast_string_field_set(eprofile, location_source, profile->location_source); + } + if (rc == 0) { + rc = DUP_VARS(eprofile->location_info, profile->location_info); + } if (rc == 0) { rc = DUP_VARS(eprofile->location_refinement, profile->location_refinement); } @@ -191,6 +202,9 @@ struct ast_geoloc_eprofile *ast_geoloc_eprofile_create_from_profile(struct ast_g if (rc == 0) { rc = DUP_VARS(eprofile->usage_rules, profile->usage_rules); } + if (rc == 0) { + rc = DUP_VARS(eprofile->confidence, profile->confidence); + } if (rc != 0) { ao2_unlock(profile); ao2_ref(eprofile, -1); diff --git a/res/res_geolocation/geoloc_private.h b/res/res_geolocation/geoloc_private.h index ff5e2af99f..910dbc5a3a 100644 --- a/res/res_geolocation/geoloc_private.h +++ b/res/res_geolocation/geoloc_private.h @@ -38,7 +38,7 @@ int ast_geoloc_ ## _stem ## _str_to_enum(const char *str) \ } #define CONFIG_ENUM_HANDLER(_object, _stem) \ -static int _stem ## _handler(const struct aco_option *opt, struct ast_variable *var, void *obj) \ +static int _object ## _ ## _stem ## _handler(const struct aco_option *opt, struct ast_variable *var, void *obj) \ { \ struct ast_geoloc_ ## _object *_thisobject = obj; \ int enumval = ast_geoloc_ ## _stem ## _str_to_enum(var->value); \ @@ -61,7 +61,7 @@ const char * ast_geoloc_ ## _stem ## _to_name(int ix) \ } #define CONFIG_ENUM_TO_STR(_object, _stem) \ -static int _stem ## _to_str(const void *obj, const intptr_t *args, char **buf) \ +static int _object ## _ ## _stem ## _to_str(const void *obj, const intptr_t *args, char **buf) \ { \ const struct ast_geoloc_ ## _object *_thisobject = obj; \ if (!ARRAY_IN_BOUNDS(_thisobject->_stem, _stem ## _names)) { \ @@ -79,7 +79,7 @@ CONFIG_ENUM_HANDLER(_object, _stem) \ CONFIG_ENUM_TO_STR(_object, _stem) #define CONFIG_VAR_LIST_HANDLER(_object, _stem) \ -static int _stem ## _handler(const struct aco_option *opt, struct ast_variable *var, void *obj) \ +static int _object ## _ ## _stem ## _handler(const struct aco_option *opt, struct ast_variable *var, void *obj) \ { \ struct ast_geoloc_ ## _object *_thisobject = obj; \ struct ast_variable *new_var; \ @@ -101,7 +101,7 @@ static int _stem ## _handler(const struct aco_option *opt, struct ast_variable * } #define CONFIG_VAR_LIST_DUP(_object, _stem) \ -static int _stem ## _dup(const void *obj, struct ast_variable **fields) \ +static int _object ## _ ## _stem ## _dup(const void *obj, struct ast_variable **fields) \ { \ const struct ast_geoloc_ ## _object *_thisobject = obj; \ if (_thisobject->_stem) { \ @@ -111,7 +111,7 @@ static int _stem ## _dup(const void *obj, struct ast_variable **fields) \ } #define CONFIG_VAR_LIST_TO_STR(_object, _stem) \ -static int _stem ## _to_str(const void *obj, const intptr_t *args, char **buf) \ +static int _object ## _ ## _stem ## _to_str(const void *obj, const intptr_t *args, char **buf) \ { \ const struct ast_geoloc_ ## _object *_thisobject = obj; \ struct ast_str *str = ast_variable_list_join(_thisobject->_stem, ",", "=", "\"", NULL); \