]> git.ipfire.org Git - thirdparty/asterisk.git/commitdiff
These changes were made in response to niklas@tese.se's letter of 11-17-2007, where...
authorSteve Murphy <murf@digium.com>
Mon, 19 Nov 2007 22:55:38 +0000 (22:55 +0000)
committerSteve Murphy <murf@digium.com>
Mon, 19 Nov 2007 22:55:38 +0000 (22:55 +0000)
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@89438 65c4cc65-6c06-0410-ace0-fbb531ad65f3

main/pbx.c

index 2c12f794cc363122139c88ee902904ba77d944ee..670195e4885560782c6370a5509bb7d805b9286b 100644 (file)
@@ -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 */
                }
        }