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 ddf855b22a..b543c6e29c 100644 --- a/doc/CHANGES-staging/res_geolocation.txt +++ b/doc/CHANGES-staging/res_geolocation.txt @@ -33,3 +33,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); \