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: https://origsvn.digium.com/svn/asterisk/trunk@128027 65c4cc65-6c06-0410-ace0-fbb531ad65f3
This commit is contained in:
Tilghman Lesher
2008-07-04 16:06:34 +00:00
parent 6f621e6205
commit 12e5c68622
3 changed files with 125 additions and 92 deletions

View File

@@ -588,7 +588,9 @@ int ast_context_remove_switch2(struct ast_context *con, const char *sw,
* *
* \param context context to remove extension from * \param context context to remove extension from
* \param extension which extension to remove * \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 * \param registrar registrar of the extension
* *
* This function removes an extension from a given context. * This function removes an extension from a given context.
@@ -602,6 +604,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 ast_context_remove_extension2(struct ast_context *con, const char *extension,
int priority, const char *registrar, int already_locked); 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 * \brief Add an ignorepat
* *

View File

@@ -4002,12 +4002,17 @@ int ast_context_remove_switch2(struct ast_context *con, const char *sw, const ch
* In this function we are using * In this function we are using
*/ */
int ast_context_remove_extension(const char *context, const char *extension, int priority, const char *registrar) 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 */ int ret = -1; /* default error return */
struct ast_context *c = find_context_locked(context); struct ast_context *c = find_context_locked(context);
if (c) { /* ... remove extension ... */ 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(); ast_unlock_contexts();
} }
return ret; return ret;
@@ -4024,24 +4029,35 @@ 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_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 *exten, *prev_exten = NULL;
struct ast_exten *peer; struct ast_exten *peer;
struct ast_exten ex, *exten2, *exten3; struct ast_exten ex, *exten2, *exten3;
char dummy_name[1024]; char dummy_name[1024];
struct ast_exten *previous_peer = NULL;
struct ast_exten *next_peer = NULL;
int found = 0;
if (!already_locked) if (!already_locked)
ast_wrlock_context(con); ast_wrlock_context(con);
/* Handle this is in the new world */ /* 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 #ifdef NEED_DEBUG
ast_verb(3,"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 #endif
/* find this particular extension */ /* find this particular extension */
ex.exten = dummy_name; ex.exten = dummy_name;
ex.matchcid = 0; ex.matchcid = matchcid;
ast_copy_string(dummy_name,extension, sizeof(dummy_name)); ex.cidmatch = callerid;
ast_copy_string(dummy_name, extension, sizeof(dummy_name));
exten = ast_hashtab_lookup(con->root_table, &ex); exten = ast_hashtab_lookup(con->root_table, &ex);
if (exten) { if (exten) {
if (priority == 0) if (priority == 0)
@@ -4109,8 +4125,7 @@ int ast_context_remove_extension2(struct ast_context *con, const char *extension
} }
#endif #endif
/* scan the extension list to find first matching extension-registrar */
/* scan the extension list to find matching extension-registrar */
for (exten = con->root; exten; prev_exten = exten, exten = exten->next) { for (exten = con->root; exten; prev_exten = exten, exten = exten->next) {
if (!strcmp(exten->exten, extension) && if (!strcmp(exten->exten, extension) &&
(!registrar || !strcmp(exten->registrar, registrar))) (!registrar || !strcmp(exten->registrar, registrar)))
@@ -4123,33 +4138,15 @@ int ast_context_remove_extension2(struct ast_context *con, const char *extension
return -1; 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 */ /* 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 */
if (!already_locked)
ast_unlock_context(con);
return -1;
}
/* we are first priority extension? */ /* we are first priority extension? */
if (!previous_peer) { if (!previous_peer) {
/* /*
@@ -4157,32 +4154,28 @@ int ast_context_remove_extension2(struct ast_context *con, const char *extension
* The next node is either the next priority or the next extension * The next node is either the next priority or the next extension
*/ */
struct ast_exten *next_node = peer->peer ? peer->peer : peer->next; struct ast_exten *next_node = peer->peer ? peer->peer : peer->next;
if (next_node && next_node == peer->peer) {
next_node->peer_table = exten->peer_table; /* move the priority hash tabs over */
exten->peer_table = 0;
next_node->peer_label_table = exten->peer_label_table;
exten->peer_label_table = 0;
}
if (!prev_exten) { /* change the root... */ if (!prev_exten) { /* change the root... */
con->root = next_node; con->root = next_node;
} else { } else {
prev_exten->next = next_node; /* unlink */ 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; peer->peer->next = peer->next;
} }
} else { /* easy, we are not first priority in extension */ } else { /* easy, we are not first priority in extension */
previous_peer->peer = peer->peer; previous_peer->peer = peer->peer;
} }
/* now, free whole priority extension */ /* now, free whole priority extension */
destroy_exten(peer); destroy_exten(peer);
/* XXX should we return -1 ? */ } else {
previous_peer = peer;
}
} }
if (!already_locked) if (!already_locked)
ast_unlock_context(con); ast_unlock_context(con);
return 0; return found ? 0 : -1;
} }

