]> git.ipfire.org Git - thirdparty/asterisk.git/commitdiff
Fix the 'dialplan remove extension' logic, so that it a) works with cidmatch,
authorTilghman Lesher <tilghman@meg.abyt.es>
Fri, 4 Jul 2008 03:30:30 +0000 (03:30 +0000)
committerTilghman Lesher <tilghman@meg.abyt.es>
Fri, 4 Jul 2008 03:30:30 +0000 (03:30 +0000)
and b) completes contexts correctly when the extension is ambiguous.
(closes issue #12980)
 Reported by: licedey
 Patches:
       20080703__bug12980.diff.txt uploaded by Corydon76 (license 14)
 Tested by: Corydon76

git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/1.4@127973 65c4cc65-6c06-0410-ace0-fbb531ad65f3

include/asterisk/pbx.h
main/pbx.c
pbx/pbx_config.c

index 41c04ce9c7e5902deed41161e14691f2e714ed4b..329119295a75bc8f9153f4a053e0c2e734c1cc00 100644 (file)
@@ -585,7 +585,9 @@ int ast_context_remove_switch2(struct ast_context *con, const char *sw,
  * 
  * \param context context to remove extension from
  * \param extension which extension to remove
- * \param priority priority of extension to remove
+ * \param priority priority of extension to remove (0 to remove all)
+ * \param callerid NULL to remove all; non-NULL to match a single record per priority
+ * \param matchcid non-zero to match callerid element (if non-NULL); 0 to match default case
  * \param registrar registrar of the extension
  *
  * This function removes an extension from a given context.
@@ -599,6 +601,12 @@ int ast_context_remove_extension(const char *context, const char *extension, int
 int ast_context_remove_extension2(struct ast_context *con, const char *extension,
        int priority, const char *registrar);
 
+int ast_context_remove_extension_callerid(const char *context, const char *extension,
+       int priority, const char *callerid, int matchcid, const char *registrar);
+
+int ast_context_remove_extension_callerid2(struct ast_context *con, const char *extension,
+       int priority, const char *callerid, int matchcid, const char *registrar);
+
 /*! 
  * \brief Add an ignorepat
  * 
index 107840c9a3c9592777c53b84dea64720b55410af..f4e5a150cd9106a106eb7d55b779003568dff15c 100644 (file)
@@ -2804,12 +2804,17 @@ int ast_context_remove_switch2(struct ast_context *con, const char *sw, const ch
  * In this function we are using
  */
 int ast_context_remove_extension(const char *context, const char *extension, int priority, const char *registrar)
+{
+       return ast_context_remove_extension_callerid(context, extension, priority, NULL, 0, registrar);
+}
+
+int ast_context_remove_extension_callerid(const char *context, const char *extension, int priority, const char *callerid, int matchcid, const char *registrar)
 {
        int ret = -1; /* default error return */
        struct ast_context *c = find_context_locked(context);
 
        if (c) { /* ... remove extension ... */
-               ret = ast_context_remove_extension2(c, extension, priority, registrar);
+               ret = ast_context_remove_extension_callerid2(c, extension, priority, callerid, matchcid, registrar);
                ast_unlock_contexts();
        }
        return ret;
@@ -2826,13 +2831,21 @@ int ast_context_remove_extension(const char *context, const char *extension, int
  *
  */
 int ast_context_remove_extension2(struct ast_context *con, const char *extension, int priority, const char *registrar)
+{
+       return ast_context_remove_extension_callerid2(con, extension, priority, NULL, 0, registrar);
+}
+
+int ast_context_remove_extension_callerid2(struct ast_context *con, const char *extension, int priority, const char *callerid, int matchcid, const char *registrar)
 {
        struct ast_exten *exten, *prev_exten = NULL;
        struct ast_exten *peer;
+       struct ast_exten *previous_peer = NULL;
+       struct ast_exten *next_peer = NULL;
+       int found = 0;
 
        ast_mutex_lock(&con->lock);
 
-       /* scan the extension list to find matching extension-registrar */
+       /* scan the extension list to find first matching extension-registrar */
        for (exten = con->root; exten; prev_exten = exten, exten = exten->next) {
                if (!strcmp(exten->exten, extension) &&
                        (!registrar || !strcmp(exten->registrar, registrar)))
@@ -2844,56 +2857,43 @@ int ast_context_remove_extension2(struct ast_context *con, const char *extension
                return -1;
        }
 
-       /* should we free all peers in this extension? (priority == 0)? */
-       if (priority == 0) {
-               /* remove this extension from context list */
-               if (prev_exten)
-                       prev_exten->next = exten->next;
-               else
-                       con->root = exten->next;
+       /* scan the priority list to remove extension with exten->priority == priority */
+       for (peer = exten, next_peer = exten->peer ? exten->peer : exten->next;
+                       peer && !strcmp(peer->exten, extension);
+                       peer = next_peer, next_peer = next_peer ? (next_peer->peer ? next_peer->peer : next_peer->next) : NULL) {
+               if ((priority == 0 || peer->priority == priority) &&
+                               (!callerid || !matchcid || (matchcid && !strcmp(peer->cidmatch, callerid))) &&
+                               (!registrar || !strcmp(peer->registrar, registrar) )) {
+                       found = 1;
 
-               /* fire out all peers */
-               while ( (peer = exten) ) {
-                       exten = peer->peer; /* prepare for next entry */
-                       destroy_exten(peer);
-               }
-       } else {
-               /* scan the priority list to remove extension with exten->priority == priority */
-               struct ast_exten *previous_peer = NULL;
+                       /* we are first priority extension? */
+                       if (!previous_peer) {
+                               /*
+                                * We are first in the priority chain, so must update the extension chain.
+                                * The next node is either the next priority or the next extension
+                                */
+                               struct ast_exten *next_node = peer->peer ? peer->peer : peer->next;
 
-               for (peer = exten; peer; previous_peer = peer, peer = peer->peer) {
-                       if (peer->priority == priority &&
-                                       (!registrar || !strcmp(peer->registrar, registrar) ))
-                               break; /* found our priority */
-               }
-               if (!peer) { /* not found */
-                       ast_mutex_unlock(&con->lock);
-                       return -1;
-               }
-               /* we are first priority extension? */
-               if (!previous_peer) {
-                       /*
-                        * We are first in the priority chain, so must update the extension chain.
-                        * The next node is either the next priority or the next extension
-                        */
-                       struct ast_exten *next_node = peer->peer ? peer->peer : peer->next;
+                               if (!prev_exten) {      /* change the root... */
+                                       con->root = next_node;
+                               } else {
+                                       prev_exten->next = next_node; /* unlink */
+                               }
+                               if (peer->peer) { /* update the new head of the pri list */
+                                       peer->peer->next = peer->next;
+                               }
+                       } else { /* easy, we are not first priority in extension */
+                               previous_peer->peer = peer->peer;
+                       }
 
-                       if (!prev_exten)        /* change the root... */
-                               con->root = next_node;
-                       else
-                               prev_exten->next = next_node; /* unlink */
-                       if (peer->peer) /* XXX update the new head of the pri list */
-                               peer->peer->next = peer->next;
-               } else { /* easy, we are not first priority in extension */
-                       previous_peer->peer = peer->peer;
+                       /* now, free whole priority extension */
+                       destroy_exten(peer);
+               } else {
+                       previous_peer = peer;
                }
-
-               /* now, free whole priority extension */
-               destroy_exten(peer);
-               /* XXX should we return -1 ? */
        }
        ast_mutex_unlock(&con->lock);
-       return 0;
+       return found ? 0 : -1;
 }
 
 
index 63f6c04f1c8846132488c923e98f6fc848cfec47..0fb9430c76ced2231ead689de1d91b6b9c04b6f1 100644 (file)
@@ -69,7 +69,7 @@ static char context_add_extension_help[] =
 "         Now, you can dial 6123 and talk to Markster :)\n";
 
 static char context_remove_extension_help[] =
-"Usage: dialplan remove extension exten@context [priority]\n"
+"Usage: dialplan remove extension exten[/cid]@context [priority]\n"
 "       Remove an extension from a given context. If a priority\n"
 "       is given, only that specific priority from the given extension\n"
 "       will be removed.\n";
@@ -207,9 +207,9 @@ static int partial_match(const char *s, const char *word, int len)
 /*! \brief split extension\@context in two parts, return -1 on error.
  * The return string is malloc'ed and pointed by *ext
  */
-static int split_ec(const char *src, char **ext, char ** const ctx)
+static int split_ec(const char *src, char **ext, char ** const ctx, char ** const cid)
 {
-       char *c, *e = ast_strdup(src); /* now src is not used anymore */
+       char *i, *c, *e = ast_strdup(src); /* now src is not used anymore */
 
        if (e == NULL)
                return -1;      /* malloc error */
@@ -225,7 +225,14 @@ static int split_ec(const char *src, char **ext, char ** const ctx)
                        free(e);
                        return -1;
                }
-       } 
+       }
+       if (cid && (i = strchr(e, '/'))) {
+               *i++ = '\0';
+               *cid = i;
+       } else if (cid) {
+               /* Signal none detected */
+               *cid = NULL;
+       }
        return 0;
 }
 
@@ -478,7 +485,7 @@ static char *complete_context_remove_include(const char *line, const char *word,
 static int handle_context_remove_extension_deprecated(int fd, int argc, char *argv[])
 {
        int removing_priority = 0;
-       char *exten, *context;
+       char *exten, *context, *cid;
        int ret = RESULT_FAILURE;
 
        if (argc != 4 && argc != 3) return RESULT_SHOWUSAGE;
@@ -516,7 +523,7 @@ static int handle_context_remove_extension_deprecated(int fd, int argc, char *ar
        /*
         * Format exten@context checking ...
         */
-       if (split_ec(argv[2], &exten, &context))
+       if (split_ec(argv[2], &exten, &context, &cid))
                return RESULT_FAILURE; /* XXX malloc failure */
        if ((!strlen(exten)) || (!(strlen(context)))) {
                ast_cli(fd, "Missing extension or context name in second argument '%s'\n",
@@ -525,7 +532,9 @@ static int handle_context_remove_extension_deprecated(int fd, int argc, char *ar
                return RESULT_FAILURE;
        }
 
-       if (!ast_context_remove_extension(context, exten, removing_priority, registrar)) {
+       if (!ast_context_remove_extension_callerid(context, exten, removing_priority,
+                       /* Do NOT substitute S_OR; it is NOT the same thing */
+                       cid ? cid : (removing_priority ? "" : NULL), cid ? 1 : 0, registrar)) {
                if (!removing_priority)
                        ast_cli(fd, "Whole extension %s@%s removed\n",
                                exten, context);
@@ -545,7 +554,7 @@ static int handle_context_remove_extension_deprecated(int fd, int argc, char *ar
 static int handle_context_remove_extension(int fd, int argc, char *argv[])
 {
        int removing_priority = 0;
-       char *exten, *context;
+       char *exten, *context, *cid;
        int ret = RESULT_FAILURE;
 
        if (argc != 5 && argc != 4) return RESULT_SHOWUSAGE;
@@ -583,7 +592,7 @@ static int handle_context_remove_extension(int fd, int argc, char *argv[])
        /*
         * Format exten@context checking ...
         */
-       if (split_ec(argv[3], &exten, &context))
+       if (split_ec(argv[3], &exten, &context, &cid))
                return RESULT_FAILURE; /* XXX malloc failure */
        if ((!strlen(exten)) || (!(strlen(context)))) {
                ast_cli(fd, "Missing extension or context name in third argument '%s'\n",
@@ -592,7 +601,9 @@ static int handle_context_remove_extension(int fd, int argc, char *argv[])
                return RESULT_FAILURE;
        }
 
-       if (!ast_context_remove_extension(context, exten, removing_priority, registrar)) {
+       if (!ast_context_remove_extension_callerid(context, exten, removing_priority,
+                       /* Do NOT substitute S_OR; it is NOT the same thing */
+                       cid ? cid : (removing_priority ? "" : NULL), cid ? 1 : 0, registrar)) {
                if (!removing_priority)
                        ast_cli(fd, "Whole extension %s@%s removed\n",
                                exten, context);
@@ -675,13 +686,14 @@ static char *complete_context_remove_extension_deprecated(const char *line, cons
        word = word2;
 #endif
 
-       if (pos == 2) { /* 'remove extension _X_' (exten@context ... */
+       if (pos == 2) { /* 'remove extension _X_' (exten/cid@context ... */
                struct ast_context *c = NULL;
-               char *context = NULL, *exten = NULL;
+               char *context = NULL, *exten = NULL, *cid = NULL;
                int le = 0;     /* length of extension */
                int lc = 0;     /* length of context */
+               int lcid = 0; /* length of cid */
 
-               lc = split_ec(word, &exten, &context);
+               lc = split_ec(word, &exten, &context, &cid);
 #ifdef BROKEN_READLINE
                free(word2);
 #endif
@@ -689,6 +701,7 @@ static char *complete_context_remove_extension_deprecated(const char *line, cons
                        return NULL;
                le = strlen(exten);
                lc = strlen(context);
+               lcid = cid ? strlen(cid) : -1;
 
                if (ast_rdlock_contexts()) {
                        ast_log(LOG_ERROR, "Failed to lock context list\n");
@@ -702,11 +715,22 @@ static char *complete_context_remove_extension_deprecated(const char *line, cons
                        if (!partial_match(ast_get_context_name(c), context, lc))
                                continue;       /* context not matched */
                        while ( (e = ast_walk_context_extensions(c, e)) ) { /* try to complete extensions ... */
-                               if ( partial_match(ast_get_extension_name(e), exten, le) && ++which > state) { /* n-th match */
-                                       /* If there is an extension then return exten@context. XXX otherwise ? */
-                                       if (exten)
-                                               asprintf(&ret, "%s@%s", ast_get_extension_name(e), ast_get_context_name(c));
-                                       break;
+                               if ( !strchr(word, '/') ||
+                                               (!strchr(word, '@') && partial_match(ast_get_extension_cidmatch(e), cid, lcid)) ||
+                                               (strchr(word, '@') && !strcmp(ast_get_extension_cidmatch(e), cid))) {
+                                       if ( ((strchr(word, '/') || strchr(word, '@')) && !strcmp(ast_get_extension_name(e), exten)) ||
+                                                (!strchr(word, '/') && !strchr(word, '@') && partial_match(ast_get_extension_name(e), exten, le))) { /* n-th match */
+                                               if (++which > state) {
+                                                       /* If there is an extension then return exten@context. */
+                                                       if (ast_get_extension_matchcid(e) && (!strchr(word, '@') || strchr(word, '/'))) {
+                                                               asprintf(&ret, "%s/%s@%s", ast_get_extension_name(e), ast_get_extension_cidmatch(e), ast_get_context_name(c));
+                                                               break;
+                                                       } else if (!ast_get_extension_matchcid(e) && !strchr(word, '/')) {
+                                                               asprintf(&ret, "%s@%s", ast_get_extension_name(e), ast_get_context_name(c));
+                                                               break;
+                                                       }
+                                               }
+                                       }
                                }
                        }
                        if (e)  /* got a match */
@@ -718,11 +742,11 @@ static char *complete_context_remove_extension_deprecated(const char *line, cons
                if (exten)
                        free(exten);
        } else if (pos == 3) { /* 'remove extension EXT _X_' (priority) */
-               char *exten = NULL, *context, *p;
+               char *exten = NULL, *context, *cid, *p;
                struct ast_context *c;
-               int le, lc, len;
+               int le, lc, lcid, len;
                const char *s = skip_words(line, 2); /* skip 'remove' 'extension' */
-               int i = split_ec(s, &exten, &context);  /* parse ext@context */
+               int i = split_ec(s, &exten, &context, &cid);    /* parse ext@context */
 
                if (i)  /* error */
                        goto error3;
@@ -732,6 +756,7 @@ static char *complete_context_remove_extension_deprecated(const char *line, cons
                        *p = '\0';
                le = strlen(exten);
                lc = strlen(context);
+               lcid = strlen(cid);
                len = strlen(word);
                if (le == 0 || lc == 0)
                        goto error3;
@@ -754,6 +779,9 @@ static char *complete_context_remove_extension_deprecated(const char *line, cons
                                struct ast_exten *priority;
                                char buffer[10];
 
+                               if (cid && strcmp(ast_get_extension_cidmatch(e), cid) != 0) {
+                                       continue;
+                               }
                                if (strcmp(ast_get_extension_name(e), exten) != 0)
                                        continue;
                                /* XXX lock e ? */
@@ -799,18 +827,21 @@ static char *complete_context_remove_extension(const char *line, const char *wor
 
        if (pos == 3) { /* 'dialplan remove extension _X_' (exten@context ... */
                struct ast_context *c = NULL;
-               char *context = NULL, *exten = NULL;
+               char *context = NULL, *exten = NULL, *cid = NULL;
                int le = 0;     /* length of extension */
                int lc = 0;     /* length of context */
+               int lcid = 0; /* length of cid */
 
-               lc = split_ec(word, &exten, &context);
+               lc = split_ec(word, &exten, &context, &cid);
+               if (lc) { /* error */
 #ifdef BROKEN_READLINE
-               free(word2);
+                       free(word2);
 #endif
-               if (lc) /* error */
                        return NULL;
+               }
                le = strlen(exten);
                lc = strlen(context);
+               lcid = cid ? strlen(cid) : -1;
 
                if (ast_rdlock_contexts()) {
                        ast_log(LOG_ERROR, "Failed to lock context list\n");
@@ -824,27 +855,41 @@ static char *complete_context_remove_extension(const char *line, const char *wor
                        if (!partial_match(ast_get_context_name(c), context, lc))
                                continue;       /* context not matched */
                        while ( (e = ast_walk_context_extensions(c, e)) ) { /* try to complete extensions ... */
-                               if ( partial_match(ast_get_extension_name(e), exten, le) && ++which > state) { /* n-th match */
-                                       /* If there is an extension then return exten@context. XXX otherwise ? */
-                                       if (exten)
-                                               asprintf(&ret, "%s@%s", ast_get_extension_name(e), ast_get_context_name(c));
-                                       break;
+                               if ( !strchr(word, '/') ||
+                                               (!strchr(word, '@') && partial_match(ast_get_extension_cidmatch(e), cid, lcid)) ||
+                                               (strchr(word, '@') && !strcmp(ast_get_extension_cidmatch(e), cid))) {
+                                       if ( ((strchr(word, '/') || strchr(word, '@')) && !strcmp(ast_get_extension_name(e), exten)) ||
+                                                (!strchr(word, '/') && !strchr(word, '@') && partial_match(ast_get_extension_name(e), exten, le))) { /* n-th match */
+                                               if (++which > state) {
+                                                       /* If there is an extension then return exten@context. */
+                                                       if (ast_get_extension_matchcid(e) && (!strchr(word, '@') || strchr(word, '/'))) {
+                                                               asprintf(&ret, "%s/%s@%s", ast_get_extension_name(e), ast_get_extension_cidmatch(e), ast_get_context_name(c));
+                                                               break;
+                                                       } else if (!ast_get_extension_matchcid(e) && !strchr(word, '/')) {
+                                                               asprintf(&ret, "%s@%s", ast_get_extension_name(e), ast_get_context_name(c));
+                                                               break;
+                                                       }
+                                               }
+                                       }
                                }
                        }
                        if (e)  /* got a match */
                                break;
                }
+#ifdef BROKEN_READLINE
+               free(word2);
+#endif
 
                ast_unlock_contexts();
        error2:
                if (exten)
                        free(exten);
        } else if (pos == 4) { /* 'dialplan remove extension EXT _X_' (priority) */
-               char *exten = NULL, *context, *p;
+               char *exten = NULL, *context, *cid, *p;
                struct ast_context *c;
-               int le, lc, len;
+               int le, lc, lcid, len;
                const char *s = skip_words(line, 3); /* skip 'dialplan' 'remove' 'extension' */
-               int i = split_ec(s, &exten, &context);  /* parse ext@context */
+               int i = split_ec(s, &exten, &context, &cid);    /* parse ext@context */
 
                if (i)  /* error */
                        goto error3;
@@ -854,6 +899,7 @@ static char *complete_context_remove_extension(const char *line, const char *wor
                        *p = '\0';
                le = strlen(exten);
                lc = strlen(context);
+               lcid = cid ? strlen(cid) : -1;
                len = strlen(word);
                if (le == 0 || lc == 0)
                        goto error3;
@@ -876,6 +922,9 @@ static char *complete_context_remove_extension(const char *line, const char *wor
                                struct ast_exten *priority;
                                char buffer[10];
 
+                               if (cid && strcmp(ast_get_extension_cidmatch(e), cid) != 0) {
+                                       continue;
+                               }
                                if (strcmp(ast_get_extension_name(e), exten) != 0)
                                        continue;
                                /* XXX lock e ? */