mirror of
https://github.com/asterisk/asterisk.git
synced 2025-10-13 00:04:53 +00:00
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: https://origsvn.digium.com/svn/asterisk/branches/1.4@127973 65c4cc65-6c06-0410-ace0-fbb531ad65f3
This commit is contained in:
@@ -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
|
||||
*
|
||||
|
62
main/pbx.c
62
main/pbx.c
@@ -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,32 +2857,15 @@ 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;
|
||||
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;
|
||||
|
||||
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) {
|
||||
/*
|
||||
@@ -2878,22 +2874,26 @@ int ast_context_remove_extension2(struct ast_context *con, const char *extension
|
||||
*/
|
||||
struct ast_exten *next_node = peer->peer ? peer->peer : peer->next;
|
||||
|
||||
if (!prev_exten) /* change the root... */
|
||||
if (!prev_exten) { /* change the root... */
|
||||
con->root = next_node;
|
||||
else
|
||||
} else {
|
||||
prev_exten->next = next_node; /* unlink */
|
||||
if (peer->peer) /* XXX update the new head of the pri list */
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
/* now, free whole priority extension */
|
||||
destroy_exten(peer);
|
||||
/* XXX should we return -1 ? */
|
||||
} else {
|
||||
previous_peer = peer;
|
||||
}
|
||||
}
|
||||
ast_mutex_unlock(&con->lock);
|
||||
return 0;
|
||||
return found ? 0 : -1;
|
||||
}
|
||||
|
||||
|
||||
|
103
pbx/pbx_config.c
103
pbx/pbx_config.c
@@ -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 */
|
||||
@@ -226,6 +226,13 @@ static int split_ec(const char *src, char **ext, char ** const ctx)
|
||||
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,13 +715,24 @@ 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)
|
||||
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;
|
||||
}
|
||||
@@ -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);
|
||||
#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)
|
||||
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 ? */
|
||||
|
Reference in New Issue
Block a user