res_geolocation: Add profile parameter suppress_empty_ca_elements

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.

Fixed a possible SEGV if a sub-parameter value didn't have a
value.

ASTERISK-30177

Change-Id: I924ccc5aa2f45110a3155b22e53dfaf3ef2092dd
pull/27/head
George Joseph 3 years ago committed by Friendly Automation
parent 2d5a6498dd
commit 4ffc5561c4

@ -170,8 +170,9 @@ location_source = sip1.myserver.net
Defines the object type. Defines the object type.
type = profile type = profile
-- profile_precedence (optional) ------------------------------------------ -- profile_precedence (optional) --------------------------------------
Sets how to reconcile incoming and configured profiles. Sets how to reconcile incoming and configured profiles.
profile_precedence = < prefer_incoming | prefer_config | discard_incoming profile_precedence = < prefer_incoming | prefer_config | discard_incoming
| discard_config > | discard_config >
@ -202,7 +203,9 @@ profile_precedence = prefer_config
-- pidf_element (optional) -------------------------------------------- -- pidf_element (optional) --------------------------------------------
PIDF-LO element in which to place the location description. PIDF-LO element in which to place the location description.
pidf_element = < tuple | device | person > pidf_element = < tuple | device | person >
Default: device
If the format is civicAddress or GML, this sets the PIDF element into If the format is civicAddress or GML, this sets the PIDF element into
which the location information will be placed. which the location information will be placed.
@ -217,10 +220,12 @@ Per [RFC5491], "device" is preferred and therefore the default.
Example: Example:
pidf_element = tuple pidf_element = tuple
-- allow_routing_use (optional) ------------------------------------- -- allow_routing_use (optional) ---------------------------------------
Sets whether the "Geolocation-Routing" header is added to outgoing Sets whether the "Geolocation-Routing" header is added to outgoing
requests. requests.
allow_routing_use = < yes | no > allow_routing_use = < yes | no >
Default: no
Set to "yes" to indicate that servers later in the path Set to "yes" to indicate that servers later in the path
can use the location information for routing purposes. Set to "no" can use the location information for routing purposes. Set to "no"
@ -253,7 +258,7 @@ floor and room just for this profile
Example: Example:
location_info_refinement = floor=20, room=20a2 location_info_refinement = floor=20, room=20a2
-- location_variables ------------------------------------------------- -- location_variables (optional) --------------------------------------
If the referenced Location object uses any replacement variables, they If the referenced Location object uses any replacement variables, they
can be assigned here. There is no need to define variables that come can be assigned here. There is no need to define variables that come
@ -261,6 +266,26 @@ from the channel using this profile. They get assigned automatically.
location_variables = myfloor=20, myroom=222 location_variables = myfloor=20, myroom=222
-- suppress_empty_ca_elements (optional) ------------------------------
Sets whether empty values for Civic Address elements should be
suppressed from the outgoing PIDF-LO document.
suppress_empty_ca_elements = < yes | no >
Default: no
Setting to "yes" allows you to define a location info template
with channel variables that may or may not exist.
For example, with:
location_info_refinement = FLR=${MyFlr}
suppress_empty_ca_elements = no ; the default
If the MyFlr channel variable weren't set, the outgoing PIDF-LO document
would have an empty <FLR/> element in it. If suppress_empty_ca_elements
were set to "yes", the FLR element would be dropped from the PIDF-LO
document altogether.
-- Profile Example ---------------------------------------------------- -- Profile Example ----------------------------------------------------
[myprofile] [myprofile]

@ -30,3 +30,6 @@ Added 4 built-in profiles:
The profiles are empty except for having their precedence The profiles are empty except for having their precedence
set. 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.

