Index: pbx/pbx_config.c =================================================================== --- pbx/pbx_config.c (revision 127467) +++ pbx/pbx_config.c (working copy) @@ -69,7 +69,7 @@ " 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 @@ /*! \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 @@ 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 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 @@ /* * 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 @@ 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(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 @@ /* * 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 @@ 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 @@ 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 @@ 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,16 @@ 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 ( !cid || partial_match(ast_get_extension_cidmatch(e), cid, lcid)) { + 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 && 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)); + } else if (exten && !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 +736,11 @@ 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 +750,7 @@ *p = '\0'; le = strlen(exten); lc = strlen(context); + lcid = strlen(cid); len = strlen(word); if (le == 0 || lc == 0) goto error3; @@ -754,6 +773,9 @@ 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 +821,21 @@ 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 +849,35 @@ 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 ( !cid || partial_match(ast_get_extension_cidmatch(e), cid, lcid)) { + 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 && 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)); + } else if (exten && !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 +887,7 @@ *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 +910,9 @@ 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 ? */ Index: include/asterisk/pbx.h =================================================================== --- include/asterisk/pbx.h (revision 127467) +++ include/asterisk/pbx.h (working copy) @@ -585,7 +585,9 @@ * * \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_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: main/pbx.c =================================================================== --- main/pbx.c (revision 127467) +++ main/pbx.c (working copy) @@ -2820,11 +2820,16 @@ */ 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; @@ -2842,12 +2847,20 @@ */ 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))) @@ -2859,56 +2872,43 @@ 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; }