aboutsummaryrefslogtreecommitdiffstats
path: root/pbx.c
diff options
context:
space:
mode:
authormarkster <markster@f38db490-d61c-443f-a65b-d21fe96a405b>2001-09-28 21:20:52 +0000
committermarkster <markster@f38db490-d61c-443f-a65b-d21fe96a405b>2001-09-28 21:20:52 +0000
commit6a0f5ddef69ba88188d20a8f88eeaae7b08861bd (patch)
tree5e9503ba2ab49ca3c8711b1423fc371547841052 /pbx.c
parent5748a5ea45fd3ef6acb81b40c81b0f52a20ad3f3 (diff)
Version 0.1.9 from FTP
git-svn-id: http://svn.digium.com/svn/asterisk/trunk@361 f38db490-d61c-443f-a65b-d21fe96a405b
Diffstat (limited to 'pbx.c')
-rwxr-xr-xpbx.c1905
1 files changed, 1544 insertions, 361 deletions
diff --git a/pbx.c b/pbx.c
index bbc5f22b8..186045098 100755
--- a/pbx.c
+++ b/pbx.c
@@ -18,12 +18,14 @@
#include <asterisk/options.h>
#include <asterisk/logger.h>
#include <asterisk/file.h>
+#include <asterisk/callerid.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <setjmp.h>
#include <ctype.h>
+#include <errno.h>
#include "asterisk.h"
/*
@@ -47,6 +49,8 @@ struct ast_pbx {
/* An extension */
struct ast_exten {
char exten[AST_MAX_EXTENSION];
+ int matchcid;
+ char cidmatch[AST_MAX_EXTENSION];
int priority;
/* An extension */
struct ast_context *parent;
@@ -70,6 +74,19 @@ struct ast_include {
struct ast_include *next;
};
+struct ast_sw {
+ char name[AST_MAX_EXTENSION];
+ char *registrar;
+ char data[AST_MAX_EXTENSION];
+ struct ast_sw *next;
+};
+
+struct ast_ignorepat {
+ char pattern[AST_MAX_EXTENSION];
+ char *registrar;
+ struct ast_ignorepat *next;
+};
+
/* An extension context */
struct ast_context {
/* Name of the context */
@@ -82,8 +99,12 @@ struct ast_context {
struct ast_context *next;
/* Include other contexts */
struct ast_include *includes;
+ /* Patterns for which to continue playing dialtone */
+ struct ast_ignorepat *ignorepats;
/* Registrar */
char *registrar;
+ /* Alternative switches */
+ struct ast_sw *alts;
};
@@ -121,68 +142,98 @@ static struct pbx_builtin {
/* These applications are built into the PBX core and do not
need separate modules */
{ "Answer", pbx_builtin_answer,
- "Answer a channel if ringing",
- " Answer(): If the channel is ringing, answer it, otherwise do nothing. Returns 0 unless it\n"
- " tries to answer the channel and fails.\n" },
+"Answer a channel if ringing",
+" Answer(): If the channel is ringing, answer it, otherwise do nothing. \n"
+"Returns 0 unless it tries to answer the channel and fails.\n" },
+
{ "Goto", pbx_builtin_goto,
- "Goto a particular priority, extension, or context",
- " Goto([[context|]extension|]priority): Set the priority to the specified value, optionally setting\n"
- " the extension and optionally the context as well. The extension BYEXTENSION is special in that it\n"
- " uses the current extension, thus permitting you to go to a different context, without specifying a\n"
- " specific extension. Always returns 0, even if the given context, extension, or priority is invalid.\n" },
+"Goto a particular priority, extension, or context",
+" Goto([[context|]extension|]priority): Set the priority to the specified\n"
+"value, optionally setting the extension and optionally the context as well.\n"
+"The extension BYEXTENSION is special in that it uses the current extension,\n"
+"thus permitting you to go to a different context, without specifying a\n"
+"specific extension. Always returns 0, even if the given context, extension,\n"
+"or priority is invalid.\n" },
+
{ "Hangup", pbx_builtin_hangup,
- "Unconditional hangup",
- " Hangup(): Unconditionally hangs up a given channel by returning -1 always.\n" },
+"Unconditional hangup",
+" Hangup(): Unconditionally hangs up a given channel by returning -1 always.\n" },
+
{ "DigitTimeout", pbx_builtin_dtimeout,
- "Set maximum timeout between digits",
- " DigitTimeout(seconds): Set the maximum amount of time permitted between digits when the user is\n"
- " typing in an extension. When this timeout expires, after the user has started to type in an\n"
- " extension, the extension will be considered complete, and will be interpreted. Note that if an\n"
- " extension typed in is valid, it will not have to timeout to be tested, so typically at the expiry\n"
- " of this timeout, the extension will be considered invalid (and thus control would be passed to the\n"
- " 'i' extension, or if it doesn't exist the call would be terminated). Always returns 0.\n" },
+"Set maximum timeout between digits",
+" DigitTimeout(seconds): Set the maximum amount of time permitted between\n"
+"digits when the user is typing in an extension. When this timeout expires,\n"
+"after the user has started to type in an extension, the extension will be\n"
+"considered complete, and will be interpreted. Note that if an extension\n"
+"typed in is valid, it will not have to timeout to be tested, so typically\n"
+"at the expiry of this timeout, the extension will be considered invalid\n"
+"(and thus control would be passed to the 'i' extension, or if it doesn't\n"
+"exist the call would be terminated). Always returns 0.\n" },
+
{ "ResponseTimeout", pbx_builtin_rtimeout,
- "Set maximum timeout awaiting response",
- " ResponseTimeout(seconds): Set the maximum amount of time permitted after falling through a series\n"
- " of priorities for a channel in which the user may begin typing an extension. If the user does not\n"
- " type an extension in this amount of time, control will pass to the 't' extension if it exists, and\n"
- " if not the call would be terminated. Always returns 0.\n" },
+"Set maximum timeout awaiting response",
+" ResponseTimeout(seconds): Set the maximum amount of time permitted after\n"
+"falling through a series of priorities for a channel in which the user may\n"
+"begin typing an extension. If the user does not type an extension in this\n"
+"amount of time, control will pass to the 't' extension if it exists, and\n"
+"if not the call would be terminated. Always returns 0.\n" },
+
{ "BackGround", pbx_builtin_background,
- "Play a file while awaiting extension",
- " Background(filename): Plays a given file, while simultaneously waiting for the user to begin typing\n"
- " an extension. The timeouts do not count until the last BackGround application as ended. Always\n"
- " returns 0.\n" },
+"Play a file while awaiting extension",
+" Background(filename): Plays a given file, while simultaneously waiting for\n"
+"the user to begin typing an extension. The timeouts do not count until the\n"
+"last BackGround application as ended. Always returns 0.\n" },
+
{ "Wait", pbx_builtin_wait,
- "Waits for some time",
- " Wait(seconds): Waits for a specified number of seconds, then returns 0.\n" },
- { "StripMSD", pbx_builtin_stripmsd, "Strip leading digits",
- " StripMSD(count): Strips the leading 'count' digits from the channel's associated extension. For\n"
- " example, the number 5551212 when stripped with a count of 3 would be changed to 1212. This app\n"
- " always returns 0, and the PBX will continue processing at the next priority for the *new* extension.\n"
- " So, for example, if priority 3 of 5551212 is StripMSD 3, the next step executed will be priority 4 of\n"
- " 1212. If you switch into an extension which has no first step, the PBX will treat it as though\n"
- " the user dialed an invalid extension.\n" },
- { "Prefix", pbx_builtin_prefix, "Prepend leading digits",
- " Prefix(digits): Prepends the digit string specified by digits to the channel's associated\n"
- " extension. For example, the number 1212 when prefixed with '555' will become 5551212. This app\n"
- " always returns 0, and the PBX will continue processing at the next priority for the *new* extension.\n"
- " So, for example, if priority 3 of 1212 is Prefix 555, the next step executed will be priority 4 of\n"
- " 5551212. If you switch into an extension which has no first step, the PBX will treat it as though\n"
- " the user dialed an invalid extension.\n" },
- { "SetLanguage", pbx_builtin_setlanguage, "Sets user language",
- " SetLanguage(language): Set the channel language to 'language'. This information is used for the\n"
- " generation of numbers, and to select a natural language file when available. For example, if\n"
- " language is set to 'fr' and the file 'demo-congrats' is requested to be played, if the file \n"
- " 'demo-congrats-fr' exists, then it will play that file, and if not will play the normal \n"
- " 'demo-congrats'. Always returns 0.\n" },
- { "Ringing", pbx_builtin_ringing, "Indicate ringing tone",
- " Ringing(): Request that the channel indicate ringing tone to the user. Always returns 0.\n" },
- { "Congestion", pbx_builtin_congestion, "Indicate congestion and stop",
- " Congestion(): Requests that the channel indicate congestion and then waits for the user to\n"
- " hang up. Always returns -1." },
- { "Busy", pbx_builtin_busy, "Indicate busy condition and stop",
- " Busy(): Requests that the channel indicate busy condition and then waits for the user to\n"
- " hang up. Always returns -1." },
+"Waits for some time",
+" Wait(seconds): Waits for a specified number of seconds, then returns 0.\n" },
+
+ { "StripMSD", pbx_builtin_stripmsd,
+"Strip leading digits",
+" StripMSD(count): Strips the leading 'count' digits from the channel's\n"
+"associated extension. For example, the number 5551212 when stripped with a\n"
+"count of 3 would be changed to 1212. This app always returns 0, and the PBX\n"
+"will continue processing at the next priority for the *new* extension.\n"
+" So, for example, if priority 3 of 5551212 is StripMSD 3, the next step\n"
+"executed will be priority 4 of 1212. If you switch into an extension which\n"
+"has no first step, the PBX will treat it as though the user dialed an\n"
+"invalid extension.\n" },
+
+ { "Prefix", pbx_builtin_prefix,
+"Prepend leading digits",
+" Prefix(digits): Prepends the digit string specified by digits to the\n"
+"channel's associated extension. For example, the number 1212 when prefixed\n"
+"with '555' will become 5551212. This app always returns 0, and the PBX will\n"
+"continue processing at the next priority for the *new* extension.\n"
+" So, for example, if priority 3 of 1212 is Prefix 555, the next step\n"
+"executed will be priority 4 of 5551212. If you switch into an extension\n"
+"which has no first step, the PBX will treat it as though the user dialed an\n"
+"invalid extension.\n" },
+
+ { "SetLanguage", pbx_builtin_setlanguage,
+"Sets user language",
+" SetLanguage(language): Set the channel language to 'language'. This\n"
+"information is used for the generation of numbers, and to select a natural\n"
+"language file when available. For example, if language is set to 'fr' and\n"
+"the file 'demo-congrats' is requested to be played, if the file 'demo-\n"
+"congrats-fr' exists, then it will play that file, and if not will play the\n"
+"normal 'demo-congrats'. Always returns 0.\n" },
+
+ { "Ringing", pbx_builtin_ringing,
+"Indicate ringing tone",
+" Ringing(): Request that the channel indicate ringing tone to the user.\n"
+"Always returns 0.\n" },
+
+ { "Congestion", pbx_builtin_congestion,
+"Indicate congestion and stop",
+" Congestion(): Requests that the channel indicate congestion and then\n"
+"waits for the user to hang up. Always returns -1." },
+
+ { "Busy", pbx_builtin_busy,
+"Indicate busy condition and stop",
+" Busy(): Requests that the channel indicate busy condition and then waits\n"
+"for the user to hang up. Always returns -1." },
+
};
/* Lock for the application list */
@@ -192,8 +243,12 @@ static struct ast_context *contexts = NULL;
static pthread_mutex_t conlock = PTHREAD_MUTEX_INITIALIZER;
static struct ast_app *apps = NULL;
-static int pbx_exec(struct ast_channel *c, /* Channel */
- int (*execute)(struct ast_channel *chan, void *data),
+/* Lock for switches */
+static pthread_mutex_t switchlock = PTHREAD_MUTEX_INITIALIZER;
+struct ast_switch *switches = NULL;
+
+int pbx_exec(struct ast_channel *c, /* Channel */
+ struct ast_app *app,
void *data, /* Data for execution */
int newstack) /* Force stack increment */
{
@@ -201,6 +256,7 @@ static int pbx_exec(struct ast_channel *c, /* Channel */
how many times it is called, it returns to the same place */
int res;
int stack = c->stack;
+ int (*execute)(struct ast_channel *chan, void *data) = app->execute;
if (newstack && stack > AST_CHANNEL_MAX_STACK - 2) {
/* Don't allow us to go over the max number of stacks we
permit saving. */
@@ -221,7 +277,11 @@ static int pbx_exec(struct ast_channel *c, /* Channel */
c->stack = stack;
return res;
} else {
+ c->appl = app->name;
+ c->data = data;
res = execute(c, data);
+ c->appl = NULL;
+ c->data = NULL;
/* Any application that returns, we longjmp back, just in case. */
if (c->stack != stack + 1)
ast_log(LOG_WARNING, "Stack is not at expected value\n");
@@ -239,7 +299,7 @@ static int pbx_exec(struct ast_channel *c, /* Channel */
#define HELPER_EXEC 2
#define HELPER_CANMATCH 3
-static struct ast_app *pbx_findapp(char *app)
+struct ast_app *pbx_findapp(char *app)
{
struct ast_app *tmp;
if (ast_pthread_mutex_lock(&applock)) {
@@ -256,6 +316,23 @@ static struct ast_app *pbx_findapp(char *app)
return tmp;
}
+static struct ast_switch *pbx_findswitch(char *sw)
+{
+ struct ast_switch *asw;
+ if (ast_pthread_mutex_lock(&switchlock)) {
+ ast_log(LOG_WARNING, "Unable to obtain application lock\n");
+ return NULL;
+ }
+ asw = switches;
+ while(asw) {
+ if (!strcasecmp(asw->name, sw))
+ break;
+ asw = asw->next;
+ }
+ ast_pthread_mutex_unlock(&switchlock);
+ return asw;
+}
+
static void pbx_destroy(struct ast_pbx *p)
{
free(p);
@@ -270,13 +347,10 @@ int ast_extension_match(char *pattern, char *data)
/* All patterns begin with _ */
if (pattern[0] != '_')
return 0;
- /* Obviously must be the same length */
- if (strlen(pattern) != strlen(data) + 1)
- return 0;
/* Start optimistic */
match=1;
pattern++;
- while(match && *data && *pattern) {
+ while(match && *data && *pattern && (*pattern != '/')) {
switch(toupper(*pattern)) {
case 'N':
if ((*data < '2') || (*data > '9'))
@@ -286,6 +360,14 @@ int ast_extension_match(char *pattern, char *data)
if ((*data < '0') || (*data > '9'))
match = 0;
break;
+ case '.':
+ /* Must match */
+ return 1;
+ case ' ':
+ case '-':
+ /* Ignore these characters */
+ data--;
+ break;
default:
if (*data != *pattern)
match =0;
@@ -293,6 +375,9 @@ int ast_extension_match(char *pattern, char *data)
data++;
pattern++;
}
+ /* Must be at the end of both */
+ if (*data || (*pattern && (*pattern != '/')))
+ match = 0;
return match;
}
@@ -313,7 +398,7 @@ static int extension_close(char *pattern, char *data)
/* Start optimistic */
match=1;
pattern++;
- while(match && *data && *pattern) {
+ while(match && *data && *pattern && (*pattern != '/')) {
switch(toupper(*pattern)) {
case 'N':
if ((*data < '2') || (*data > '9'))
@@ -323,6 +408,14 @@ static int extension_close(char *pattern, char *data)
if ((*data < '0') || (*data > '9'))
match = 0;
break;
+ case '.':
+ /* Must match */
+ return 1;
+ case ' ':
+ case '-':
+ /* Ignore these characters */
+ data--;
+ break;
default:
if (*data != *pattern)
match =0;
@@ -355,15 +448,49 @@ struct ast_context *ast_context_find(char *name)
#define STATUS_NO_PRIORITY 3
#define STATUS_SUCCESS 4
-static struct ast_exten *pbx_find_extension(char *context, char *exten, int priority, int action, char *incstack[], int *stacklen, int *status)
+static int matchcid(char *cidpattern, char *callerid)
{
- int x;
+ char tmp[AST_MAX_EXTENSION];
+ int failresult;
+ char *name, *num;
+
+ /* If the Caller*ID pattern is empty, then we're matching NO Caller*ID, so
+ failing to get a number should count as a match, otherwise not */
+
+
+ if (strlen(cidpattern))
+ failresult = 0;
+ else
+ failresult = 1;
+
+ if (!callerid)
+ return failresult;
+
+ /* Copy original Caller*ID */
+ strncpy(tmp, callerid, sizeof(tmp));
+ /* Parse Number */
+ if (ast_callerid_parse(tmp, &name, &num))
+ return failresult;
+ if (!num)
+ return failresult;
+ ast_shrink_phone_number(num);
+ return ast_extension_match(cidpattern, num);
+}
+
+static struct ast_exten *pbx_find_extension(struct ast_channel *chan, char *context, char *exten, int priority, char *callerid, int action, char *incstack[], int *stacklen, int *status, struct ast_switch **swo, char **data)
+{
+ int x, res;
struct ast_context *tmp;
struct ast_exten *e, *eroot;
struct ast_include *i;
+ struct ast_sw *sw;
+ struct ast_switch *asw;
/* Initialize status if appropriate */
- if (!*stacklen)
+ if (!*stacklen) {
*status = STATUS_NO_CONTEXT;
+ *swo = NULL;
+ *data = NULL;
+ }
/* Check for stack overflow */
if (*stacklen >= AST_PBX_MAX_STACK) {
ast_log(LOG_WARNING, "Maximum PBX stack exceeded\n");
@@ -383,8 +510,9 @@ static struct ast_exten *pbx_find_extension(char *context, char *exten, int prio
eroot = tmp->root;
while(eroot) {
/* Match extension */
- if (ast_extension_match(eroot->exten, exten) ||
- ((action == HELPER_CANMATCH) && (extension_close(eroot->exten, exten)))) {
+ if ((ast_extension_match(eroot->exten, exten) ||
+ ((action == HELPER_CANMATCH) && (extension_close(eroot->exten, exten)))) &&
+ (!eroot->matchcid || matchcid(eroot->cidmatch, callerid))) {
e = eroot;
if (*status < STATUS_NO_PRIORITY)
*status = STATUS_NO_PRIORITY;
@@ -399,14 +527,35 @@ static struct ast_exten *pbx_find_extension(char *context, char *exten, int prio
}
eroot = eroot->next;
}
+ /* Check alternative switches */
+ sw = tmp->alts;
+ while(sw) {
+ if ((asw = pbx_findswitch(sw->name))) {
+ if (action == HELPER_CANMATCH)
+ res = asw->canmatch ? asw->canmatch(chan, context, exten, priority, callerid, sw->data) : 0;
+ else
+ res = asw->exists ? asw->exists(chan, context, exten, priority, callerid, sw->data) : 0;
+ if (res) {
+ /* Got a match */
+ *swo = asw;
+ *data = sw->data;
+ return NULL;
+ }
+ } else {
+ ast_log(LOG_WARNING, "No such switch '%s'\n", sw->name);
+ }
+ sw = sw->next;
+ }
/* Setup the stack */
incstack[*stacklen] = tmp->name;
(*stacklen)++;
/* Now try any includes we have in this context */
i = tmp->includes;
while(i) {
- if ((e = pbx_find_extension(i->name, exten, priority, action, incstack, stacklen, status)))
+ if ((e = pbx_find_extension(chan, i->name, exten, priority, callerid, action, incstack, stacklen, status, swo, data)))
return e;
+ if (*swo)
+ return NULL;
i = i->next;
}
}
@@ -415,10 +564,12 @@ static struct ast_exten *pbx_find_extension(char *context, char *exten, int prio
return NULL;
}
-static int pbx_extension_helper(struct ast_channel *c, char *context, char *exten, int priority, int action)
+static int pbx_extension_helper(struct ast_channel *c, char *context, char *exten, int priority, char *callerid, int action)
{
struct ast_exten *e;
struct ast_app *app;
+ struct ast_switch *sw;
+ char *data;
int newstack = 0;
int res;
int status = 0;
@@ -431,7 +582,7 @@ static int pbx_extension_helper(struct ast_channel *c, char *context, char *exte
else
return -1;
}
- e = pbx_find_extension(context, exten, priority, action, incstack, &stacklen, &status);
+ e = pbx_find_extension(c, context, exten, priority, callerid, action, incstack, &stacklen, &status, &sw, &data);
if (e) {
switch(action) {
case HELPER_CANMATCH:
@@ -455,12 +606,7 @@ static int pbx_extension_helper(struct ast_channel *c, char *context, char *exte
else if (option_verbose > 2)
ast_verbose( VERBOSE_PREFIX_3 "Executing %s(\"%s\", \"%s\") %s\n",
app->name, c->name, (e->data ? (char *)e->data : NULL), (newstack ? "in new stack" : "in same stack"));
- c->appl = app->name;
- c->data = e->data;
- res = pbx_exec(c, app->execute, e->data, newstack);
- c->appl = NULL;
- c->data = NULL;
- pthread_mutex_unlock(&conlock);
+ res = pbx_exec(c, app, e->data, newstack);
return res;
} else {
ast_log(LOG_WARNING, "No application '%s' for extension (%s, %s, %d)\n", e->app, context, exten, priority);
@@ -470,6 +616,30 @@ static int pbx_extension_helper(struct ast_channel *c, char *context, char *exte
ast_log(LOG_WARNING, "Huh (%d)?\n", action);
return -1;
}
+ } else if (sw) {
+ switch(action) {
+ case HELPER_CANMATCH:
+ pthread_mutex_unlock(&conlock);
+ return -1;
+ case HELPER_EXISTS:
+ pthread_mutex_unlock(&conlock);
+ return -1;
+ case HELPER_SPAWN:
+ newstack++;
+ /* Fall through */
+ case HELPER_EXEC:
+ pthread_mutex_unlock(&conlock);
+ if (sw->exec)
+ res = sw->exec(c, context, exten, priority, callerid, newstack, data);
+ else {
+ ast_log(LOG_WARNING, "No execution engine for switch %s\n", sw->name);
+ res = -1;
+ }
+ return res;
+ default:
+ ast_log(LOG_WARNING, "Huh (%d)?\n", action);
+ return -1;
+ }
} else {
pthread_mutex_unlock(&conlock);
switch(status) {
@@ -494,95 +664,9 @@ static int pbx_extension_helper(struct ast_channel *c, char *context, char *exte
return 0;
}
-#if 0
- tmp = contexts;
- while(tmp) {
- if (!strcasecmp(tmp->name, context)) {
-#if 0
- /* By locking tmp, not only can the state of its entries not
- change, but it cannot be destroyed either. */
- ast_pthread_mutex_lock(&tmp->lock);
-#endif
- e = tmp->root;
- while(e) {
- if (extension_match(e->exten, exten) ||
- ((action == HELPER_CANMATCH) && extension_close(e->exten, exten))) {
- reale = e;
- while(e) {
- if (e->priority == priority) {
- /* We have a winner! Maybe there are some races
- in here though. XXX */
- switch(action) {
- case HELPER_CANMATCH:
- ast_pthread_mutex_unlock(&conlock);
- return -1;
- case HELPER_EXISTS:
- ast_pthread_mutex_unlock(&conlock);
- return -1;
- case HELPER_SPAWN:
- newstack++;
- /* Fall through */
- case HELPER_EXEC:
- app = pbx_findapp(e->app);
- ast_pthread_mutex_unlock(&conlock);
- if (app) {
- strncpy(c->context, context, sizeof(c->context));
- strncpy(c->exten, exten, sizeof(c->exten));
- c->priority = priority;
- if (option_debug)
- ast_log(LOG_DEBUG, "Launching '%s'\n", app->name);
- else if (option_verbose > 2)
- ast_verbose( VERBOSE_PREFIX_3 "Executing %s(\"%s\", \"%s\") %s\n",
- app->name, c->name, (e->data ? (char *)e->data : NULL), (newstack ? "in new stack" : "in same stack"));
- c->appl = app->name;
- c->data = e->data;
- res = pbx_exec(c, app->execute, e->data, newstack);
- c->appl = NULL;
- c->data = NULL;
- ast_pthread_mutex_unlock(&conlock);
- return res;
- } else {
- ast_log(LOG_WARNING, "No application '%s' for extension (%s, %s, %d)\n", e->app, context, exten, priority);
- return -1;
- }
- default:
- ast_log(LOG_WARNING, "Huh (%d)?\n", action);
- }
- }
- e = e->peer;
- }
- ast_pthread_mutex_unlock(&tmp->lock);
- if ((action != HELPER_EXISTS) && (action != HELPER_CANMATCH)) {
- ast_log(LOG_WARNING, "No such priority '%d' in '%s' in '%s'\n", priority, exten, context);
- ast_pthread_mutex_unlock(&conlock);
- return -1;
- } else if (action != HELPER_CANMATCH) {
- ast_pthread_mutex_unlock(&conlock);
- return 0;
- } else e = reale; /* Keep going */
- }
- e = e->next;
- }
- if ((action != HELPER_EXISTS) && (action != HELPER_CANMATCH)) {
- ast_pthread_mutex_unlock(&conlock);
- ast_log(LOG_WARNING, "No such extension '%s' in '%s'\n", exten, context);
- return -1;
- } else {
- ast_pthread_mutex_unlock(&conlock);
- return 0;
- }
- }
- tmp = tmp->next;
- }
- ast_pthread_mutex_unlock(&conlock);
- if (action != HELPER_EXISTS) {
- ast_log(LOG_WARNING, "No such context '%s'\n", context);
- return -1;
- } else
- return 0;
-#endif
}
+#if 0
int ast_pbx_longest_extension(char *context)
{
/* XXX Not include-aware XXX */
@@ -615,20 +699,21 @@ int ast_pbx_longest_extension(char *context)
ast_log(LOG_WARNING, "No such context '%s'\n", context);
return -1;
}
+#endif
-int ast_exists_extension(struct ast_channel *c, char *context, char *exten, int priority)
+int ast_exists_extension(struct ast_channel *c, char *context, char *exten, int priority, char *callerid)
{
- return pbx_extension_helper(c, context, exten, priority, HELPER_EXISTS);
+ return pbx_extension_helper(c, context, exten, priority, callerid, HELPER_EXISTS);
}
-int ast_canmatch_extension(struct ast_channel *c, char *context, char *exten, int priority)
+int ast_canmatch_extension(struct ast_channel *c, char *context, char *exten, int priority, char *callerid)
{
- return pbx_extension_helper(c, context, exten, priority, HELPER_CANMATCH);
+ return pbx_extension_helper(c, context, exten, priority, callerid, HELPER_CANMATCH);
}
-int ast_spawn_extension(struct ast_channel *c, char *context, char *exten, int priority)
+int ast_spawn_extension(struct ast_channel *c, char *context, char *exten, int priority, char *callerid)
{
- return pbx_extension_helper(c, context, exten, priority, HELPER_SPAWN);
+ return pbx_extension_helper(c, context, exten, priority, callerid, HELPER_SPAWN);
}
int ast_pbx_run(struct ast_channel *c)
@@ -664,7 +749,7 @@ int ast_pbx_run(struct ast_channel *c)
/* Start by trying whatever the channel is set to */
- if (!ast_exists_extension(c, c->context, c->exten, c->priority)) {
+ if (!ast_exists_extension(c, c->context, c->exten, c->priority, c->callerid)) {
strncpy(c->context, "default", sizeof(c->context));
strncpy(c->exten, "s", sizeof(c->exten));
c->priority = 1;
@@ -672,9 +757,9 @@ int ast_pbx_run(struct ast_channel *c)
for(;;) {
pos = 0;
digit = 0;
- while(ast_exists_extension(c, c->context, c->exten, c->priority)) {
+ while(ast_exists_extension(c, c->context, c->exten, c->priority, c->callerid)) {
memset(exten, 0, sizeof(exten));
- if ((res = ast_spawn_extension(c, c->context, c->exten, c->priority))) {
+ if ((res = ast_spawn_extension(c, c->context, c->exten, c->priority, c->callerid))) {
/* Something bad happened, or a hangup has been requested. */
switch(res) {
case AST_PBX_KEEPALIVE:
@@ -714,9 +799,9 @@ int ast_pbx_run(struct ast_channel *c)
firstpass = 0;
c->priority++;
}
- if (!ast_exists_extension(c, c->context, c->exten, 1)) {
+ if (!ast_exists_extension(c, c->context, c->exten, 1, c->callerid)) {
/* It's not a valid extension anymore */
- if (ast_exists_extension(c, c->context, "i", 1)) {
+ if (ast_exists_extension(c, c->context, "i", 1, c->callerid)) {
if (option_verbose > 2)
ast_verbose(VERBOSE_PREFIX_3 "Sent into invalid extension '%s' in context '%s' on %s\n", c->exten, c->context, c->name);
strncpy(c->exten, "i", sizeof(c->exten));
@@ -732,8 +817,8 @@ int ast_pbx_run(struct ast_channel *c)
waittime = c->pbx->dtimeout;
else
waittime = c->pbx->rtimeout;
- while(!ast_exists_extension(c, c->context, exten, 1) &&
- ast_canmatch_extension(c, c->context, exten, 1)) {
+ while(!ast_exists_extension(c, c->context, exten, 1, c->callerid) &&
+ ast_canmatch_extension(c, c->context, exten, 1, c->callerid)) {
/* As long as we're willing to wait, and as long as it's not defined,
keep reading digits until we can't possibly get a right answer anymore. */
digit = ast_waitfordigit(c, waittime * 1000);
@@ -746,7 +831,7 @@ int ast_pbx_run(struct ast_channel *c)
exten[pos++] = digit;
waittime = c->pbx->dtimeout;
}
- if (ast_exists_extension(c, c->context, exten, 1)) {
+ if (ast_exists_extension(c, c->context, exten, 1, c->callerid)) {
/* Prepare the next cycle */
strncpy(c->exten, exten, sizeof(c->exten));
c->priority = 1;
@@ -754,7 +839,7 @@ int ast_pbx_run(struct ast_channel *c)
/* No such extension */
if (strlen(exten)) {
/* An invalid extension */
- if (ast_exists_extension(c, c->context, "i", 1)) {
+ if (ast_exists_extension(c, c->context, "i", 1, c->callerid)) {
if (option_verbose > 2)
ast_verbose( VERBOSE_PREFIX_3 "Invalid extension '%s' in context '%s' on %s\n", exten, c->context, c->name);
strncpy(c->exten, "i", sizeof(c->exten));
@@ -765,7 +850,7 @@ int ast_pbx_run(struct ast_channel *c)
}
} else {
/* A simple timeout */
- if (ast_exists_extension(c, c->context, "t", 1)) {
+ if (ast_exists_extension(c, c->context, "t", 1, c->callerid)) {
if (option_verbose > 2)
ast_verbose( VERBOSE_PREFIX_3 "Timeout on %s\n", c->name);
strncpy(c->exten, "t", sizeof(c->exten));
@@ -818,13 +903,291 @@ int ast_pbx_start(struct ast_channel *c)
}
return 0;
}
-#if 0
-int ast_remove_extension(struct ast_context *con, char *extension, int priority)
+
+/*
+ * This function locks contexts list by &conlist, search for the rigt context
+ * structure, leave context list locked and call ast_context_remove_include2
+ * which removes include, unlock contexts list and return ...
+ */
+int ast_context_remove_include(char *context, char *include, char *registrar)
+{
+ struct ast_context *c;
+
+ if (ast_lock_contexts()) return -1;
+
+ /* walk contexts and search for the right one ...*/
+ c = ast_walk_contexts(NULL);
+ while (c) {
+ /* we found one ... */
+ if (!strcmp(ast_get_context_name(c), context)) {
+ int ret;
+ /* remove include from this context ... */
+ ret = ast_context_remove_include2(c, include, registrar);
+
+ ast_unlock_contexts();
+
+ /* ... return results */
+ return ret;
+ }
+ c = ast_walk_contexts(c);
+ }
+
+ /* we can't find the right one context */
+ ast_unlock_contexts();
+ return -1;
+}
+
+/*
+ * When we call this function, &conlock lock must be locked, because when
+ * we giving *con argument, some process can remove/change this context
+ * and after that there can be segfault.
+ *
+ * This function locks given context, removes include, unlock context and
+ * return.
+ */
+int ast_context_remove_include2(struct ast_context *con, char *include, char *registrar)
{
- /* XXX Implement me XXX */
+ struct ast_include *i, *pi = NULL;
+
+ if (pthread_mutex_lock(&con->lock)) return -1;
+
+ /* walk includes */
+ i = con->includes;
+ while (i) {
+ /* find our include */
+ if (!strcmp(i->name, include) &&
+ (!strcmp(i->registrar, registrar) || !registrar)) {
+ /* remove from list */
+ if (pi)
+ pi->next = i->next;
+ else
+ con->includes = i->next;
+ /* free include and return */
+ free(i);
+ ast_pthread_mutex_unlock(&con->lock);
+ return 0;
+ }
+ pi = i;
+ i = i->next;
+ }
+
+ /* we can't find the right include */
+ ast_pthread_mutex_unlock(&con->lock);
return -1;
}
-#endif
+
+/*
+ * This function locks contexts list by &conlist, search for the rigt context
+ * structure, leave context list locked and call ast_context_remove_switch2
+ * which removes switch, unlock contexts list and return ...
+ */
+int ast_context_remove_switch(char *context, char *sw, char *data, char *registrar)
+{
+ struct ast_context *c;
+
+ if (ast_lock_contexts()) return -1;
+
+ /* walk contexts and search for the right one ...*/
+ c = ast_walk_contexts(NULL);
+ while (c) {
+ /* we found one ... */
+ if (!strcmp(ast_get_context_name(c), context)) {
+ int ret;
+ /* remove switch from this context ... */
+ ret = ast_context_remove_switch2(c, sw, data, registrar);
+
+ ast_unlock_contexts();
+
+ /* ... return results */
+ return ret;
+ }
+ c = ast_walk_contexts(c);
+ }
+
+ /* we can't find the right one context */
+ ast_unlock_contexts();
+ return -1;
+}
+
+/*
+ * When we call this function, &conlock lock must be locked, because when
+ * we giving *con argument, some process can remove/change this context
+ * and after that there can be segfault.
+ *
+ * This function locks given context, removes switch, unlock context and
+ * return.
+ */
+int ast_context_remove_switch2(struct ast_context *con, char *sw, char *data, char *registrar)
+{
+ struct ast_sw *i, *pi = NULL;
+
+ if (pthread_mutex_lock(&con->lock)) return -1;
+
+ /* walk switchs */
+ i = con->alts;
+ while (i) {
+ /* find our switch */
+ if (!strcmp(i->name, sw) && !strcmp(i->data, data) &&
+ (!strcmp(i->registrar, registrar) || !registrar)) {
+ /* remove from list */
+ if (pi)
+ pi->next = i->next;
+ else
+ con->alts = i->next;
+ /* free switch and return */
+ free(i);
+ ast_pthread_mutex_unlock(&con->lock);
+ return 0;
+ }
+ pi = i;
+ i = i->next;
+ }
+
+ /* we can't find the right switch */
+ ast_pthread_mutex_unlock(&con->lock);
+ return -1;
+}
+
+/*
+ * This functions lock contexts list, search for the right context,
+ * call ast_context_remove_extension2, unlock contexts list and return.
+ * In this function we are using
+ */
+int ast_context_remove_extension(char *context, char *extension, int priority, char *registrar)
+{
+ struct ast_context *c;
+
+ if (ast_lock_contexts()) return -1;
+
+ /* walk contexts ... */
+ c = ast_walk_contexts(NULL);
+ while (c) {
+ /* ... search for the right one ... */
+ if (!strcmp(ast_get_context_name(c), context)) {
+ /* ... remove extension ... */
+ int ret = ast_context_remove_extension2(c, extension, priority,
+ registrar);
+ /* ... unlock contexts list and return */
+ ast_unlock_contexts();
+ return ret;
+ }
+ c = ast_walk_contexts(c);
+ }
+
+ /* we can't find the right context */
+ ast_unlock_contexts();
+ return -1;
+}
+
+/*
+ * When do you want to call this function, make sure that &conlock is locked,
+ * because some process can handle with your *con context before you lock
+ * it.
+ *
+ * This functionc locks given context, search for the right extension and
+ * fires out all peer in this extensions with given priority. If priority
+ * is set to 0, all peers are removed. After that, unlock context and
+ * return.
+ */
+int ast_context_remove_extension2(struct ast_context *con, char *extension, int priority, char *registrar)
+{
+ struct ast_exten *exten, *prev_exten = NULL;
+
+ if (ast_pthread_mutex_lock(&con->lock)) return -1;
+
+ /* go through all extensions in context and search the right one ... */
+ exten = con->root;
+ while (exten) {
+
+ /* look for right extension */
+ if (!strcmp(exten->exten, extension) &&
+ (!strcmp(exten->registrar, registrar) || !registrar)) {
+ struct ast_exten *peer;
+
+ /* 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 */
+ peer = exten;
+ while (peer) {
+ exten = peer->peer;
+
+ peer->datad(peer->data);
+ free(peer);
+
+ peer = exten;
+ }
+
+ ast_pthread_mutex_unlock(&con->lock);
+ return 0;
+ } else {
+ /* remove only extension with exten->priority == priority */
+ struct ast_exten *previous_peer = NULL;
+
+ peer = exten;
+ while (peer) {
+ /* is this our extension? */
+ if (peer->priority == priority &&
+ (!strcmp(peer->registrar, registrar) || !registrar)) {
+ /* we are first priority extension? */
+ if (!previous_peer) {
+ /* exists previous extension here? */
+ if (prev_exten) {
+ /* yes, so we must change next pointer in
+ * previous connection to next peer
+ */
+ if (peer->peer) {
+ prev_exten->next = peer->peer;
+ peer->peer->next = exten->next;
+ } else
+ prev_exten->next = exten->next;
+ } else {
+ /* no previous extension, we are first
+ * extension, so change con->root ...
+ */
+ if (peer->peer)
+ con->root = peer->peer;
+ else
+ con->root = exten->next;
+ }
+ } else {
+ /* we are not first priority in extension */
+ previous_peer->peer = peer->peer;
+ }
+
+ /* now, free whole priority extension */
+ peer->datad(peer->data);
+ free(peer);
+
+ ast_pthread_mutex_unlock(&con->lock);
+ return 0;
+ } else {
+ /* this is not right extension, skip to next peer */
+ previous_peer = peer;
+ peer = peer->peer;
+ }
+ }
+
+ ast_pthread_mutex_unlock(&con->lock);
+ return -1;
+ }
+ }
+
+ prev_exten = exten;
+ exten = exten->next;
+ }
+
+ /* we can't find right extension */
+ ast_pthread_mutex_unlock(&con->lock);
+ return -1;
+}
+
+
int ast_register_application(char *app, int (*execute)(struct ast_channel *, void *), char *synopsis, char *description)
{
struct ast_app *tmp;
@@ -860,200 +1223,486 @@ int ast_register_application(char *app, int (*execute)(struct ast_channel *, voi
return 0;
}
-static char app_help[] =
-"Usage: show application <application>\n"
+int ast_register_switch(struct ast_switch *sw)
+{
+ struct ast_switch *tmp, *prev=NULL;
+ if (ast_pthread_mutex_lock(&switchlock)) {
+ ast_log(LOG_ERROR, "Unable to lock switch lock\n");
+ return -1;
+ }
+ tmp = switches;
+ while(tmp) {
+ if (!strcasecmp(tmp->name, sw->name))
+ break;
+ prev = tmp;
+ tmp = tmp->next;
+ }
+ if (tmp) {
+ ast_pthread_mutex_unlock(&switchlock);
+ ast_log(LOG_WARNING, "Switch '%s' already found\n", sw->name);
+ return -1;
+ }
+ sw->next = NULL;
+ if (prev)
+ prev->next = sw;
+ else
+ switches = sw;
+ ast_pthread_mutex_unlock(&switchlock);
+ return 0;
+}
+
+void ast_unregister_switch(struct ast_switch *sw)
+{
+ struct ast_switch *tmp, *prev=NULL;
+ if (ast_pthread_mutex_lock(&switchlock)) {
+ ast_log(LOG_ERROR, "Unable to lock switch lock\n");
+ return;
+ }
+ tmp = switches;
+ while(tmp) {
+ if (tmp == sw) {
+ if (prev)
+ prev->next = tmp->next;
+ else
+ switches = tmp->next;
+ tmp->next = NULL;
+ break;
+ }
+ prev = tmp;
+ tmp = tmp->next;
+ }
+ ast_pthread_mutex_unlock(&switchlock);
+}
+
+/*
+ * Help for CLI commands ...
+ */
+static char show_application_help[] =
+"Usage: show application <application> [<application> [<application> [...]]]\n"
" Describes a particular application.\n";
-static char apps_help[] =
+static char show_applications_help[] =
"Usage: show applications\n"
" List applications which are currently available.\n";
-static char dialplan_help[] =
-"Usage: show dialplan [[exten@]context]\n"
-" Displays dialplan. Optionally takes a context (possibly preceeded by\n"
-" an extension) to limit the scope of the plan that is displayed.\n";
+static char show_dialplan_help[] =
+"Usage: show dialplan [exten@][context]\n"
+" Show dialplan\n";
-static int handle_show_applications(int fd, int argc, char *argv[])
+static char show_switches_help[] =
+"Usage: show switches\n"
+" Show registered switches\n";
+
+/*
+ * IMPLEMENTATION OF CLI FUNCTIONS IS IN THE SAME ORDER AS COMMANDS HELPS
+ *
+ */
+
+/*
+ * 'show application' CLI command implementation functions ...
+ */
+
+/*
+ * There is a possibility to show informations about more than one
+ * application at one time. You can type 'show application Dial Echo' and
+ * you will see informations about these two applications ...
+ */
+static char *complete_show_application(char *line, char *word,
+ int pos, int state)
{
- struct ast_app *tmp;
- char buf[256];
+ struct ast_app *a;
+ int which = 0;
+
+ /* try to lock applications list ... */
if (ast_pthread_mutex_lock(&applock)) {
ast_log(LOG_ERROR, "Unable to lock application list\n");
- return -1;
+ return NULL;
}
- tmp = apps;
- ast_cli(fd, "\n -= Registered Asterisk Applications =-\n");
- while(tmp) {
- snprintf(buf, sizeof(buf), " %15s: %s\n", tmp->name, tmp->synopsis ? tmp->synopsis : "<Synopsis not available>");
- ast_cli(fd, buf);
- tmp = tmp->next;
+
+ /* ... walk all applications ... */
+ a = apps;
+ while (a) {
+ /* ... check if word matches this application ... */
+ if (!strncasecmp(word, a->name, strlen(word))) {
+ /* ... if this is right app serve it ... */
+ if (++which > state) {
+ char *ret = strdup(a->name);
+ ast_pthread_mutex_unlock(&applock);
+ return ret;
+ }
+ }
+ a = a->next;
}
+
+ /* no application match */
ast_pthread_mutex_unlock(&applock);
- return RESULT_SUCCESS;
+ return NULL;
}
-static char *complete_app(char *line, char *word, int pos, int state)
+static int handle_show_application(int fd, int argc, char *argv[])
{
- struct ast_app *tmp;
- char *ret;
- int which = 0;
+ struct ast_app *a;
+ char buf[2048];
+ int app, no_registered_app = 1;
+
+ if (argc < 3) return RESULT_SHOWUSAGE;
+
+ /* try to lock applications list ... */
if (ast_pthread_mutex_lock(&applock)) {
ast_log(LOG_ERROR, "Unable to lock application list\n");
- return NULL;
+ return -1;
}
- tmp = apps;
- while(tmp) {
- if (!strncasecmp(word, tmp->name, strlen(word))) {
- if (++which > state)
- break;
+
+ /* ... go through all applications ... */
+ a = apps;
+ while (a) {
+ /* ... compare this application name with all arguments given
+ * to 'show application' command ... */
+ for (app = 2; app < argc; app++) {
+ if (!strcasecmp(a->name, argv[app])) {
+ no_registered_app = 0;
+
+ /* ... one of our applications, show info ...*/
+ snprintf(buf, sizeof(buf),
+ "\n -= Info about application '%s' =- \n\n"
+ "[Synopsis]:\n %s\n\n"
+ "[Description]:\n%s\n",
+ a->name,
+ a->synopsis ? a->synopsis : "Not available",
+ a->description ? a-> description : "Not available");
+ ast_cli(fd, buf);
+ }
}
- tmp = tmp->next;
+ a = a->next;
}
- if (tmp)
- ret = tmp->name;
- else
- ret = NULL;
+
ast_pthread_mutex_unlock(&applock);
-
- return ret ? strdup(ret) : ret;
+
+ /* we found at least one app? no? */
+ if (no_registered_app) {
+ ast_cli(fd, "Your application(s) is (are) not registered\n");
+ return RESULT_FAILURE;
+ }
+
+ return RESULT_SUCCESS;
}
-static char *complete_context(char *line, char *word, int pos, int state)
+static int handle_show_switches(int fd, int argc, char *argv[])
{
- struct ast_context *tmp;
- char *ret;
- int which = 0;
- if (ast_pthread_mutex_lock(&conlock)) {
- ast_log(LOG_ERROR, "Unable to lock context list\n");
- return NULL;
+ struct ast_switch *sw;
+ if (!switches) {
+ ast_cli(fd, "There are no registered alternative switches\n");
+ return RESULT_SUCCESS;
}
- tmp = contexts;
- while(tmp) {
- if (!strncasecmp(word, tmp->name, strlen(word))) {
- if (++which > state)
- break;
- }
- tmp = tmp->next;
+ /* ... we have applications ... */
+ ast_cli(fd, "\n -= Registered Asterisk Alternative Switches =-\n");
+ if (ast_pthread_mutex_lock(&switchlock)) {
+ ast_log(LOG_ERROR, "Unable to lock switches\n");
+ return -1;
}
- if (tmp)
- ret = tmp->name;
- else
- ret = NULL;
- ast_pthread_mutex_unlock(&conlock);
-
- return ret ? strdup(ret) : ret;
+ sw = switches;
+ while (sw) {
+ ast_cli(fd, "%s: %s\n", sw->name, sw->description);
+ sw = sw->next;
+ }
+ ast_pthread_mutex_unlock(&switchlock);
+ return RESULT_SUCCESS;
}
-static int handle_show_application(int fd, int argc, char *argv[])
+/*
+ * 'show applications' CLI command implementation functions ...
+ */
+static int handle_show_applications(int fd, int argc, char *argv[])
{
- struct ast_app *tmp;
- char buf[2048];
- if (argc != 3)
- return RESULT_SHOWUSAGE;
+ struct ast_app *a;
+
+ /* try to lock applications list ... */
if (ast_pthread_mutex_lock(&applock)) {
ast_log(LOG_ERROR, "Unable to lock application list\n");
return -1;
}
- tmp = apps;
- while(tmp) {
- if (!strcasecmp(tmp->name, argv[2])) {
- snprintf(buf, sizeof(buf), "\n -= About Application '%s' =- \n\n"
- "[Synopsis]:\n %s\n\n"
- "[Description:]\n%s\n\n", tmp->name, tmp->synopsis ?
- tmp->synopsis : "Not available", tmp->description ?
- tmp->description : "Not available\n");
- break;
- }
- tmp = tmp->next;
+
+ /* ... go to first application ... */
+ a = apps;
+
+ /* ... have we got at least one application (first)? no? */
+ if (!a) {
+ ast_cli(fd, "There is no registered applications\n");
+ ast_pthread_mutex_unlock(&applock);
+ return -1;
+ }
+
+ /* ... we have applications ... */
+ ast_cli(fd, "\n -= Registered Asterisk Applications =-\n");
+
+ /* ... go through all applications ... */
+ while (a) {
+ /* ... show informations about applications ... */
+ ast_cli(fd," %15s: %s\n",
+ a->name,
+ a->synopsis ? a->synopsis : "<Synopsis not available>");
+ a = a->next;
}
+
+ /* ... unlock and return */
ast_pthread_mutex_unlock(&applock);
- if (!tmp)
- snprintf(buf, sizeof(buf), "No such application '%s' is registered.\n", argv[2]);
- ast_cli(fd, buf);
+
return RESULT_SUCCESS;
}
-static int handle_dialplan(int fd, int argc, char *argv[])
+/*
+ * 'show dialplan' CLI command implementation functions ...
+ */
+static char *complete_show_dialplan_context(char *line, char *word, int pos,
+ int state)
{
- struct ast_context *con;
- struct ast_exten *eroot, *e;
- struct ast_include *inc;
- char tmp[512];
- char cpy[512];
- char tmp2[512];
- char *context;
- char *exten;
- int spaces;
-
- if ((argc < 2) || (argc > 3))
- return RESULT_SHOWUSAGE;
-
- if (argc > 2) {
- strncpy(cpy, argv[2], sizeof(cpy));
- if ((context = strchr(cpy, '@'))) {
- *context = '\0';
- context++;
- exten = cpy;
- } else {
- context = cpy;
- exten = NULL;
+ struct ast_context *c;
+ int which = 0;
+
+ /* we are do completion of [exten@]context on second postion only */
+ if (pos != 2) return NULL;
+
+ /* try to lock contexts list ... */
+ if (ast_lock_contexts()) {
+ ast_log(LOG_ERROR, "Unable to lock context list\n");
+ return NULL;
+ }
+
+ /* ... walk through all contexts ... */
+ c = ast_walk_contexts(NULL);
+ while(c) {
+ /* ... word matches context name? yes? ... */
+ if (!strncasecmp(word, ast_get_context_name(c), strlen(word))) {
+ /* ... for serve? ... */
+ if (++which > state) {
+ /* ... yes, serve this context name ... */
+ char *ret = strdup(ast_get_context_name(c));
+ ast_unlock_contexts();
+ return ret;
+ }
}
- } else {
- context = NULL;
- exten = NULL;
+ c = ast_walk_contexts(c);
}
- ast_pthread_mutex_lock(&conlock);
- con = contexts;
- while(con) {
- if (!context || (!strcasecmp(context, con->name))) {
- ast_cli(fd, "\n [ Context '%s' created by '%s']\n", con->name, con->registrar);
- eroot = con->root;
- while(eroot) {
- if (!exten || (!strcasecmp(exten, eroot->exten))) {
- memset(tmp, ' ', sizeof(tmp));
- snprintf(tmp, sizeof(tmp), " '%s' => ", eroot->exten);
- spaces = strlen(tmp);
- tmp[spaces] = ' ';
- if (spaces < 19)
- spaces = 19;
- snprintf(tmp2, sizeof(tmp2), "%d. %s(%s)", eroot->priority, eroot->app, (char *)eroot->data);
- snprintf(tmp + spaces, sizeof(tmp) - spaces, "%-45s [%s]\n",
- tmp2, eroot->registrar);
- ast_cli(fd, tmp);
- memset(tmp, ' ', spaces);
- e = eroot->peer;
- while(e) {
- snprintf(tmp2, sizeof(tmp2), "%d. %s(%s)", e->priority, e->app, (char *)e->data);
- snprintf(tmp + spaces, sizeof(tmp) - spaces, "%-45s [%s]\n",
- tmp2, e->registrar);
- ast_cli(fd, tmp);
- e = e->peer;
+
+ /* ... unlock and return */
+ ast_unlock_contexts();
+ return NULL;
+}
+
+static int handle_show_dialplan(int fd, int argc, char *argv[])
+{
+ struct ast_context *c;
+ char *exten = NULL, *context = NULL;
+ int context_existence = 0, extension_existence = 0;
+
+ if (argc != 3 && argc != 2) return -1;
+
+ /* we obtain [exten@]context? if yes, split them ... */
+ if (argc == 3) {
+ char *splitter = argv[2];
+ /* is there a '@' character? */
+ if (strchr(argv[2], '@')) {
+ /* yes, split into exten & context ... */
+ exten = strsep(&splitter, "@");
+ context = splitter;
+
+ /* check for length and change to NULL if !strlen() */
+ if (!strlen(exten)) exten = NULL;
+ if (!strlen(context)) context = NULL;
+ } else
+ {
+ /* no '@' char, only context given */
+ context = argv[2];
+ if (!strlen(context)) context = NULL;
+ }
+ }
+
+ /* try to lock contexts */
+ if (ast_lock_contexts()) {
+ ast_cli(LOG_WARNING, "Failed to lock contexts list\n");
+ return RESULT_FAILURE;
+ }
+
+ /* walk all contexts ... */
+ c = ast_walk_contexts(NULL);
+ while (c) {
+ /* show this context? */
+ if (!context ||
+ !strcmp(ast_get_context_name(c), context)) {
+ context_existence = 1;
+
+ /* try to lock context before walking in ... */
+ if (!ast_lock_context(c)) {
+ struct ast_exten *e;
+ struct ast_include *i;
+ struct ast_ignorepat *ip;
+ struct ast_sw *sw;
+ char buf[256], buf2[256];
+ int context_info_printed = 0;
+
+ /* are we looking for exten too? if yes, we print context
+ * if we our extension only
+ */
+ if (!exten) {
+ ast_cli(fd, "[ Context '%s' created by '%s' ]\n",
+ ast_get_context_name(c), ast_get_context_registrar(c));
+ context_info_printed = 1;
+ }
+
+ /* walk extensions ... */
+ e = ast_walk_context_extensions(c, NULL);
+ while (e) {
+ struct ast_exten *p;
+
+ /* looking for extension? is this our extension? */
+ if (exten &&
+ strcmp(ast_get_extension_name(e), exten))
+ {
+ /* we are looking for extension and it's not our
+ * extension, so skip to next extension */
+ e = ast_walk_context_extensions(c, e);
+ continue;
+ }
+
+ extension_existence = 1;
+
+ /* may we print context info? */
+ if (!context_info_printed) {
+ ast_cli(fd, "[ Context '%s' created by '%s' ]\n",
+ ast_get_context_name(c),
+ ast_get_context_registrar(c));
+ context_info_printed = 1;
}
+
+ /* write extension name and first peer */
+ bzero(buf, sizeof(buf));
+ snprintf(buf, sizeof(buf), "'%s' =>",
+ ast_get_extension_name(e));
+
+ snprintf(buf2, sizeof(buf2),
+ "%d. %s(%s)",
+ ast_get_extension_priority(e),
+ ast_get_extension_app(e),
+ (char *)ast_get_extension_app_data(e));
+
+ ast_cli(fd, " %-17s %-45s [%s]\n", buf, buf2,
+ ast_get_extension_registrar(e));
+
+ /* walk next extension peers */
+ p = ast_walk_extension_priorities(e, e);
+ while (p) {
+ bzero((void *)buf2, sizeof(buf2));
+
+ snprintf(buf2, sizeof(buf2),
+ "%d. %s(%s)",
+ ast_get_extension_priority(p),
+ ast_get_extension_app(p),
+ (char *)ast_get_extension_app_data(p));
+
+ ast_cli(fd," %-17s %-45s [%s]\n",
+ "", buf2,
+ ast_get_extension_registrar(p));
+
+ p = ast_walk_extension_priorities(e, p);
+ }
+ e = ast_walk_context_extensions(c, e);
}
- eroot = eroot->next;
- }
- inc = con->includes;
- while(inc) {
- snprintf(tmp, sizeof(tmp), " Include => '%s'", inc->name);
- ast_cli(fd, "%s [%s]\n", tmp, inc->registrar);
- inc = inc->next;
+
+ /* include & ignorepat we all printing if we are not
+ * looking for exact extension
+ */
+ if (!exten) {
+ if (ast_walk_context_extensions(c, NULL))
+ ast_cli(fd, "\n");
+
+ /* walk included and write info ... */
+ i = ast_walk_context_includes(c, NULL);
+ while (i) {
+ bzero(buf, sizeof(buf));
+ snprintf(buf, sizeof(buf), "'%s'",
+ ast_get_include_name(i));
+ ast_cli(fd, " Include => %-45s [%s]\n",
+ buf, ast_get_include_registrar(i));
+ i = ast_walk_context_includes(c, i);
+ }
+
+ /* walk ignore patterns and write info ... */
+ ip = ast_walk_context_ignorepats(c, NULL);
+ while (ip) {
+ bzero(buf, sizeof(buf));
+ snprintf(buf, sizeof(buf), "'%s'",
+ ast_get_ignorepat_name(ip));
+ ast_cli(fd, " Ignore pattern => %-45s [%s]\n",
+ buf, ast_get_ignorepat_registrar(ip));
+ ip = ast_walk_context_ignorepats(c, ip);
+ }
+ sw = ast_walk_context_switches(c, NULL);
+ while(sw) {
+ bzero(buf, sizeof(buf));
+ snprintf(buf, sizeof(buf), "'%s/%s'",
+ ast_get_switch_name(sw),
+ ast_get_switch_data(sw));
+ ast_cli(fd, " Alt. Switch => %-45s [%s]\n",
+ buf, ast_get_switch_registrar(sw));
+ sw = ast_walk_context_switches(c, sw);
+ }
+ }
+
+ ast_unlock_context(c);
+
+ /* if we print something in context, make an empty line */
+ if (context_info_printed) ast_cli(fd, "\n");
}
}
- con = con->next;
+ c = ast_walk_contexts(c);
}
- ast_pthread_mutex_unlock(&conlock);
+ ast_unlock_contexts();
+
+ /* check for input failure and throw some error messages */
+ if (context && !context_existence) {
+ ast_cli(fd, "There is no existence of '%s' context\n",
+ context);
+ return RESULT_FAILURE;
+ }
+
+ if (exten && !extension_existence) {
+ if (context)
+ ast_cli(fd, "There is no existence of %s@%s extension\n",
+ exten, context);
+ else
+ ast_cli(fd,
+ "There is no existence of '%s' extension in all contexts\n",
+ exten);
+ return RESULT_FAILURE;
+ }
+
+ /* everything ok */
return RESULT_SUCCESS;
}
-static struct ast_cli_entry showapps = { { "show", "applications", NULL },
- handle_show_applications, "Shows registered applications", apps_help };
-
-static struct ast_cli_entry showdialplan = { { "show", "dialplan", NULL },
- handle_dialplan, "Displays all or part of dialplan", dialplan_help, complete_context };
+/*
+ * CLI entries for upper commands ...
+ */
+static struct ast_cli_entry show_applications_cli =
+ { { "show", "applications", NULL },
+ handle_show_applications, "Shows registered applications",
+ show_applications_help };
+
+static struct ast_cli_entry show_application_cli =
+ { { "show", "application", NULL },
+ handle_show_application, "Describe a specific application",
+ show_application_help, complete_show_application };
+
+static struct ast_cli_entry show_dialplan_cli =
+ { { "show", "dialplan", NULL },
+ handle_show_dialplan, "Show dialplan",
+ show_dialplan_help, complete_show_dialplan_context };
+
+static struct ast_cli_entry show_switches_cli =
+ { { "show", "switches", NULL },
+ handle_show_switches, "Show alternative switches",
+ show_switches_help, NULL };
-static struct ast_cli_entry showapp = { { "show", "application", NULL },
- handle_show_application, "Describe a specific application", app_help, complete_app };
-
int ast_unregister_application(char *app) {
struct ast_app *tmp, *tmpl = NULL;
if (ast_pthread_mutex_lock(&applock)) {
@@ -1095,12 +1744,14 @@ struct ast_context *ast_context_create(char *name, char *registrar)
}
tmp = malloc(sizeof(struct ast_context));
if (tmp) {
+ memset(tmp, 0, sizeof(struct ast_context));
pthread_mutex_init(&tmp->lock, NULL);
strncpy(tmp->name, name, sizeof(tmp->name));
tmp->root = NULL;
tmp->registrar = registrar;
tmp->next = contexts;
tmp->includes = NULL;
+ tmp->ignorepats = NULL;
contexts = tmp;
if (option_debug)
ast_log(LOG_DEBUG, "Registered context '%s'\n", tmp->name);
@@ -1113,48 +1764,400 @@ struct ast_context *ast_context_create(char *name, char *registrar)
return tmp;
}
-int ast_context_add_include2(struct ast_context *con, char *value, char *registrar)
+/*
+ * errno values
+ * EBUSY - can't lock
+ * ENODATA - no existence of context
+ */
+int ast_context_add_include(char *context, char *include, char *registrar)
+{
+ struct ast_context *c;
+
+ if (ast_lock_contexts()) {
+ errno = EBUSY;
+ return -1;
+ }
+
+ /* walk contexts ... */
+ c = ast_walk_contexts(NULL);
+ while (c) {
+ /* ... search for the right one ... */
+ if (!strcmp(ast_get_context_name(c), context)) {
+ int ret = ast_context_add_include2(c, include, registrar);
+ /* ... unlock contexts list and return */
+ ast_unlock_contexts();
+ return ret;
+ }
+ c = ast_walk_contexts(c);
+ }
+
+ /* we can't find the right context */
+ ast_unlock_contexts();
+ errno = ENODATA;
+ return -1;
+}
+
+/*
+ * errno values
+ * ENOMEM - out of memory
+ * EBUSY - can't lock
+ * EEXIST - already included
+ * EINVAL - there is no existence of context for inclusion
+ */
+int ast_context_add_include2(struct ast_context *con, char *value,
+ char *registrar)
+{
+ struct ast_include *new_include;
+ struct ast_include *i, *il = NULL; /* include, include_last */
+
+ /* allocate new include structure ... */
+ if (!(new_include = malloc(sizeof(struct ast_include)))) {
+ ast_log(LOG_WARNING, "Out of memory\n");
+ errno = ENOMEM;
+ return -1;
+ }
+
+ /* ... fill in this structure ... */
+ strncpy(new_include->name, value, sizeof(new_include->name));
+ new_include->next = NULL;
+ new_include->registrar = registrar;
+
+ /* ... try to lock this context ... */
+ if (ast_pthread_mutex_lock(&con->lock)) {
+ free(new_include);
+ errno = EBUSY;
+ return -1;
+ }
+
+ /* ... go to last include and check if context is already included too... */
+ i = con->includes;
+ while (i) {
+ if (!strcasecmp(i->name, new_include->name)) {
+ free(new_include);
+ ast_pthread_mutex_unlock(&con->lock);
+ errno = EEXIST;
+ return -1;
+ }
+ il = i;
+ i = i->next;
+ }
+
+ /* ... include new context into context list, unlock, return */
+ if (il)
+ il->next = new_include;
+ else
+ con->includes = new_include;
+ if (option_verbose > 2)
+ ast_verbose(VERBOSE_PREFIX_3 "Including context '%s' in context '%s'\n", new_include->name, ast_get_context_name(con));
+ ast_pthread_mutex_unlock(&con->lock);
+
+ return 0;
+}
+
+/*
+ * errno values
+ * EBUSY - can't lock
+ * ENODATA - no existence of context
+ */
+int ast_context_add_switch(char *context, char *sw, char *data, char *registrar)
+{
+ struct ast_context *c;
+
+ if (ast_lock_contexts()) {
+ errno = EBUSY;
+ return -1;
+ }
+
+ /* walk contexts ... */
+ c = ast_walk_contexts(NULL);
+ while (c) {
+ /* ... search for the right one ... */
+ if (!strcmp(ast_get_context_name(c), context)) {
+ int ret = ast_context_add_switch2(c, sw, data, registrar);
+ /* ... unlock contexts list and return */
+ ast_unlock_contexts();
+ return ret;
+ }
+ c = ast_walk_contexts(c);
+ }
+
+ /* we can't find the right context */
+ ast_unlock_contexts();
+ errno = ENODATA;
+ return -1;
+}
+
+/*
+ * errno values
+ * ENOMEM - out of memory
+ * EBUSY - can't lock
+ * EEXIST - already included
+ * EINVAL - there is no existence of context for inclusion
+ */
+int ast_context_add_switch2(struct ast_context *con, char *value,
+ char *data, char *registrar)
+{
+ struct ast_sw *new_sw;
+ struct ast_sw *i, *il = NULL; /* sw, sw_last */
+
+ /* allocate new sw structure ... */
+ if (!(new_sw = malloc(sizeof(struct ast_sw)))) {
+ ast_log(LOG_WARNING, "Out of memory\n");
+ errno = ENOMEM;
+ return -1;
+ }
+
+ /* ... fill in this structure ... */
+ strncpy(new_sw->name, value, sizeof(new_sw->name));
+ if (data)
+ strncpy(new_sw->data, data, sizeof(new_sw->data));
+ else
+ strncpy(new_sw->data, "", sizeof(new_sw->data));
+ new_sw->next = NULL;
+ new_sw->registrar = registrar;
+
+ /* ... try to lock this context ... */
+ if (ast_pthread_mutex_lock(&con->lock)) {
+ free(new_sw);
+ errno = EBUSY;
+ return -1;
+ }
+
+ /* ... go to last sw and check if context is already swd too... */
+ i = con->alts;
+ while (i) {
+ if (!strcasecmp(i->name, new_sw->name)) {
+ free(new_sw);
+ ast_pthread_mutex_unlock(&con->lock);
+ errno = EEXIST;
+ return -1;
+ }
+ il = i;
+ i = i->next;
+ }
+
+ /* ... sw new context into context list, unlock, return */
+ if (il)
+ il->next = new_sw;
+ else
+ con->alts = new_sw;
+ if (option_verbose > 2)
+ ast_verbose(VERBOSE_PREFIX_3 "Including switch '%s/%s' in context '%s'\n", new_sw->name, new_sw->data, ast_get_context_name(con));
+ ast_pthread_mutex_unlock(&con->lock);
+
+ return 0;
+}
+
+/*
+ * EBUSY - can't lock
+ * ENODATA - there is not context existence
+ */
+int ast_context_remove_ignorepat(char *context, char *ignorepat, char *registrar)
+{
+ struct ast_context *c;
+
+ if (ast_lock_contexts()) {
+ errno = EBUSY;
+ return -1;
+ }
+
+ c = ast_walk_contexts(NULL);
+ while (c) {
+ if (!strcmp(ast_get_context_name(c), context)) {
+ int ret = ast_context_remove_ignorepat2(c, ignorepat, registrar);
+ ast_unlock_contexts();
+ return ret;
+ }
+ c = ast_walk_contexts(c);
+ }
+
+ ast_unlock_contexts();
+ errno = ENODATA;
+ return -1;
+}
+
+int ast_context_remove_ignorepat2(struct ast_context *con, char *ignorepat, char *registrar)
+{
+ struct ast_ignorepat *ip, *ipl = NULL;
+
+ if (ast_pthread_mutex_lock(&con->lock)) {
+ errno = EBUSY;
+ return -1;
+ }
+
+ ip = con->ignorepats;
+ while (ip) {
+ if (!strcmp(ip->pattern, ignorepat) &&
+ (registrar == ip->registrar || !registrar)) {
+ if (ipl) {
+ ipl->next = ip->next;
+ free(ip);
+ } else {
+ con->ignorepats = ip->next;
+ free(ip);
+ }
+ ast_pthread_mutex_unlock(&con->lock);
+ return 0;
+ }
+ ipl = ip; ip = ip->next;
+ }
+
+ ast_pthread_mutex_unlock(&con->lock);
+ errno = EINVAL;
+ return -1;
+}
+
+/*
+ * EBUSY - can't lock
+ * ENODATA - there is no existence of context
+ */
+int ast_context_add_ignorepat(char *con, char *value, char *registrar)
+{
+ struct ast_context *c;
+
+ if (ast_lock_contexts()) {
+ errno = EBUSY;
+ return -1;
+ }
+
+ c = ast_walk_contexts(NULL);
+ while (c) {
+ if (!strcmp(ast_get_context_name(c), con)) {
+ int ret = ast_context_add_ignorepat2(c, value, registrar);
+ ast_unlock_contexts();
+ return ret;
+ }
+ c = ast_walk_contexts(c);
+ }
+
+ ast_unlock_contexts();
+ errno = ENODATA;
+ return -1;
+}
+
+int ast_context_add_ignorepat2(struct ast_context *con, char *value, char *registrar)
{
- struct ast_include *inc, *incc, *incl = NULL;
- inc = malloc(sizeof(struct ast_include));
- if (!inc) {
+ struct ast_ignorepat *ignorepat, *ignorepatc, *ignorepatl = NULL;
+ ignorepat = malloc(sizeof(struct ast_ignorepat));
+ if (!ignorepat) {
ast_log(LOG_WARNING, "Out of memory\n");
+ errno = ENOMEM;
return -1;
}
- strncpy(inc->name, value, sizeof(inc->name));
- inc->next = NULL;
- inc->registrar = registrar;
+ strncpy(ignorepat->pattern, value, sizeof(ignorepat->pattern));
+ ignorepat->next = NULL;
+ ignorepat->registrar = registrar;
pthread_mutex_lock(&con->lock);
- incc = con->includes;
- while(incc) {
- incl = incc;
- if (!strcasecmp(incc->name, value)) {
+ ignorepatc = con->ignorepats;
+ while(ignorepatc) {
+ ignorepatl = ignorepatc;
+ if (!strcasecmp(ignorepatc->pattern, value)) {
/* Already there */
pthread_mutex_unlock(&con->lock);
- return 0;
+ errno = EEXIST;
+ return -1;
}
- incc = incc->next;
+ ignorepatc = ignorepatc->next;
}
- if (incl)
- incl->next = inc;
+ if (ignorepatl)
+ ignorepatl->next = ignorepat;
else
- con->includes = inc;
+ con->ignorepats = ignorepat;
pthread_mutex_unlock(&con->lock);
return 0;
}
+int ast_ignore_pattern(char *context, char *pattern)
+{
+ struct ast_context *con;
+ struct ast_ignorepat *pat;
+ con = ast_context_find(context);
+ if (con) {
+ pat = con->ignorepats;
+ while (pat) {
+ if (ast_extension_match(pat->pattern, pattern))
+ return 1;
+ pat = pat->next;
+ }
+ }
+ return 0;
+}
+
+/*
+ * EBUSY - can't lock
+ * ENODATA - no existence of context
+ *
+ */
+int ast_add_extension(char *context, int replace, char *extension, int priority, char *callerid,
+ char *application, void *data, void (*datad)(void *), char *registrar)
+{
+ struct ast_context *c;
+
+ if (ast_lock_contexts()) {
+ errno = EBUSY;
+ return -1;
+ }
+
+ c = ast_walk_contexts(NULL);
+ while (c) {
+ if (!strcmp(context, ast_get_context_name(c))) {
+ int ret = ast_add_extension2(c, replace, extension, priority, callerid,
+ application, data, datad, registrar);
+ ast_unlock_contexts();
+ return ret;
+ }
+ c = ast_walk_contexts(c);
+ }
+
+ ast_unlock_contexts();
+ errno = ENODATA;
+ return -1;
+}
+
+static void ext_strncpy(char *dst, char *src, int len)
+{
+ int count=0;
+ while(*src && (count < len - 1)) {
+ switch(*src) {
+ case ' ':
+ case '-':
+ /* Ignore */
+ break;
+ default:
+ *dst = *src;
+ dst++;
+ }
+ src++;
+ count++;
+ }
+ *dst = '\0';
+}
+
+/*
+ * EBUSY - can't lock
+ * EEXIST - extension with the same priority exist and no replace is set
+ *
+ */
int ast_add_extension2(struct ast_context *con,
- int replace, char *extension, int priority,
+ int replace, char *extension, int priority, char *callerid,
char *application, void *data, void (*datad)(void *),
char *registrar)
{
-#define LOG { if (option_debug) \
- ast_log(LOG_DEBUG, "Added extension '%s' priority %d to %s\n", tmp->exten, tmp->priority, con->name); \
- else if (option_verbose > 2) \
- ast_verbose( VERBOSE_PREFIX_3 "Added extension '%s' priority %d to %s\n", tmp->exten, tmp->priority, con->name); \
- }
+#define LOG do { if (option_debug) {\
+ if (tmp->matchcid) { \
+ ast_log(LOG_DEBUG, "Added extension '%s' priority %d (CID match '%s') to %s\n", tmp->exten, tmp->priority, tmp->cidmatch, con->name); \
+ } else { \
+ ast_log(LOG_DEBUG, "Added extension '%s' priority %d to %s\n", tmp->exten, tmp->priority, con->name); \
+ } \
+ } else if (option_verbose > 2) { \
+ if (tmp->matchcid) { \
+ ast_verbose( VERBOSE_PREFIX_3 "Added extension '%s' priority %d (CID match '%s')to %s\n", tmp->exten, tmp->priority, tmp->cidmatch, con->name); \
+ } else { \
+ ast_verbose( VERBOSE_PREFIX_3 "Added extension '%s' priority %d to %s\n", tmp->exten, tmp->priority, con->name); \
+ } \
+ } } while(0)
/*
* This is a fairly complex routine. Different extensions are kept
@@ -1167,8 +2170,15 @@ int ast_add_extension2(struct ast_context *con,
/* Be optimistic: Build the extension structure first */
tmp = malloc(sizeof(struct ast_exten));
if (tmp) {
- strncpy(tmp->exten, extension, sizeof(tmp->exten));
+ ext_strncpy(tmp->exten, extension, sizeof(tmp->exten));
tmp->priority = priority;
+ if (callerid) {
+ ext_strncpy(tmp->cidmatch, callerid, sizeof(tmp->cidmatch));
+ tmp->matchcid = 1;
+ } else {
+ strcpy(tmp->cidmatch, "");
+ tmp->matchcid = 0;
+ }
strncpy(tmp->app, application, sizeof(tmp->app));
tmp->data = data;
tmp->datad = datad;
@@ -1177,6 +2187,7 @@ int ast_add_extension2(struct ast_context *con,
tmp->next = NULL;
} else {
ast_log(LOG_WARNING, "Out of memory\n");
+ errno = ENOMEM;
return -1;
}
if (ast_pthread_mutex_lock(&con->lock)) {
@@ -1184,11 +2195,22 @@ int ast_add_extension2(struct ast_context *con,
/* And properly destroy the data */
datad(data);
ast_log(LOG_WARNING, "Failed to lock context '%s'\n", con->name);
+ errno = EBUSY;
return -1;
}
e = con->root;
while(e) {
res= strcasecmp(e->exten, extension);
+ if (!res) {
+ if (!e->matchcid && !tmp->matchcid)
+ res = 0;
+ else if (tmp->matchcid && !e->matchcid)
+ res = 1;
+ else if (e->matchcid && !tmp->matchcid)
+ res = -1;
+ else
+ res = strcasecmp(e->cidmatch, tmp->cidmatch);
+ }
if (res == 0) {
/* We have an exact match, now we find where we are
and be sure there's no duplicates */
@@ -1224,6 +2246,7 @@ int ast_add_extension2(struct ast_context *con,
tmp->datad(tmp->data);
free(tmp);
ast_pthread_mutex_unlock(&con->lock);
+ errno = EEXIST;
return -1;
}
} else if (e->priority > tmp->priority) {
@@ -1295,6 +2318,7 @@ void ast_context_destroy(struct ast_context *con, char *registrar)
{
struct ast_context *tmp, *tmpl=NULL;
struct ast_include *tmpi, *tmpil= NULL;
+ struct ast_sw *sw, *swl= NULL;
ast_pthread_mutex_lock(&conlock);
tmp = contexts;
while(tmp) {
@@ -1320,6 +2344,12 @@ void ast_context_destroy(struct ast_context *con, char *registrar)
free(tmpil);
tmpil = tmpi;
}
+ for (sw = tmp->alts; sw; ) {
+ swl = sw;
+ sw = sw->next;
+ free(swl);
+ swl = sw;
+ }
free(tmp);
if (!con) {
/* Might need to get another one -- restart */
@@ -1373,12 +2403,7 @@ static int pbx_builtin_congestion(struct ast_channel *chan, void *data)
static int pbx_builtin_answer(struct ast_channel *chan, void *data)
{
- if (chan->state != AST_STATE_RING) {
- if (option_debug)
- ast_log(LOG_DEBUG, "Ignoring answer request since line is not ringing\n");
- return 0;
- } else
- return ast_answer(chan);
+ return ast_answer(chan);
}
static int pbx_builtin_setlanguage(struct ast_channel *chan, void *data)
@@ -1511,9 +2536,10 @@ int load_pbx(void)
ast_verbose( "Asterisk PBX Core Initializing\n");
ast_verbose( "Registering builtin applications:\n");
}
- ast_cli_register(&showapps);
- ast_cli_register(&showapp);
- ast_cli_register(&showdialplan);
+ ast_cli_register(&show_applications_cli);
+ ast_cli_register(&show_application_cli);
+ ast_cli_register(&show_dialplan_cli);
+ ast_cli_register(&show_switches_cli);
for (x=0;x<sizeof(builtins) / sizeof(struct pbx_builtin); x++) {
if (option_verbose)
ast_verbose( VERBOSE_PREFIX_1 "[%s]\n", builtins[x].name);
@@ -1525,3 +2551,160 @@ int load_pbx(void)
return 0;
}
+/*
+ * Lock context list functions ...
+ */
+int ast_lock_contexts()
+{
+ return ast_pthread_mutex_lock(&conlock);
+}
+
+int ast_unlock_contexts()
+{
+ return ast_pthread_mutex_unlock(&conlock);
+}
+
+/*
+ * Lock context ...
+ */
+int ast_lock_context(struct ast_context *con)
+{
+ return ast_pthread_mutex_lock(&con->lock);
+}
+
+int ast_unlock_context(struct ast_context *con)
+{
+ return ast_pthread_mutex_unlock(&con->lock);
+}
+
+/*
+ * Name functions ...
+ */
+char *ast_get_context_name(struct ast_context *con)
+{
+ return con ? con->name : NULL;
+}
+
+char *ast_get_extension_name(struct ast_exten *exten)
+{
+ return exten ? exten->exten : NULL;
+}
+
+char *ast_get_include_name(struct ast_include *inc)
+{
+ return inc ? inc->name : NULL;
+}
+
+char *ast_get_ignorepat_name(struct ast_ignorepat *ip)
+{
+ return ip ? ip->pattern : NULL;
+}
+
+int ast_get_extension_priority(struct ast_exten *exten)
+{
+ return exten ? exten->priority : -1;
+}
+
+/*
+ * Registrar info functions ...
+ */
+char *ast_get_context_registrar(struct ast_context *c)
+{
+ return c ? c->registrar : NULL;
+}
+
+char *ast_get_extension_registrar(struct ast_exten *e)
+{
+ return e ? e->registrar : NULL;
+}
+
+char *ast_get_include_registrar(struct ast_include *i)
+{
+ return i ? i->registrar : NULL;
+}
+
+char *ast_get_ignorepat_registrar(struct ast_ignorepat *ip)
+{
+ return ip ? ip->registrar : NULL;
+}
+
+char *ast_get_extension_app(struct ast_exten *e)
+{
+ return e ? e->app : NULL;
+}
+
+void *ast_get_extension_app_data(struct ast_exten *e)
+{
+ return e ? e->data : NULL;
+}
+
+char *ast_get_switch_name(struct ast_sw *sw)
+{
+ return sw ? sw->name : NULL;
+}
+
+char *ast_get_switch_data(struct ast_sw *sw)
+{
+ return sw ? sw->data : NULL;
+}
+
+char *ast_get_switch_registrar(struct ast_sw *sw)
+{
+ return sw ? sw->registrar : NULL;
+}
+
+/*
+ * Walking functions ...
+ */
+struct ast_context *ast_walk_contexts(struct ast_context *con)
+{
+ if (!con)
+ return contexts;
+ else
+ return con->next;
+}
+
+struct ast_exten *ast_walk_context_extensions(struct ast_context *con,
+ struct ast_exten *exten)
+{
+ if (!exten)
+ return con ? con->root : NULL;
+ else
+ return exten->next;
+}
+
+struct ast_sw *ast_walk_context_switches(struct ast_context *con,
+ struct ast_sw *sw)
+{
+ if (!sw)
+ return con ? con->alts : NULL;
+ else
+ return sw->next;
+}
+
+struct ast_exten *ast_walk_extension_priorities(struct ast_exten *exten,
+ struct ast_exten *priority)
+{
+ if (!priority)
+ return exten;
+ else
+ return priority->peer;
+}
+
+struct ast_include *ast_walk_context_includes(struct ast_context *con,
+ struct ast_include *inc)
+{
+ if (!inc)
+ return con ? con->includes : NULL;
+ else
+ return inc->next;
+}
+
+struct ast_ignorepat *ast_walk_context_ignorepats(struct ast_context *con,
+ struct ast_ignorepat *ip)
+{
+ if (!ip)
+ return con ? con->ignorepats : NULL;
+ else
+ return ip->next;
+}