View File

@@ -149,9 +149,9 @@ static int partial_match(const char *s, const char *word, int len)
/*! \brief split extension\@context in two parts, return -1 on error. /*! \brief split extension\@context in two parts, return -1 on error.
* The return string is malloc'ed and pointed by *ext * 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) if (e == NULL)
return -1; /* malloc error */ return -1; /* malloc error */
@@ -168,6 +168,13 @@ static int split_ec(const char *src, char **ext, char ** const ctx)
return -1; return -1;
} }
} }
if (cid && (i = strchr(e, '/'))) {
*i++ = '\0';
*cid = i;
} else if (cid) {
/* Signal none detected */
*cid = NULL;
}
return 0; return 0;
} }
@@ -298,14 +305,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) static char *handle_cli_dialplan_remove_extension(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
{ {
int removing_priority = 0; int removing_priority = 0;
char *exten, *context; char *exten, *context, *cid;
char *ret = CLI_FAILURE; char *ret = CLI_FAILURE;
switch (cmd) { switch (cmd) {
case CLI_INIT: case CLI_INIT:
e->command = "dialplan remove extension"; e->command = "dialplan remove extension";
e->usage = 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" " Remove an extension from a given context. If a priority\n"
" is given, only that specific priority from the given extension\n" " is given, only that specific priority from the given extension\n"
" will be removed.\n"; " will be removed.\n";
@@ -350,7 +357,7 @@ static char *handle_cli_dialplan_remove_extension(struct ast_cli_entry *e, int c
/* /*
* Format exten@context checking ... * 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 */ return CLI_FAILURE; /* XXX malloc failure */
if ((!strlen(exten)) || (!(strlen(context)))) { if ((!strlen(exten)) || (!(strlen(context)))) {
ast_cli(a->fd, "Missing extension or context name in third argument '%s'\n", ast_cli(a->fd, "Missing extension or context name in third argument '%s'\n",
@@ -359,7 +366,9 @@ static char *handle_cli_dialplan_remove_extension(struct ast_cli_entry *e, int c
return CLI_FAILURE; 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) if (!removing_priority)
ast_cli(a->fd, "Whole extension %s@%s removed\n", ast_cli(a->fd, "Whole extension %s@%s removed\n",
exten, context); exten, context);
@@ -368,8 +377,12 @@ static char *handle_cli_dialplan_remove_extension(struct ast_cli_entry *e, int c
exten, context, removing_priority); exten, context, removing_priority);
ret = CLI_SUCCESS; ret = CLI_SUCCESS;
} else {
if (cid) {
ast_cli(a->fd, "Failed to remove extension %s/%s@%s\n", exten, cid, context);
} else { } else {
ast_cli(a->fd, "Failed to remove extension %s@%s\n", exten, context); ast_cli(a->fd, "Failed to remove extension %s@%s\n", exten, context);
}
ret = CLI_FAILURE; ret = CLI_FAILURE;
} }
free(exten); free(exten);
@@ -381,15 +394,15 @@ static char *handle_cli_dialplan_remove_extension(struct ast_cli_entry *e, int c
#ifdef BROKEN_READLINE #ifdef BROKEN_READLINE
/* /*
* There is one funny thing, when you have word like 300@ and you hit * 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 '@' * <tab>, you arguments will act as your word is '300 ', so the '@'
* characters acts sometimes as word delimiter and sometimes as a part * character acts sometimes as a word delimiter and sometimes as a part
* of word * of a word.
* *
* This fix function, allocates new word variable and store here every * This fix function allocates a new word variable and stores it every
* time xxx@yyy always as one word and correct pos is set too * 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 * It's ugly, I know, but I'm waiting for Mark's suggestion if the
* bug or feature ... * previous is a bug or a feature ...
*/ */
static int fix_complete_args(const char *line, char **word, int *pos) static int fix_complete_args(const char *line, char **word, int *pos)
{ {
@@ -443,18 +456,21 @@ static char *complete_dialplan_remove_extension(struct ast_cli_args *a)
if (a->pos == 3) { /* 'dialplan remove extension _X_' (exten@context ... */ if (a->pos == 3) { /* 'dialplan remove extension _X_' (exten@context ... */
struct ast_context *c = NULL; struct ast_context *c = NULL;
char *context = NULL, *exten = NULL; char *context = NULL, *exten = NULL, *cid = NULL;
int le = 0; /* length of extension */ int le = 0; /* length of extension */
int lc = 0; /* length of context */ 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 #ifdef BROKEN_READLINE
free(word2); free(word2);
#endif #endif
if (lc) /* error */
return NULL; return NULL;
}
le = strlen(exten); le = strlen(exten);
lc = strlen(context); lc = strlen(context);
lcid = cid ? strlen(cid) : -1;
if (ast_rdlock_contexts()) { if (ast_rdlock_contexts()) {
ast_log(LOG_ERROR, "Failed to lock context list\n"); ast_log(LOG_ERROR, "Failed to lock context list\n");
@@ -468,13 +484,24 @@ static char *complete_dialplan_remove_extension(struct ast_cli_args *a)
if (!partial_match(ast_get_context_name(c), context, lc)) if (!partial_match(ast_get_context_name(c), context, lc))
continue; /* context not matched */ continue; /* context not matched */
while ( (e = ast_walk_context_extensions(c, e)) ) { /* try to complete extensions ... */ 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 ( !strchr(a->word, '/') ||
/* If there is an extension then return exten@context. XXX otherwise ? */ (!strchr(a->word, '@') && partial_match(ast_get_extension_cidmatch(e), cid, lcid)) ||
if (exten) (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)); asprintf(&ret, "%s@%s", ast_get_extension_name(e), ast_get_context_name(c));
break; break;
} }
} }
}
}
}
if (e) /* got a match */ if (e) /* got a match */
break; break;
} }
@@ -484,11 +511,11 @@ static char *complete_dialplan_remove_extension(struct ast_cli_args *a)
if (exten) if (exten)
free(exten); free(exten);
} else if (a->pos == 4) { /* 'dialplan remove extension EXT _X_' (priority) */ } 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; 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' */ 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 */ if (i) /* error */
goto error3; goto error3;
@@ -498,6 +525,7 @@ static char *complete_dialplan_remove_extension(struct ast_cli_args *a)
*p = '\0'; *p = '\0';
le = strlen(exten); le = strlen(exten);
lc = strlen(context); lc = strlen(context);
lcid = strlen(cid);
len = strlen(a->word); len = strlen(a->word);
if (le == 0 || lc == 0) if (le == 0 || lc == 0)
goto error3; goto error3;
@@ -520,6 +548,9 @@ static char *complete_dialplan_remove_extension(struct ast_cli_args *a)
struct ast_exten *priority; struct ast_exten *priority;
char buffer[10]; char buffer[10];
if (cid && strcmp(ast_get_extension_cidmatch(e), cid) != 0) {
continue;
}
if (strcmp(ast_get_extension_name(e), exten) != 0) if (strcmp(ast_get_extension_name(e), exten) != 0)
continue; continue;
/* XXX lock e ? */ /* XXX lock e ? */
@@ -537,10 +568,10 @@ static char *complete_dialplan_remove_extension(struct ast_cli_args *a)
error3: error3:
if (exten) if (exten)
free(exten); free(exten);
}
#ifdef BROKEN_READLINE #ifdef BROKEN_READLINE
free(word2); free(word2);
#endif #endif
}
return ret; return ret;
} }