diff options
author | tilghman <tilghman@f38db490-d61c-443f-a65b-d21fe96a405b> | 2008-07-04 16:10:32 +0000 |
---|---|---|
committer | tilghman <tilghman@f38db490-d61c-443f-a65b-d21fe96a405b> | 2008-07-04 16:10:32 +0000 |
commit | 0cc9dcff58257d2f114ce7bf99bda7ed6becb18e (patch) | |
tree | ff5d3ec6a3bcc6e810c0baeb6838b85f249617a3 | |
parent | 63face35655a24d62de29df01ad10da2cf78b94f (diff) |
Merged revisions 128027 via svnmerge from
https://origsvn.digium.com/svn/asterisk/trunk
................
r128027 | tilghman | 2008-07-04 11:06:34 -0500 (Fri, 04 Jul 2008) | 16 lines
Merged revisions 127973 via svnmerge from
https://origsvn.digium.com/svn/asterisk/branches/1.4
........
r127973 | tilghman | 2008-07-03 22:30:30 -0500 (Thu, 03 Jul 2008) | 8 lines
Fix the 'dialplan remove extension' logic, so that it a) works with cidmatch,
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: http://svn.digium.com/svn/asterisk/branches/1.6.0@128028 f38db490-d61c-443f-a65b-d21fe96a405b
-rw-r--r-- | include/asterisk/pbx.h | 11 | ||||
-rw-r--r-- | main/pbx.c | 115 | ||||
-rw-r--r-- | pbx/pbx_config.c | 89 |
3 files changed, 124 insertions, 91 deletions
diff --git a/include/asterisk/pbx.h b/include/asterisk/pbx.h index f73ac4454..d8fcbae07 100644 --- a/include/asterisk/pbx.h +++ b/include/asterisk/pbx.h @@ -595,7 +595,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. @@ -609,6 +611,13 @@ 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 already_locked); +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, + int already_locked); + /*! * \brief Add an ignorepat * diff --git a/main/pbx.c b/main/pbx.c index aedbc91da..0db5cbb2e 100644 --- a/main/pbx.c +++ b/main/pbx.c @@ -3960,11 +3960,16 @@ int ast_context_remove_switch2(struct ast_context *con, const char *sw, const ch */ 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, 1); + ret = ast_context_remove_extension_callerid2(c, extension, priority, callerid, matchcid, registrar, 1); ast_unlock_contexts(); } return ret; @@ -3982,23 +3987,34 @@ 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 already_locked) { + return ast_context_remove_extension_callerid2(con, extension, priority, NULL, 0, registrar, already_locked); +} + +int ast_context_remove_extension_callerid2(struct ast_context *con, const char *extension, int priority, const char *callerid, int matchcid, const char *registrar, int already_locked) +{ struct ast_exten *exten, *prev_exten = NULL; struct ast_exten *peer; struct ast_exten ex, *exten2, *exten3; char dummy_name[1024]; + struct ast_exten *previous_peer = NULL; + struct ast_exten *next_peer = NULL; + int found = 0; if (!already_locked) ast_wrlock_context(con); /* Handle this is in the new world */ + /* FIXME For backwards compatibility, if callerid==NULL, then remove ALL + * peers, not just those matching the callerid. */ #ifdef NEED_DEBUG - ast_log(LOG_NOTICE,"Removing %s/%s/%d from trees, registrar=%s\n", con->name, extension, priority, registrar); + ast_verb(3,"Removing %s/%s/%d%s%s from trees, registrar=%s\n", con->name, extension, priority, matchcid ? "/" : "", matchcid ? callerid : "", registrar); #endif /* find this particular extension */ ex.exten = dummy_name; - ex.matchcid = 0; - ast_copy_string(dummy_name,extension, sizeof(dummy_name)); + ex.matchcid = matchcid; + ex.cidmatch = callerid; + ast_copy_string(dummy_name, extension, sizeof(dummy_name)); exten = ast_hashtab_lookup(con->root_tree, &ex); if (exten) { if (priority == 0) @@ -4027,7 +4043,7 @@ int ast_context_remove_extension2(struct ast_context *con, const char *extension if (!exten3) ast_log(LOG_ERROR,"Did not remove this priority label (%d/%s) from the peer_label_tree of context %s, extension %s!\n", priority, exten2->label, con->name, exten2->exten); } - + exten3 = ast_hashtab_remove_this_object(exten->peer_tree, exten2); if (!exten3) ast_log(LOG_ERROR,"Did not remove this priority (%d) from the peer_tree of context %s, extension %s!\n", priority, con->name, exten2->exten); @@ -4061,9 +4077,8 @@ int ast_context_remove_extension2(struct ast_context *con, const char *extension log_match_char_tree(con->pattern_tree, " "); } #endif - - /* 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))) @@ -4076,66 +4091,44 @@ 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; - - /* 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; + /* 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; + + /* 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 */ - if (!already_locked) - ast_unlock_context(con); - 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 (next_node && next_node == peer->peer) { - next_node->peer_tree = exten->peer_tree; /* move the priority hash tabs over */ - exten->peer_tree = 0; - next_node->peer_label_tree = exten->peer_label_tree; - exten->peer_label_tree = 0; - } - 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; + 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; } - - } else { /* easy, we are not first priority in extension */ - previous_peer->peer = peer->peer; - } - /* now, free whole priority extension */ - destroy_exten(peer); - /* XXX should we return -1 ? */ + /* now, free whole priority extension */ + destroy_exten(peer); + } else { + previous_peer = peer; + } } if (!already_locked) ast_unlock_context(con); - return 0; + return found ? 0 : -1; } diff --git a/pbx/pbx_config.c b/pbx/pbx_config.c index 573b88fcb..a4d8c38cb 100644 --- a/pbx/pbx_config.c +++ b/pbx/pbx_config.c @@ -148,9 +148,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 */ @@ -166,7 +166,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; } @@ -297,14 +304,14 @@ static char *complete_dialplan_remove_include(struct ast_cli_args *a) static char *handle_cli_dialplan_remove_extension(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) { int removing_priority = 0; - char *exten, *context; + char *exten, *context, *cid; char *ret = CLI_FAILURE; switch (cmd) { case CLI_INIT: e->command = "dialplan remove extension"; e->usage = - "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"; @@ -349,7 +356,7 @@ static char *handle_cli_dialplan_remove_extension(struct ast_cli_entry *e, int c /* * Format exten@context checking ... */ - if (split_ec(a->argv[3], &exten, &context)) + if (split_ec(a->argv[3], &exten, &context, &cid)) return CLI_FAILURE; /* XXX malloc failure */ if ((!strlen(exten)) || (!(strlen(context)))) { ast_cli(a->fd, "Missing extension or context name in third argument '%s'\n", @@ -358,7 +365,9 @@ static char *handle_cli_dialplan_remove_extension(struct ast_cli_entry *e, int c return CLI_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(a->fd, "Whole extension %s@%s removed\n", exten, context); @@ -368,7 +377,11 @@ static char *handle_cli_dialplan_remove_extension(struct ast_cli_entry *e, int c ret = CLI_SUCCESS; } else { - ast_cli(a->fd, "Failed to remove extension %s@%s\n", exten, context); + if (cid) { + ast_cli(a->fd, "Failed to remove extension %s/%s@%s\n", exten, cid, context); + } else { + ast_cli(a->fd, "Failed to remove extension %s@%s\n", exten, context); + } ret = CLI_FAILURE; } free(exten); @@ -380,15 +393,15 @@ static char *handle_cli_dialplan_remove_extension(struct ast_cli_entry *e, int c #ifdef BROKEN_READLINE /* * There is one funny thing, when you have word like 300@ and you hit - * <tab>, you arguments will like as your word is '300 ', so it '@' - * characters acts sometimes as word delimiter and sometimes as a part - * of word + * <tab>, you arguments will act as your word is '300 ', so the '@' + * character acts sometimes as a word delimiter and sometimes as a part + * of a word. * - * This fix function, allocates new word variable and store here every - * time xxx@yyy always as one word and correct pos is set too + * This fix function allocates a new word variable and stores it every + * time as xxx@yyy. The correct pos is set, too. * - * It's ugly, I know, but I'm waiting for Mark suggestion if upper is - * bug or feature ... + * It's ugly, I know, but I'm waiting for Mark's suggestion if the + * previous is a bug or a feature ... */ static int fix_complete_args(const char *line, char **word, int *pos) { @@ -442,18 +455,21 @@ static char *complete_dialplan_remove_extension(struct ast_cli_args *a) if (a->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(a->word, &exten, &context); + lc = split_ec(a->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"); @@ -467,11 +483,22 @@ static char *complete_dialplan_remove_extension(struct ast_cli_args *a) 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 > a->n) { /* 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(a->word, '/') || + (!strchr(a->word, '@') && partial_match(ast_get_extension_cidmatch(e), cid, lcid)) || + (strchr(a->word, '@') && !strcmp(ast_get_extension_cidmatch(e), cid))) { + if ( ((strchr(a->word, '/') || strchr(a->word, '@')) && !strcmp(ast_get_extension_name(e), exten)) || + (!strchr(a->word, '/') && !strchr(a->word, '@') && partial_match(ast_get_extension_name(e), exten, le))) { /* n-th match */ + if (++which > a->n) { + /* If there is an extension then return exten@context. */ + if (ast_get_extension_matchcid(e) && (!strchr(a->word, '@') || strchr(a->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(a->word, '/')) { + asprintf(&ret, "%s@%s", ast_get_extension_name(e), ast_get_context_name(c)); + break; + } + } + } } } if (e) /* got a match */ @@ -483,11 +510,11 @@ static char *complete_dialplan_remove_extension(struct ast_cli_args *a) if (exten) free(exten); } else if (a->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(a->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; @@ -497,6 +524,7 @@ static char *complete_dialplan_remove_extension(struct ast_cli_args *a) *p = '\0'; le = strlen(exten); lc = strlen(context); + lcid = strlen(cid); len = strlen(a->word); if (le == 0 || lc == 0) goto error3; @@ -519,6 +547,9 @@ static char *complete_dialplan_remove_extension(struct ast_cli_args *a) 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 ? */ @@ -536,10 +567,10 @@ static char *complete_dialplan_remove_extension(struct ast_cli_args *a) error3: if (exten) free(exten); + } #ifdef BROKEN_READLINE - free(word2); + free(word2); #endif - } return ret; } |