@ -82,6 +82,7 @@ struct ast_geoloc_profile {
struct ast_variable *location_refinement; struct ast_variable *location_refinement;
struct ast_variable *location_variables; struct ast_variable *location_variables;
struct ast_variable *usage_rules; struct ast_variable *usage_rules;
int suppress_empty_ca_elements;
}; };
struct ast_geoloc_eprofile { struct ast_geoloc_eprofile {
@ -102,6 +103,7 @@ struct ast_geoloc_eprofile {
struct ast_variable *effective_location; struct ast_variable *effective_location;
struct ast_variable *usage_rules; struct ast_variable *usage_rules;
struct ast_variable *confidence; struct ast_variable *confidence;
int suppress_empty_ca_elements;
}; };
/*! /*!

@ -13,6 +13,7 @@
<xsl:output method="xml" indent="yes"/> <xsl:output method="xml" indent="yes"/>
<xsl:strip-space elements="*"/> <xsl:strip-space elements="*"/>
<xsl:param name="suppress_empty_ca_elements" select="false()"/>
<!-- REMINDER: The "match" and "select" xpaths refer to the input document, <!-- REMINDER: The "match" and "select" xpaths refer to the input document,
not the output document --> not the output document -->
@ -80,9 +81,11 @@
each element, adding the "ca" namespace --> each element, adding the "ca" namespace -->
<xsl:template match="civicAddress/*"> <xsl:template match="civicAddress/*">
<xsl:element name="ca:{name()}"> <xsl:if test="not($suppress_empty_ca_elements) or boolean(node())">
<xsl:value-of select="."/> <xsl:element name="ca:{name()}">
</xsl:element> <xsl:value-of select="."/>
</xsl:element>
</xsl:if>
</xsl:template> </xsl:template>
<xsl:template match="location-info/civicAddress"> <xsl:template match="location-info/civicAddress">

@ -445,7 +445,6 @@ static char *geoloc_config_show_profiles(struct ast_cli_entry *e, int cmd, struc
iter = ao2_iterator_init(sorted_container, AO2_ITERATOR_UNLINK); iter = ao2_iterator_init(sorted_container, AO2_ITERATOR_UNLINK);
for (; (profile = ao2_iterator_next(&iter)); ) { for (; (profile = ao2_iterator_next(&iter)); ) {
char *action = NULL;
struct ast_str *loc_str = NULL; struct ast_str *loc_str = NULL;
struct ast_str *refinement_str = NULL; struct ast_str *refinement_str = NULL;
struct ast_str *variables_str = NULL; struct ast_str *variables_str = NULL;
@ -463,24 +462,23 @@ static char *geoloc_config_show_profiles(struct ast_cli_entry *e, int cmd, struc
variables_str = ast_variable_list_join(eprofile->location_variables, ",", "=", "\"", NULL); variables_str = ast_variable_list_join(eprofile->location_variables, ",", "=", "\"", NULL);
usage_rules_str = ast_variable_list_join(eprofile->usage_rules, ",", "=", "\"", NULL); usage_rules_str = ast_variable_list_join(eprofile->usage_rules, ",", "=", "\"", NULL);
precedence_to_str(eprofile, NULL, &action);
ast_cli(a->fd, ast_cli(a->fd,
"id: %-s\n" "id: %-s\n"
"profile_disposition: %-s\n" "profile_precedence: %-s\n"
"pidf_element: %-s\n" "pidf_element: %-s\n"
"location_reference: %-s\n" "location_reference: %-s\n"
"Location_format: %-s\n" "Location_format: %-s\n"
"location_details: %-s\n" "location_details: %-s\n"
"location_method: %-s\n" "location_method: %-s\n"
"location_refinement: %-s\n" "location_refinement: %-s\n"
"location_variables: %-s\n" "location_variables: %-s\n"
"allow_routing_use: %-s\n" "allow_routing_use: %-s\n"
"effective_location: %-s\n" "suppress_empty_elements: %-s\n"
"usage_rules: %-s\n" "effective_location: %-s\n"
"notes: %-s\n", "usage_rules: %-s\n"
"notes: %-s\n",
eprofile->id, eprofile->id,
action, precedence_names[eprofile->precedence],
pidf_element_names[eprofile->pidf_element], pidf_element_names[eprofile->pidf_element],
S_OR(eprofile->location_reference, "<none>"), S_OR(eprofile->location_reference, "<none>"),
format_names[eprofile->format], format_names[eprofile->format],
@ -488,14 +486,14 @@ static char *geoloc_config_show_profiles(struct ast_cli_entry *e, int cmd, struc
S_OR(eprofile->method, "<none>"), S_OR(eprofile->method, "<none>"),
S_COR(refinement_str, ast_str_buffer(refinement_str), "<none>"), S_COR(refinement_str, ast_str_buffer(refinement_str), "<none>"),
S_COR(variables_str, ast_str_buffer(variables_str), "<none>"), S_COR(variables_str, ast_str_buffer(variables_str), "<none>"),
S_COR(eprofile->precedence, "yes", "no"), S_COR(eprofile->allow_routing_use, "yes", "no"),
S_COR(eprofile->suppress_empty_ca_elements, "yes", "no"),
S_COR(resolved_str, ast_str_buffer(resolved_str), "<none>"), S_COR(resolved_str, ast_str_buffer(resolved_str), "<none>"),
S_COR(usage_rules_str, ast_str_buffer(usage_rules_str), "<none>"), S_COR(usage_rules_str, ast_str_buffer(usage_rules_str), "<none>"),
S_OR(eprofile->notes, "<none>") S_OR(eprofile->notes, "<none>")
); );
ao2_ref(eprofile, -1); ao2_ref(eprofile, -1);
ast_free(action);
ast_free(loc_str); ast_free(loc_str);
ast_free(refinement_str); ast_free(refinement_str);
ast_free(variables_str); ast_free(variables_str);
@ -695,6 +693,8 @@ int geoloc_config_load(void)
0, STRFLDSET(struct ast_geoloc_profile, notes)); 0, STRFLDSET(struct ast_geoloc_profile, notes));
ast_sorcery_object_field_register(geoloc_sorcery, "profile", "allow_routing_use", ast_sorcery_object_field_register(geoloc_sorcery, "profile", "allow_routing_use",
"no", OPT_BOOL_T, 1, FLDSET(struct ast_geoloc_profile, allow_routing_use)); "no", OPT_BOOL_T, 1, FLDSET(struct ast_geoloc_profile, allow_routing_use));
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_load(geoloc_sorcery); ast_sorcery_load(geoloc_sorcery);

@ -88,6 +88,8 @@ static int geoloc_profile_read(struct ast_channel *chan,
ast_str_append(buf, len, "%s", eprofile->method); ast_str_append(buf, len, "%s", eprofile->method);
} else if (ast_strings_equal(args.field, "allow_routing_use")) { } else if (ast_strings_equal(args.field, "allow_routing_use")) {
ast_str_append(buf, len, "%s", eprofile->allow_routing_use ? "yes" : "no"); ast_str_append(buf, len, "%s", eprofile->allow_routing_use ? "yes" : "no");
} else if (ast_strings_equal(args.field, "suppress_empty_ca_elements")) {
ast_str_append(buf, len, "%s", eprofile->suppress_empty_ca_elements ? "yes" : "no");
} else if (ast_strings_equal(args.field, "profile_precedence")) { } else if (ast_strings_equal(args.field, "profile_precedence")) {
ast_str_append(buf, len, "%s", ast_geoloc_precedence_to_name(eprofile->precedence)); ast_str_append(buf, len, "%s", ast_geoloc_precedence_to_name(eprofile->precedence));
} else if (ast_strings_equal(args.field, "format")) { } else if (ast_strings_equal(args.field, "format")) {
@ -212,19 +214,16 @@ static int geoloc_profile_write(struct ast_channel *chan, const char *cmd, char
ast_string_field_set(eprofile, location_reference, value); ast_string_field_set(eprofile, location_reference, value);
} else if (ast_strings_equal(args.field, "method")) { } else if (ast_strings_equal(args.field, "method")) {
ast_string_field_set(eprofile, method, value); ast_string_field_set(eprofile, method, value);
} else if (ast_strings_equal(args.field, "allow_routing_use")) { } else if (ast_strings_equal(args.field, "allow_routing_use")) {
eprofile->allow_routing_use = ast_true(value); eprofile->allow_routing_use = ast_true(value);
} else if (ast_strings_equal(args.field, "suppress_empty_ca_elements")) {
eprofile->suppress_empty_ca_elements = ast_true(value);
} else if (ast_strings_equal(args.field, "profile_precedence")) { } else if (ast_strings_equal(args.field, "profile_precedence")) {
TEST_ENUM_VALUE(chan_name, eprofile, precedence, value); TEST_ENUM_VALUE(chan_name, eprofile, precedence, value);
} else if (ast_strings_equal(args.field, "format")) { } else if (ast_strings_equal(args.field, "format")) {
TEST_ENUM_VALUE(chan_name, eprofile, format, value); TEST_ENUM_VALUE(chan_name, eprofile, format, value);
} else if (ast_strings_equal(args.field, "pidf_element")) { } else if (ast_strings_equal(args.field, "pidf_element")) {
TEST_ENUM_VALUE(chan_name, eprofile, pidf_element, value); TEST_ENUM_VALUE(chan_name, eprofile, pidf_element, value);
} else if (ast_strings_equal(args.field, "location_info")) { } else if (ast_strings_equal(args.field, "location_info")) {
TEST_VARLIST(chan_name, eprofile, location_info, value); TEST_VARLIST(chan_name, eprofile, location_info, value);
} else if (ast_strings_equal(args.field, "location_source")) { } else if (ast_strings_equal(args.field, "location_source")) {

@ -175,6 +175,10 @@
<configOption name="allow_routing_use"> <configOption name="allow_routing_use">
<synopsis>Sets the value of the Geolocation-Routing header.</synopsis> <synopsis>Sets the value of the Geolocation-Routing header.</synopsis>
</configOption> </configOption>
<configOption name="suppress_empty_ca_elements">
<synopsis>Sets if empty Civic Address elements should be suppressed
from the PIDF-LO document.</synopsis>
</configOption>
<configOption name="profile_precedence" default="discard_incoming"> <configOption name="profile_precedence" default="discard_incoming">
<synopsis>Determine which profile on a channel should be used</synopsis> <synopsis>Determine which profile on a channel should be used</synopsis>

@ -176,6 +176,7 @@ struct ast_geoloc_eprofile *ast_geoloc_eprofile_create_from_profile(struct ast_g
ao2_lock(profile); ao2_lock(profile);
eprofile->allow_routing_use = profile->allow_routing_use; eprofile->allow_routing_use = profile->allow_routing_use;
eprofile->pidf_element = profile->pidf_element; eprofile->pidf_element = profile->pidf_element;
eprofile->suppress_empty_ca_elements = profile->suppress_empty_ca_elements;
rc = ast_string_field_set(eprofile, location_reference, profile->location_reference); rc = ast_string_field_set(eprofile, location_reference, profile->location_reference);
if (rc == 0) { if (rc == 0) {
@ -988,6 +989,7 @@ const char *ast_geoloc_eprofile_to_pidf(struct ast_geoloc_eprofile *eprofile,
struct ast_xml_node *temp_node = NULL; struct ast_xml_node *temp_node = NULL;
const char *entity = NULL; const char *entity = NULL;
int has_no_entity = 0; int has_no_entity = 0;
const char *params[] = { "suppress_empty_ca_elements", "false()", NULL };
SCOPE_ENTER(3, "%s\n", ref_string); SCOPE_ENTER(3, "%s\n", ref_string);
@ -1038,7 +1040,10 @@ const char *ast_geoloc_eprofile_to_pidf(struct ast_geoloc_eprofile *eprofile,
doc_len = 0; doc_len = 0;
} }
pidf_doc = ast_xslt_apply(eprofile_to_pidf_xslt, intermediate, NULL); if (eprofile->suppress_empty_ca_elements) {
params[1] = "true()";
}
pidf_doc = ast_xslt_apply(eprofile_to_pidf_xslt, intermediate, params);
if (!pidf_doc) { if (!pidf_doc) {
SCOPE_EXIT_LOG_RTN_VALUE(NULL, LOG_ERROR, "%s: Unable to create final PIDF-LO doc from intermediate doc\n", SCOPE_EXIT_LOG_RTN_VALUE(NULL, LOG_ERROR, "%s: Unable to create final PIDF-LO doc from intermediate doc\n",
ref_string); ref_string);

@ -90,7 +90,7 @@ static int _stem ## _handler(const struct aco_option *opt, struct ast_variable *
while ((item = ast_strsep(&item_string, ',', AST_STRSEP_ALL))) { \ while ((item = ast_strsep(&item_string, ',', AST_STRSEP_ALL))) { \
item_name = ast_strsep(&item, '=', AST_STRSEP_ALL); \ item_name = ast_strsep(&item, '=', AST_STRSEP_ALL); \
item_value = ast_strsep(&item, '=', AST_STRSEP_ALL); \ item_value = ast_strsep(&item, '=', AST_STRSEP_ALL); \
new_var = ast_variable_new(item_name, item_value, ""); \ new_var = ast_variable_new(item_name, S_OR(item_value, ""), ""); \
if (!new_var) { \ if (!new_var) { \
rc = -1; \ rc = -1; \
break; \ break; \

Loading…
Cancel
Save