config: Allow filters when appending to a category

In sorcery based config files where there are multiple categories with the same
name, you can't use the (+) operator to reliably append to a category because
config.c stops looking when it finds the first one with the same name.

Example:

[1000]
type = endpoint

[1000]
type = aor

[1000](+)
authenticate_qualify = yes

This config will fail because config.c appends authenticate_qualify to the
first category it finds, the endpoint, and that's not valid for endpoint.

Solution:

The capability to find a category that contains a certain variable already
exists so the only real change was to parse anything after the '+' that's not a
comma, as a filter string.

[1000]
type = endpoint

[1000]
type = aor

[1000](+type=aor)
authenticate_qualify = yes

This now works as expected.

Although the following example doesn't make any sense for pjsip, you can even
specify multiple filters:

[1000](+type=aor&qualify_frequency=10)

ASTERISK-25868 #close
Reported-by: Nick Repin

Change-Id: I10773da4c79db36fbf1993961992af63d3441580
This commit is contained in:
George Joseph
2016-03-27 22:33:29 -06:00
committed by Richard Mudgett
parent cac6453e9a
commit 50b0922a22

View File

@@ -72,7 +72,8 @@ static char *extconfig_conf = "extconfig.conf";
static struct ao2_container *cfg_hooks; static struct ao2_container *cfg_hooks;
static void config_hook_exec(const char *filename, const char *module, const struct ast_config *cfg); static void config_hook_exec(const char *filename, const char *module, const struct ast_config *cfg);
static inline struct ast_variable *variable_list_switch(struct ast_variable *l1, struct ast_variable *l2); static inline struct ast_variable *variable_list_switch(struct ast_variable *l1, struct ast_variable *l2);
static int does_category_match(struct ast_category *cat, const char *category_name, const char *match); static int does_category_match(struct ast_category *cat, const char *category_name,
const char *match, char sep);
/*! \brief Structure to keep comments for rewriting configuration files */ /*! \brief Structure to keep comments for rewriting configuration files */
struct ast_comment { struct ast_comment {
@@ -864,7 +865,8 @@ static void move_variables(struct ast_category *old, struct ast_category *new)
/*! \brief Returns true if ALL of the regex expressions and category name match. /*! \brief Returns true if ALL of the regex expressions and category name match.
* Both can be NULL (I.E. no predicate) which results in a true return; * Both can be NULL (I.E. no predicate) which results in a true return;
*/ */
static int does_category_match(struct ast_category *cat, const char *category_name, const char *match) static int does_category_match(struct ast_category *cat, const char *category_name,
const char *match, char sep)
{ {
char *dupmatch; char *dupmatch;
char *nvp = NULL; char *nvp = NULL;
@@ -883,7 +885,7 @@ static int does_category_match(struct ast_category *cat, const char *category_na
dupmatch = ast_strdupa(match); dupmatch = ast_strdupa(match);
while ((nvp = ast_strsep(&dupmatch, ',', AST_STRSEP_STRIP))) { while ((nvp = ast_strsep(&dupmatch, sep, AST_STRSEP_STRIP))) {
struct ast_variable *v; struct ast_variable *v;
char *match_name; char *match_name;
char *match_value = NULL; char *match_value = NULL;
@@ -982,19 +984,19 @@ struct ast_category *ast_category_new_template(const char *name, const char *in_
return new_category(name, in_file, lineno, 1); return new_category(name, in_file, lineno, 1);
} }
struct ast_category *ast_category_get(const struct ast_config *config, static struct ast_category *category_get_sep(const struct ast_config *config,
const char *category_name, const char *filter) const char *category_name, const char *filter, char sep)
{ {
struct ast_category *cat; struct ast_category *cat;
for (cat = config->root; cat; cat = cat->next) { for (cat = config->root; cat; cat = cat->next) {
if (cat->name == category_name && does_category_match(cat, category_name, filter)) { if (cat->name == category_name && does_category_match(cat, category_name, filter, sep)) {
return cat; return cat;
} }
} }
for (cat = config->root; cat; cat = cat->next) { for (cat = config->root; cat; cat = cat->next) {
if (does_category_match(cat, category_name, filter)) { if (does_category_match(cat, category_name, filter, sep)) {
return cat; return cat;
} }
} }
@@ -1002,6 +1004,12 @@ struct ast_category *ast_category_get(const struct ast_config *config,
return NULL; return NULL;
} }
struct ast_category *ast_category_get(const struct ast_config *config,
const char *category_name, const char *filter)
{
return category_get_sep(config, category_name, filter, ',');
}
const char *ast_category_get_name(const struct ast_category *category) const char *ast_category_get_name(const struct ast_category *category)
{ {
return category->name; return category->name;
@@ -1125,7 +1133,7 @@ static void ast_includes_destroy(struct ast_config_include *incls)
static struct ast_category *next_available_category(struct ast_category *cat, static struct ast_category *next_available_category(struct ast_category *cat,
const char *name, const char *filter) const char *name, const char *filter)
{ {
for (; cat && !does_category_match(cat, name, filter); cat = cat->next); for (; cat && !does_category_match(cat, name, filter, ','); cat = cat->next);
return cat; return cat;
} }
@@ -1777,8 +1785,13 @@ static int process_text_line(struct ast_config *cfg, struct ast_category **cat,
while ((cur = strsep(&c, ","))) { while ((cur = strsep(&c, ","))) {
if (!strcasecmp(cur, "!")) { if (!strcasecmp(cur, "!")) {
(*cat)->ignored = 1; (*cat)->ignored = 1;
} else if (!strcasecmp(cur, "+")) { } else if (cur[0] == '+') {
*cat = ast_category_get(cfg, catname, NULL); char *filter = NULL;
if (cur[1] != ',') {
filter = &cur[1];
}
*cat = category_get_sep(cfg, catname, filter, '&');
if (!(*cat)) { if (!(*cat)) {
if (newcat) { if (newcat) {
ast_category_destroy(newcat); ast_category_destroy(newcat);