summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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 */
}
}