aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/asterisk/pbx.h11
-rw-r--r--main/pbx.c115
-rw-r--r--pbx/pbx_config.c89
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;
}