aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authormurf <murf@f38db490-d61c-443f-a65b-d21fe96a405b>2007-11-19 22:55:38 +0000
committermurf <murf@f38db490-d61c-443f-a65b-d21fe96a405b>2007-11-19 22:55:38 +0000
commit096ab948cac182c6d8dc28ab4d08a7e4d9acf08d (patch)
tree91dd38141efbc49cd4ab7eb48d222597e0642f1b
parentf21fd57280d7545cfe935531e2194d857269ff74 (diff)
These changes were made in response to niklas@tese.se's letter of 11-17-2007, where he had 20 and 201 in two different contexts, included in the same context. In that particular case, we were behaving the same as 1.4, but after experimenting, I quickly found that if 20 and 201 were in the same extension, 1.4 would return 201, and this code returns 20. These changes now enable the current code to replicate the behavior of 1.4 in respect to MATCHMORE in cases like this.
git-svn-id: http://svn.digium.com/svn/asterisk/trunk@89438 f38db490-d61c-443f-a65b-d21fe96a405b
-rw-r--r--main/pbx.c79
1 files changed, 61 insertions, 18 deletions
diff --git a/main/pbx.c b/main/pbx.c
index 2c12f794c..670195e48 100644
--- a/main/pbx.c
+++ b/main/pbx.c
@@ -194,6 +194,7 @@ struct scoreboard /* make sure all fields are 0 before calling new_find_extensi
int total_length;
char last_char; /* set to ! or . if they are the end of the pattern */
int canmatch; /* if the string to match was just too short */
+ struct match_char *node;
struct ast_exten *canmatch_exten;
struct ast_exten *exten;
};
@@ -319,7 +320,7 @@ static int pbx_builtin_importvar(struct ast_channel *, void *);
static void set_ext_pri(struct ast_channel *c, const char *exten, int pri);
void new_find_extension(const char *str, struct scoreboard *score, struct match_char *tree, int length, int spec, const char *callerid);
struct match_char *already_in_tree(struct match_char *current, char *pat);
-struct match_char *add_exten_to_pattern_tree(struct ast_context *con, struct ast_exten *e1);
+struct match_char *add_exten_to_pattern_tree(struct ast_context *con, struct ast_exten *e1, int findonly);
struct match_char *add_pattern_node(struct ast_context *con, struct match_char *current, char *pattern, int is_pattern, int already, int specificity);
void create_match_char_tree(struct ast_context *con);
struct ast_exten *get_canmatch_exten(struct match_char *node);
@@ -823,7 +824,7 @@ static void pbx_destroy(struct ast_pbx *p)
*/
-static void update_scoreboard(struct scoreboard *board, int length, int spec, struct ast_exten *exten, char last, const char *callerid, int deleted)
+static void update_scoreboard(struct scoreboard *board, int length, int spec, struct ast_exten *exten, char last, const char *callerid, int deleted, struct match_char *node)
{
/* doing a matchcid() check here would be easy and cheap, but...
unfortunately, it only works if an extension can have only one
@@ -834,17 +835,18 @@ static void update_scoreboard(struct scoreboard *board, int length, int spec, st
on the scoreboard, it will never be found */
if (deleted)
return;
-
if (length > board->total_length) {
board->total_specificity = spec;
board->total_length = length;
board->exten = exten;
board->last_char = last;
+ board->node = node;
} else if (length == board->total_length && spec < board->total_specificity) {
board->total_specificity = spec;
board->total_length = length;
board->exten = exten;
board->last_char = last;
+ board->node = node;
}
}
@@ -888,13 +890,38 @@ struct ast_exten *get_canmatch_exten(struct match_char *node)
return 0;
}
+static struct ast_exten *trie_find_next_match(struct match_char *node)
+{
+ struct match_char *m3;
+ struct match_char *m4;
+ struct ast_exten *e3;
+
+ if (!node || !node->next_char)
+ return NULL;
+
+ m3 = node->next_char;
+
+ if (m3->exten)
+ return m3->exten;
+ for(m4=m3->alt_char; m4; m4 = m4->alt_char) {
+ if (m4->exten)
+ return m4->exten;
+ }
+ for(m4=m3; m4; m4 = m4->alt_char) {
+ e3 = trie_find_next_match(m3);
+ if (e3)
+ return e3;
+ }
+ return NULL;
+}
+
void new_find_extension(const char *str, struct scoreboard *score, struct match_char *tree, int length, int spec, const char *callerid)
{
struct match_char *p; /* note minimal stack storage requirements */
for (p=tree; p; p=p->alt_char) {
if (p->x[0] == 'N' && p->x[1] == 0 && *str >= '2' && *str <= '9' ) {
if (p->exten) /* if a shorter pattern matches along the way, might as well report it */
- update_scoreboard(score, length+1, spec+p->specificity, p->exten,0,callerid, p->deleted);
+ update_scoreboard(score, length+1, spec+p->specificity, p->exten,0,callerid, p->deleted, p);
if (p->next_char && ( *(str+1) || (p->next_char->x[0] == '/' && p->next_char->x[1] == 0))) {
if (*(str+1))
@@ -909,7 +936,7 @@ void new_find_extension(const char *str, struct scoreboard *score, struct match_
}
} else if (p->x[0] == 'Z' && p->x[1] == 0 && *str >= '1' && *str <= '9' ) {
if (p->exten) /* if a shorter pattern matches along the way, might as well report it */
- update_scoreboard(score, length+1, spec+p->specificity, p->exten,0,callerid, p->deleted);
+ update_scoreboard(score, length+1, spec+p->specificity, p->exten,0,callerid, p->deleted,p);
if (p->next_char && ( *(str+1) || (p->next_char->x[0] == '/' && p->next_char->x[1] == 0))) {
if (*(str+1))
@@ -924,7 +951,7 @@ void new_find_extension(const char *str, struct scoreboard *score, struct match_
}
} else if (p->x[0] == 'X' && p->x[1] == 0 && *str >= '0' && *str <= '9' ) {
if (p->exten) /* if a shorter pattern matches along the way, might as well report it */
- update_scoreboard(score, length+1, spec+p->specificity, p->exten,0,callerid, p->deleted);
+ update_scoreboard(score, length+1, spec+p->specificity, p->exten,0,callerid, p->deleted,p);
if (p->next_char && ( *(str+1) || (p->next_char->x[0] == '/' && p->next_char->x[1] == 0))) {
if (*(str+1))
@@ -944,7 +971,7 @@ void new_find_extension(const char *str, struct scoreboard *score, struct match_
i++;
}
if (p->exten)
- update_scoreboard(score, length+i, spec+(i*p->specificity), p->exten, '.', callerid, p->deleted);
+ update_scoreboard(score, length+i, spec+(i*p->specificity), p->exten, '.', callerid, p->deleted, p);
if (p->next_char && p->next_char->x[0] == '/' && p->next_char->x[1] == 0) {
new_find_extension("/", score, p->next_char, length+i, spec+(p->specificity*i), callerid);
}
@@ -956,7 +983,7 @@ void new_find_extension(const char *str, struct scoreboard *score, struct match_
i++;
}
if (p->exten)
- update_scoreboard(score, length+1, spec+(p->specificity*i), p->exten, '!', callerid, p->deleted);
+ update_scoreboard(score, length+1, spec+(p->specificity*i), p->exten, '!', callerid, p->deleted, p);
if (p->next_char && p->next_char->x[0] == '/' && p->next_char->x[1] == 0) {
new_find_extension("/", score, p->next_char, length+i, spec+(p->specificity*i), callerid);
}
@@ -968,7 +995,7 @@ void new_find_extension(const char *str, struct scoreboard *score, struct match_
}
} else if (index(p->x, *str)) {
if (p->exten) /* if a shorter pattern matches along the way, might as well report it */
- update_scoreboard(score, length+1, spec+p->specificity, p->exten,0,callerid, p->deleted);
+ update_scoreboard(score, length+1, spec+p->specificity, p->exten,0,callerid, p->deleted, p);
if (p->next_char && ( *(str+1) || (p->next_char->x[0] == '/' && p->next_char->x[1] == 0))) {
@@ -1050,7 +1077,7 @@ struct match_char *add_pattern_node(struct ast_context *con, struct match_char *
return m;
}
-struct match_char *add_exten_to_pattern_tree(struct ast_context *con, struct ast_exten *e1)
+struct match_char *add_exten_to_pattern_tree(struct ast_context *con, struct ast_exten *e1, int findonly)
{
struct match_char *m1=0,*m2=0;
int specif;
@@ -1131,9 +1158,15 @@ struct match_char *add_exten_to_pattern_tree(struct ast_context *con, struct ast
m1 = m2->next_char; /* m1 points to the node to compare against */
} else {
if (m2) {
+ if (findonly)
+ return m2;
m1 = m2;
- } else
+ } else {
+ if (findonly)
+ return m1;
m1 = add_pattern_node(con, m1, buf, pattern, already,specif); /* m1 is the node just added */
+ }
+
if (!(*(s1+1)))
m1->exten = e1;
already = 0;
@@ -1158,7 +1191,7 @@ void create_match_char_tree(struct ast_context *con)
t1 = ast_hashtab_start_traversal(con->root_tree);
while( (e1 = ast_hashtab_next(t1)) ) {
if (e1->exten)
- add_exten_to_pattern_tree(con, e1);
+ add_exten_to_pattern_tree(con, e1, 0);
else
ast_log(LOG_ERROR,"Attempt to create extension with no extension name.\n");
}
@@ -1532,7 +1565,6 @@ struct ast_exten *pbx_find_extension(struct ast_channel *chan,
pattern.label = label;
pattern.priority = priority;
-
/* Initialize status if appropriate */
if (q->stacklen == 0) {
q->status = STATUS_NO_CONTEXT;
@@ -1565,12 +1597,14 @@ struct ast_exten *pbx_find_extension(struct ast_channel *chan,
#endif
if (!tmp)
return NULL;
+
}
if (q->status < STATUS_NO_EXTENSION)
q->status = STATUS_NO_EXTENSION;
/* Do a search for matching extension */
+
eroot = NULL;
score.total_specificity = 0;
score.exten = 0;
@@ -1599,8 +1633,14 @@ struct ast_exten *pbx_find_extension(struct ast_channel *chan,
return score.canmatch_exten;
}
- if (action == E_MATCHMORE && eroot)
+ if (action == E_MATCHMORE && eroot) {
+ if (score.node) {
+ struct ast_exten *z = trie_find_next_match(score.node);
+ return z;
+ }
return NULL; /* according to the code, complete matches are null matches in MATCHMORE mode */
+ }
+
if (eroot) {
/* found entry, now look for the right priority */
@@ -1703,8 +1743,11 @@ struct ast_exten *pbx_find_extension(struct ast_channel *chan,
/* Now try any includes we have in this context */
for (i = tmp->includes; i; i = i->next) {
if (include_valid(i)) {
- if ((e = pbx_find_extension(chan, bypass, q, i->rname, exten, priority, label, callerid, action)))
+ if ((e = pbx_find_extension(chan, bypass, q, i->rname, exten, priority, label, callerid, action))) {
+ ast_log(LOG_NOTICE,"pbx_find_extension returns exten %s from recursive call\n", e->exten);
return e;
+ }
+
if (q->swo)
return NULL;
}
@@ -3614,7 +3657,7 @@ int ast_context_remove_extension2(struct ast_context *con, const char *extension
if (priority == 0)
{
/* success, this exten is in this pattern tree. */
- struct match_char *x = add_exten_to_pattern_tree(con, exten);
+ struct match_char *x = add_exten_to_pattern_tree(con, exten, 1);
if (x->exten) { /* this test for safety purposes */
x->deleted = 1; /* with this marked as deleted, it will never show up in the scoreboard, and therefore never be found */
x->exten = 0; /* get rid of what will become a bad pointer */
@@ -3636,7 +3679,7 @@ int ast_context_remove_extension2(struct ast_context *con, const char *extension
if (ast_hashtab_size(exten->peer_tree) == 0) {
/* well, if the last priority of an exten is to be removed,
then, the extension is removed, too! */
- struct match_char *x = add_exten_to_pattern_tree(con, exten);
+ struct match_char *x = add_exten_to_pattern_tree(con, exten, 1);
if (x->exten) { /* this test for safety purposes */
x->deleted = 1; /* with this marked as deleted, it will never show up in the scoreboard, and therefore never be found */
x->exten = 0; /* get rid of what will become a bad pointer */
@@ -5796,7 +5839,7 @@ int ast_add_extension2(struct ast_context *con,
tmp2 = ast_hashtab_lookup(con->root_tree,&dummy_exten);
if (!tmp2) {
/* hmmm, not in the trie; */
- add_exten_to_pattern_tree(con, tmp);
+ add_exten_to_pattern_tree(con, tmp, 0);
ast_hashtab_insert_safe(con->root_tree, tmp); /* for the sake of completeness */
}
}