|
|
@ -12,6 +12,7 @@
|
|
|
|
*/
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
#include <pthread.h>
|
|
|
|
#include <pthread.h>
|
|
|
|
|
|
|
|
#include <asterisk/cli.h>
|
|
|
|
#include <asterisk/pbx.h>
|
|
|
|
#include <asterisk/pbx.h>
|
|
|
|
#include <asterisk/channel.h>
|
|
|
|
#include <asterisk/channel.h>
|
|
|
|
#include <asterisk/options.h>
|
|
|
|
#include <asterisk/options.h>
|
|
|
@ -55,14 +56,17 @@ struct ast_exten {
|
|
|
|
void *data;
|
|
|
|
void *data;
|
|
|
|
/* Data destructor */
|
|
|
|
/* Data destructor */
|
|
|
|
void (*datad)(void *);
|
|
|
|
void (*datad)(void *);
|
|
|
|
/* Next highest priority with our extension */
|
|
|
|
/* Next higher priority with our extension */
|
|
|
|
struct ast_exten *peer;
|
|
|
|
struct ast_exten *peer;
|
|
|
|
|
|
|
|
/* Registrar */
|
|
|
|
|
|
|
|
char *registrar;
|
|
|
|
/* Extension with a greater ID */
|
|
|
|
/* Extension with a greater ID */
|
|
|
|
struct ast_exten *next;
|
|
|
|
struct ast_exten *next;
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
struct ast_include {
|
|
|
|
struct ast_include {
|
|
|
|
char name[AST_MAX_EXTENSION];
|
|
|
|
char name[AST_MAX_EXTENSION];
|
|
|
|
|
|
|
|
char *registrar;
|
|
|
|
struct ast_include *next;
|
|
|
|
struct ast_include *next;
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
@ -78,6 +82,8 @@ struct ast_context {
|
|
|
|
struct ast_context *next;
|
|
|
|
struct ast_context *next;
|
|
|
|
/* Include other contexts */
|
|
|
|
/* Include other contexts */
|
|
|
|
struct ast_include *includes;
|
|
|
|
struct ast_include *includes;
|
|
|
|
|
|
|
|
/* Registrar */
|
|
|
|
|
|
|
|
char *registrar;
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@ -86,6 +92,8 @@ struct ast_app {
|
|
|
|
/* Name of the application */
|
|
|
|
/* Name of the application */
|
|
|
|
char name[AST_MAX_APP];
|
|
|
|
char name[AST_MAX_APP];
|
|
|
|
int (*execute)(struct ast_channel *chan, void *data);
|
|
|
|
int (*execute)(struct ast_channel *chan, void *data);
|
|
|
|
|
|
|
|
char *synopsis;
|
|
|
|
|
|
|
|
char *description;
|
|
|
|
struct ast_app *next;
|
|
|
|
struct ast_app *next;
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
@ -99,24 +107,82 @@ static int pbx_builtin_dtimeout(struct ast_channel *, void *);
|
|
|
|
static int pbx_builtin_rtimeout(struct ast_channel *, void *);
|
|
|
|
static int pbx_builtin_rtimeout(struct ast_channel *, void *);
|
|
|
|
static int pbx_builtin_wait(struct ast_channel *, void *);
|
|
|
|
static int pbx_builtin_wait(struct ast_channel *, void *);
|
|
|
|
static int pbx_builtin_setlanguage(struct ast_channel *, void *);
|
|
|
|
static int pbx_builtin_setlanguage(struct ast_channel *, void *);
|
|
|
|
|
|
|
|
static int pbx_builtin_ringing(struct ast_channel *, void *);
|
|
|
|
|
|
|
|
static int pbx_builtin_congestion(struct ast_channel *, void *);
|
|
|
|
|
|
|
|
static int pbx_builtin_busy(struct ast_channel *, void *);
|
|
|
|
|
|
|
|
|
|
|
|
static struct pbx_builtin {
|
|
|
|
static struct pbx_builtin {
|
|
|
|
char name[AST_MAX_APP];
|
|
|
|
char name[AST_MAX_APP];
|
|
|
|
int (*execute)(struct ast_channel *chan, void *data);
|
|
|
|
int (*execute)(struct ast_channel *chan, void *data);
|
|
|
|
|
|
|
|
char *synopsis;
|
|
|
|
|
|
|
|
char *description;
|
|
|
|
} builtins[] =
|
|
|
|
} builtins[] =
|
|
|
|
{
|
|
|
|
{
|
|
|
|
/* These applications are built into the PBX core and do not
|
|
|
|
/* These applications are built into the PBX core and do not
|
|
|
|
need separate modules */
|
|
|
|
need separate modules */
|
|
|
|
{ "Answer", pbx_builtin_answer },
|
|
|
|
{ "Answer", pbx_builtin_answer,
|
|
|
|
{ "Goto", pbx_builtin_goto },
|
|
|
|
"Answer a channel if ringing",
|
|
|
|
{ "Hangup", pbx_builtin_hangup },
|
|
|
|
" Answer(): If the channel is ringing, answer it, otherwise do nothing. Returns 0 unless it\n"
|
|
|
|
{ "DigitTimeout", pbx_builtin_dtimeout },
|
|
|
|
" tries to answer the channel and fails.\n" },
|
|
|
|
{ "ResponseTimeout", pbx_builtin_rtimeout },
|
|
|
|
{ "Goto", pbx_builtin_goto,
|
|
|
|
{ "BackGround", pbx_builtin_background },
|
|
|
|
"Goto a particular priority, extension, or context",
|
|
|
|
{ "Wait", pbx_builtin_wait },
|
|
|
|
" Goto([[context|]extension|]priority): Set the priority to the specified value, optionally setting\n"
|
|
|
|
{ "StripMSD", pbx_builtin_stripmsd },
|
|
|
|
" the extension and optionally the context as well. The extension BYEXTENSION is special in that it\n"
|
|
|
|
{ "Prefix", pbx_builtin_prefix },
|
|
|
|
" uses the current extension, thus permitting you to go to a different context, without specifying a\n"
|
|
|
|
{ "SetLanguage", pbx_builtin_setlanguage },
|
|
|
|
" specific extension. Always returns 0, even if the given context, extension, or priority is invalid.\n" },
|
|
|
|
|
|
|
|
{ "Hangup", pbx_builtin_hangup,
|
|
|
|
|
|
|
|
"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" },
|
|
|
|
|
|
|
|
{ "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" },
|
|
|
|
|
|
|
|
{ "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" },
|
|
|
|
|
|
|
|
{ "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." },
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
/* Lock for the application list */
|
|
|
|
/* Lock for the application list */
|
|
|
@ -176,7 +242,7 @@ static int pbx_exec(struct ast_channel *c, /* Channel */
|
|
|
|
static struct ast_app *pbx_findapp(char *app)
|
|
|
|
static struct ast_app *pbx_findapp(char *app)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
struct ast_app *tmp;
|
|
|
|
struct ast_app *tmp;
|
|
|
|
if (pthread_mutex_lock(&applock)) {
|
|
|
|
if (ast_pthread_mutex_lock(&applock)) {
|
|
|
|
ast_log(LOG_WARNING, "Unable to obtain application lock\n");
|
|
|
|
ast_log(LOG_WARNING, "Unable to obtain application lock\n");
|
|
|
|
return NULL;
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -186,7 +252,7 @@ static struct ast_app *pbx_findapp(char *app)
|
|
|
|
break;
|
|
|
|
break;
|
|
|
|
tmp = tmp->next;
|
|
|
|
tmp = tmp->next;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
pthread_mutex_unlock(&applock);
|
|
|
|
ast_pthread_mutex_unlock(&applock);
|
|
|
|
return tmp;
|
|
|
|
return tmp;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
@ -195,7 +261,7 @@ static void pbx_destroy(struct ast_pbx *p)
|
|
|
|
free(p);
|
|
|
|
free(p);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static inline int extension_match(char *pattern, char *data)
|
|
|
|
int ast_extension_match(char *pattern, char *data)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
int match;
|
|
|
|
int match;
|
|
|
|
/* If they're the same return */
|
|
|
|
/* If they're the same return */
|
|
|
@ -270,14 +336,17 @@ static int extension_close(char *pattern, char *data)
|
|
|
|
struct ast_context *ast_context_find(char *name)
|
|
|
|
struct ast_context *ast_context_find(char *name)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
struct ast_context *tmp;
|
|
|
|
struct ast_context *tmp;
|
|
|
|
pthread_mutex_lock(&conlock);
|
|
|
|
ast_pthread_mutex_lock(&conlock);
|
|
|
|
|
|
|
|
if (name) {
|
|
|
|
tmp = contexts;
|
|
|
|
tmp = contexts;
|
|
|
|
while(tmp) {
|
|
|
|
while(tmp) {
|
|
|
|
if (!strcasecmp(name, tmp->name))
|
|
|
|
if (!strcasecmp(name, tmp->name))
|
|
|
|
break;
|
|
|
|
break;
|
|
|
|
tmp = tmp->next;
|
|
|
|
tmp = tmp->next;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
pthread_mutex_unlock(&conlock);
|
|
|
|
} else
|
|
|
|
|
|
|
|
tmp = contexts;
|
|
|
|
|
|
|
|
ast_pthread_mutex_unlock(&conlock);
|
|
|
|
return tmp;
|
|
|
|
return tmp;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
@ -314,7 +383,7 @@ static struct ast_exten *pbx_find_extension(char *context, char *exten, int prio
|
|
|
|
eroot = tmp->root;
|
|
|
|
eroot = tmp->root;
|
|
|
|
while(eroot) {
|
|
|
|
while(eroot) {
|
|
|
|
/* Match extension */
|
|
|
|
/* Match extension */
|
|
|
|
if (extension_match(eroot->exten, exten) ||
|
|
|
|
if (ast_extension_match(eroot->exten, exten) ||
|
|
|
|
((action == HELPER_CANMATCH) && (extension_close(eroot->exten, exten)))) {
|
|
|
|
((action == HELPER_CANMATCH) && (extension_close(eroot->exten, exten)))) {
|
|
|
|
e = eroot;
|
|
|
|
e = eroot;
|
|
|
|
if (*status < STATUS_NO_PRIORITY)
|
|
|
|
if (*status < STATUS_NO_PRIORITY)
|
|
|
@ -355,9 +424,7 @@ static int pbx_extension_helper(struct ast_channel *c, char *context, char *exte
|
|
|
|
int status = 0;
|
|
|
|
int status = 0;
|
|
|
|
char *incstack[AST_PBX_MAX_STACK];
|
|
|
|
char *incstack[AST_PBX_MAX_STACK];
|
|
|
|
int stacklen = 0;
|
|
|
|
int stacklen = 0;
|
|
|
|
|
|
|
|
if (ast_pthread_mutex_lock(&conlock)) {
|
|
|
|
|
|
|
|
|
|
|
|
if (pthread_mutex_lock(&conlock)) {
|
|
|
|
|
|
|
|
ast_log(LOG_WARNING, "Unable to obtain lock\n");
|
|
|
|
ast_log(LOG_WARNING, "Unable to obtain lock\n");
|
|
|
|
if ((action == HELPER_EXISTS) || (action == HELPER_CANMATCH))
|
|
|
|
if ((action == HELPER_EXISTS) || (action == HELPER_CANMATCH))
|
|
|
|
return 0;
|
|
|
|
return 0;
|
|
|
@ -434,7 +501,7 @@ static int pbx_extension_helper(struct ast_channel *c, char *context, char *exte
|
|
|
|
#if 0
|
|
|
|
#if 0
|
|
|
|
/* By locking tmp, not only can the state of its entries not
|
|
|
|
/* By locking tmp, not only can the state of its entries not
|
|
|
|
change, but it cannot be destroyed either. */
|
|
|
|
change, but it cannot be destroyed either. */
|
|
|
|
pthread_mutex_lock(&tmp->lock);
|
|
|
|
ast_pthread_mutex_lock(&tmp->lock);
|
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
e = tmp->root;
|
|
|
|
e = tmp->root;
|
|
|
|
while(e) {
|
|
|
|
while(e) {
|
|
|
@ -447,17 +514,17 @@ static int pbx_extension_helper(struct ast_channel *c, char *context, char *exte
|
|
|
|
in here though. XXX */
|
|
|
|
in here though. XXX */
|
|
|
|
switch(action) {
|
|
|
|
switch(action) {
|
|
|
|
case HELPER_CANMATCH:
|
|
|
|
case HELPER_CANMATCH:
|
|
|
|
pthread_mutex_unlock(&conlock);
|
|
|
|
ast_pthread_mutex_unlock(&conlock);
|
|
|
|
return -1;
|
|
|
|
return -1;
|
|
|
|
case HELPER_EXISTS:
|
|
|
|
case HELPER_EXISTS:
|
|
|
|
pthread_mutex_unlock(&conlock);
|
|
|
|
ast_pthread_mutex_unlock(&conlock);
|
|
|
|
return -1;
|
|
|
|
return -1;
|
|
|
|
case HELPER_SPAWN:
|
|
|
|
case HELPER_SPAWN:
|
|
|
|
newstack++;
|
|
|
|
newstack++;
|
|
|
|
/* Fall through */
|
|
|
|
/* Fall through */
|
|
|
|
case HELPER_EXEC:
|
|
|
|
case HELPER_EXEC:
|
|
|
|
app = pbx_findapp(e->app);
|
|
|
|
app = pbx_findapp(e->app);
|
|
|
|
pthread_mutex_unlock(&conlock);
|
|
|
|
ast_pthread_mutex_unlock(&conlock);
|
|
|
|
if (app) {
|
|
|
|
if (app) {
|
|
|
|
strncpy(c->context, context, sizeof(c->context));
|
|
|
|
strncpy(c->context, context, sizeof(c->context));
|
|
|
|
strncpy(c->exten, exten, sizeof(c->exten));
|
|
|
|
strncpy(c->exten, exten, sizeof(c->exten));
|
|
|
@ -472,7 +539,7 @@ static int pbx_extension_helper(struct ast_channel *c, char *context, char *exte
|
|
|
|
res = pbx_exec(c, app->execute, e->data, newstack);
|
|
|
|
res = pbx_exec(c, app->execute, e->data, newstack);
|
|
|
|
c->appl = NULL;
|
|
|
|
c->appl = NULL;
|
|
|
|
c->data = NULL;
|
|
|
|
c->data = NULL;
|
|
|
|
pthread_mutex_unlock(&conlock);
|
|
|
|
ast_pthread_mutex_unlock(&conlock);
|
|
|
|
return res;
|
|
|
|
return res;
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
ast_log(LOG_WARNING, "No application '%s' for extension (%s, %s, %d)\n", e->app, context, exten, priority);
|
|
|
|
ast_log(LOG_WARNING, "No application '%s' for extension (%s, %s, %d)\n", e->app, context, exten, priority);
|
|
|
@ -484,30 +551,30 @@ static int pbx_extension_helper(struct ast_channel *c, char *context, char *exte
|
|
|
|
}
|
|
|
|
}
|
|
|
|
e = e->peer;
|
|
|
|
e = e->peer;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
pthread_mutex_unlock(&tmp->lock);
|
|
|
|
ast_pthread_mutex_unlock(&tmp->lock);
|
|
|
|
if ((action != HELPER_EXISTS) && (action != HELPER_CANMATCH)) {
|
|
|
|
if ((action != HELPER_EXISTS) && (action != HELPER_CANMATCH)) {
|
|
|
|
ast_log(LOG_WARNING, "No such priority '%d' in '%s' in '%s'\n", priority, exten, context);
|
|
|
|
ast_log(LOG_WARNING, "No such priority '%d' in '%s' in '%s'\n", priority, exten, context);
|
|
|
|
pthread_mutex_unlock(&conlock);
|
|
|
|
ast_pthread_mutex_unlock(&conlock);
|
|
|
|
return -1;
|
|
|
|
return -1;
|
|
|
|
} else if (action != HELPER_CANMATCH) {
|
|
|
|
} else if (action != HELPER_CANMATCH) {
|
|
|
|
pthread_mutex_unlock(&conlock);
|
|
|
|
ast_pthread_mutex_unlock(&conlock);
|
|
|
|
return 0;
|
|
|
|
return 0;
|
|
|
|
} else e = reale; /* Keep going */
|
|
|
|
} else e = reale; /* Keep going */
|
|
|
|
}
|
|
|
|
}
|
|
|
|
e = e->next;
|
|
|
|
e = e->next;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if ((action != HELPER_EXISTS) && (action != HELPER_CANMATCH)) {
|
|
|
|
if ((action != HELPER_EXISTS) && (action != HELPER_CANMATCH)) {
|
|
|
|
pthread_mutex_unlock(&conlock);
|
|
|
|
ast_pthread_mutex_unlock(&conlock);
|
|
|
|
ast_log(LOG_WARNING, "No such extension '%s' in '%s'\n", exten, context);
|
|
|
|
ast_log(LOG_WARNING, "No such extension '%s' in '%s'\n", exten, context);
|
|
|
|
return -1;
|
|
|
|
return -1;
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
pthread_mutex_unlock(&conlock);
|
|
|
|
ast_pthread_mutex_unlock(&conlock);
|
|
|
|
return 0;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
tmp = tmp->next;
|
|
|
|
tmp = tmp->next;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
pthread_mutex_unlock(&conlock);
|
|
|
|
ast_pthread_mutex_unlock(&conlock);
|
|
|
|
if (action != HELPER_EXISTS) {
|
|
|
|
if (action != HELPER_EXISTS) {
|
|
|
|
ast_log(LOG_WARNING, "No such context '%s'\n", context);
|
|
|
|
ast_log(LOG_WARNING, "No such context '%s'\n", context);
|
|
|
|
return -1;
|
|
|
|
return -1;
|
|
|
@ -522,7 +589,7 @@ int ast_pbx_longest_extension(char *context)
|
|
|
|
struct ast_context *tmp;
|
|
|
|
struct ast_context *tmp;
|
|
|
|
struct ast_exten *e;
|
|
|
|
struct ast_exten *e;
|
|
|
|
int len = 0;
|
|
|
|
int len = 0;
|
|
|
|
if (pthread_mutex_lock(&conlock)) {
|
|
|
|
if (ast_pthread_mutex_lock(&conlock)) {
|
|
|
|
ast_log(LOG_WARNING, "Unable to obtain lock\n");
|
|
|
|
ast_log(LOG_WARNING, "Unable to obtain lock\n");
|
|
|
|
return -1;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -531,16 +598,16 @@ int ast_pbx_longest_extension(char *context)
|
|
|
|
if (!strcasecmp(tmp->name, context)) {
|
|
|
|
if (!strcasecmp(tmp->name, context)) {
|
|
|
|
/* By locking tmp, not only can the state of its entries not
|
|
|
|
/* By locking tmp, not only can the state of its entries not
|
|
|
|
change, but it cannot be destroyed either. */
|
|
|
|
change, but it cannot be destroyed either. */
|
|
|
|
pthread_mutex_lock(&tmp->lock);
|
|
|
|
ast_pthread_mutex_lock(&tmp->lock);
|
|
|
|
/* But we can relieve the conlock, as tmp will not change */
|
|
|
|
/* But we can relieve the conlock, as tmp will not change */
|
|
|
|
pthread_mutex_unlock(&conlock);
|
|
|
|
ast_pthread_mutex_unlock(&conlock);
|
|
|
|
e = tmp->root;
|
|
|
|
e = tmp->root;
|
|
|
|
while(e) {
|
|
|
|
while(e) {
|
|
|
|
if (strlen(e->exten) > len)
|
|
|
|
if (strlen(e->exten) > len)
|
|
|
|
len = strlen(e->exten);
|
|
|
|
len = strlen(e->exten);
|
|
|
|
e = e->next;
|
|
|
|
e = e->next;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
pthread_mutex_unlock(&tmp->lock);
|
|
|
|
ast_pthread_mutex_unlock(&tmp->lock);
|
|
|
|
return len;
|
|
|
|
return len;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
tmp = tmp->next;
|
|
|
|
tmp = tmp->next;
|
|
|
@ -624,6 +691,11 @@ int ast_pbx_run(struct ast_channel *c)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
goto out;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (c->softhangup) {
|
|
|
|
|
|
|
|
ast_log(LOG_WARNING, "Extension %s, priority %d returned normally even though call was hung up\n",
|
|
|
|
|
|
|
|
c->exten, c->priority);
|
|
|
|
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
}
|
|
|
|
/* If we're playing something in the background, wait for it to finish or for a digit */
|
|
|
|
/* If we're playing something in the background, wait for it to finish or for a digit */
|
|
|
|
if (c->stream) {
|
|
|
|
if (c->stream) {
|
|
|
|
digit = ast_waitstream(c, AST_DIGIT_ANY);
|
|
|
|
digit = ast_waitstream(c, AST_DIGIT_ANY);
|
|
|
@ -642,6 +714,19 @@ int ast_pbx_run(struct ast_channel *c)
|
|
|
|
firstpass = 0;
|
|
|
|
firstpass = 0;
|
|
|
|
c->priority++;
|
|
|
|
c->priority++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!ast_exists_extension(c, c->context, c->exten, 1)) {
|
|
|
|
|
|
|
|
/* It's not a valid extension anymore */
|
|
|
|
|
|
|
|
if (ast_exists_extension(c, c->context, "i", 1)) {
|
|
|
|
|
|
|
|
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));
|
|
|
|
|
|
|
|
c->priority = 1;
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
ast_log(LOG_WARNING, "Channel '%s' sent into invalid extension '%s' in context '%s', but no invalid handler\n",
|
|
|
|
|
|
|
|
c->name, c->exten, c->context);
|
|
|
|
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
} else {
|
|
|
|
/* Done, wait for an extension */
|
|
|
|
/* Done, wait for an extension */
|
|
|
|
if (digit)
|
|
|
|
if (digit)
|
|
|
|
waittime = c->pbx->dtimeout;
|
|
|
|
waittime = c->pbx->dtimeout;
|
|
|
@ -692,6 +777,7 @@ int ast_pbx_run(struct ast_channel *c)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
if (firstpass)
|
|
|
|
if (firstpass)
|
|
|
|
ast_log(LOG_WARNING, "Don't know what to do with '%s'\n", c->name);
|
|
|
|
ast_log(LOG_WARNING, "Don't know what to do with '%s'\n", c->name);
|
|
|
|
out:
|
|
|
|
out:
|
|
|
@ -718,12 +804,15 @@ static void *pbx_thread(void *data)
|
|
|
|
int ast_pbx_start(struct ast_channel *c)
|
|
|
|
int ast_pbx_start(struct ast_channel *c)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
pthread_t t;
|
|
|
|
pthread_t t;
|
|
|
|
|
|
|
|
pthread_attr_t attr;
|
|
|
|
if (!c) {
|
|
|
|
if (!c) {
|
|
|
|
ast_log(LOG_WARNING, "Asked to start thread on NULL channel?\n");
|
|
|
|
ast_log(LOG_WARNING, "Asked to start thread on NULL channel?\n");
|
|
|
|
return -1;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/* Start a new thread, and get something handling this channel. */
|
|
|
|
/* Start a new thread, and get something handling this channel. */
|
|
|
|
if (pthread_create(&t, NULL, pbx_thread, c)) {
|
|
|
|
pthread_attr_init(&attr);
|
|
|
|
|
|
|
|
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
|
|
|
|
|
|
|
|
if (pthread_create(&t, &attr, pbx_thread, c)) {
|
|
|
|
ast_log(LOG_WARNING, "Failed to create new channel thread\n");
|
|
|
|
ast_log(LOG_WARNING, "Failed to create new channel thread\n");
|
|
|
|
return -1;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -736,10 +825,10 @@ int ast_remove_extension(struct ast_context *con, char *extension, int priority)
|
|
|
|
return -1;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
int ast_register_application(char *app, int (*execute)(struct ast_channel *, void *))
|
|
|
|
int ast_register_application(char *app, int (*execute)(struct ast_channel *, void *), char *synopsis, char *description)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
struct ast_app *tmp;
|
|
|
|
struct ast_app *tmp;
|
|
|
|
if (pthread_mutex_lock(&applock)) {
|
|
|
|
if (ast_pthread_mutex_lock(&applock)) {
|
|
|
|
ast_log(LOG_ERROR, "Unable to lock application list\n");
|
|
|
|
ast_log(LOG_ERROR, "Unable to lock application list\n");
|
|
|
|
return -1;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -747,7 +836,7 @@ int ast_register_application(char *app, int (*execute)(struct ast_channel *, voi
|
|
|
|
while(tmp) {
|
|
|
|
while(tmp) {
|
|
|
|
if (!strcasecmp(app, tmp->name)) {
|
|
|
|
if (!strcasecmp(app, tmp->name)) {
|
|
|
|
ast_log(LOG_WARNING, "Already have an application '%s'\n", app);
|
|
|
|
ast_log(LOG_WARNING, "Already have an application '%s'\n", app);
|
|
|
|
pthread_mutex_unlock(&applock);
|
|
|
|
ast_pthread_mutex_unlock(&applock);
|
|
|
|
return -1;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
tmp = tmp->next;
|
|
|
|
tmp = tmp->next;
|
|
|
@ -756,22 +845,218 @@ int ast_register_application(char *app, int (*execute)(struct ast_channel *, voi
|
|
|
|
if (tmp) {
|
|
|
|
if (tmp) {
|
|
|
|
strncpy(tmp->name, app, sizeof(tmp->name));
|
|
|
|
strncpy(tmp->name, app, sizeof(tmp->name));
|
|
|
|
tmp->execute = execute;
|
|
|
|
tmp->execute = execute;
|
|
|
|
|
|
|
|
tmp->synopsis = synopsis;
|
|
|
|
|
|
|
|
tmp->description = description;
|
|
|
|
tmp->next = apps;
|
|
|
|
tmp->next = apps;
|
|
|
|
apps = tmp;
|
|
|
|
apps = tmp;
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
ast_log(LOG_WARNING, "Out of memory\n");
|
|
|
|
ast_log(LOG_WARNING, "Out of memory\n");
|
|
|
|
pthread_mutex_unlock(&applock);
|
|
|
|
ast_pthread_mutex_unlock(&applock);
|
|
|
|
return -1;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (option_verbose > 1)
|
|
|
|
if (option_verbose > 1)
|
|
|
|
ast_verbose( VERBOSE_PREFIX_2 "Registered application '%s'\n", tmp->name);
|
|
|
|
ast_verbose( VERBOSE_PREFIX_2 "Registered application '%s'\n", tmp->name);
|
|
|
|
pthread_mutex_unlock(&applock);
|
|
|
|
ast_pthread_mutex_unlock(&applock);
|
|
|
|
return 0;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static char app_help[] =
|
|
|
|
|
|
|
|
"Usage: show application <application>\n"
|
|
|
|
|
|
|
|
" Describes a particular application.\n";
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static char apps_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 int handle_show_applications(int fd, int argc, char *argv[])
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
struct ast_app *tmp;
|
|
|
|
|
|
|
|
char buf[256];
|
|
|
|
|
|
|
|
if (ast_pthread_mutex_lock(&applock)) {
|
|
|
|
|
|
|
|
ast_log(LOG_ERROR, "Unable to lock application list\n");
|
|
|
|
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
ast_pthread_mutex_unlock(&applock);
|
|
|
|
|
|
|
|
return RESULT_SUCCESS;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static char *complete_app(char *line, char *word, int pos, int state)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
struct ast_app *tmp;
|
|
|
|
|
|
|
|
char *ret;
|
|
|
|
|
|
|
|
int which = 0;
|
|
|
|
|
|
|
|
if (ast_pthread_mutex_lock(&applock)) {
|
|
|
|
|
|
|
|
ast_log(LOG_ERROR, "Unable to lock application list\n");
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
tmp = apps;
|
|
|
|
|
|
|
|
while(tmp) {
|
|
|
|
|
|
|
|
if (!strncasecmp(word, tmp->name, strlen(word))) {
|
|
|
|
|
|
|
|
if (++which > state)
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
tmp = tmp->next;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
if (tmp)
|
|
|
|
|
|
|
|
ret = tmp->name;
|
|
|
|
|
|
|
|
else
|
|
|
|
|
|
|
|
ret = NULL;
|
|
|
|
|
|
|
|
ast_pthread_mutex_unlock(&applock);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return ret ? strdup(ret) : ret;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static char *complete_context(char *line, char *word, int pos, int state)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
tmp = contexts;
|
|
|
|
|
|
|
|
while(tmp) {
|
|
|
|
|
|
|
|
if (!strncasecmp(word, tmp->name, strlen(word))) {
|
|
|
|
|
|
|
|
if (++which > state)
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
tmp = tmp->next;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
if (tmp)
|
|
|
|
|
|
|
|
ret = tmp->name;
|
|
|
|
|
|
|
|
else
|
|
|
|
|
|
|
|
ret = NULL;
|
|
|
|
|
|
|
|
ast_pthread_mutex_unlock(&conlock);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return ret ? strdup(ret) : ret;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static int handle_show_application(int fd, int argc, char *argv[])
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
struct ast_app *tmp;
|
|
|
|
|
|
|
|
char buf[2048];
|
|
|
|
|
|
|
|
if (argc != 3)
|
|
|
|
|
|
|
|
return RESULT_SHOWUSAGE;
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
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[])
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
context = NULL;
|
|
|
|
|
|
|
|
exten = NULL;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
con = con->next;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
ast_pthread_mutex_unlock(&conlock);
|
|
|
|
|
|
|
|
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 };
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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) {
|
|
|
|
int ast_unregister_application(char *app) {
|
|
|
|
struct ast_app *tmp, *tmpl = NULL;
|
|
|
|
struct ast_app *tmp, *tmpl = NULL;
|
|
|
|
if (pthread_mutex_lock(&applock)) {
|
|
|
|
if (ast_pthread_mutex_lock(&applock)) {
|
|
|
|
ast_log(LOG_ERROR, "Unable to lock application list\n");
|
|
|
|
ast_log(LOG_ERROR, "Unable to lock application list\n");
|
|
|
|
return -1;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -784,25 +1069,25 @@ int ast_unregister_application(char *app) {
|
|
|
|
apps = tmp->next;
|
|
|
|
apps = tmp->next;
|
|
|
|
if (option_verbose > 1)
|
|
|
|
if (option_verbose > 1)
|
|
|
|
ast_verbose( VERBOSE_PREFIX_2 "Unregistered application '%s'\n", tmp->name);
|
|
|
|
ast_verbose( VERBOSE_PREFIX_2 "Unregistered application '%s'\n", tmp->name);
|
|
|
|
pthread_mutex_unlock(&applock);
|
|
|
|
ast_pthread_mutex_unlock(&applock);
|
|
|
|
return 0;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
tmpl = tmp;
|
|
|
|
tmpl = tmp;
|
|
|
|
tmp = tmp->next;
|
|
|
|
tmp = tmp->next;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
pthread_mutex_unlock(&applock);
|
|
|
|
ast_pthread_mutex_unlock(&applock);
|
|
|
|
return -1;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
struct ast_context *ast_context_create(char *name)
|
|
|
|
struct ast_context *ast_context_create(char *name, char *registrar)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
struct ast_context *tmp;
|
|
|
|
struct ast_context *tmp;
|
|
|
|
|
|
|
|
|
|
|
|
pthread_mutex_lock(&conlock);
|
|
|
|
ast_pthread_mutex_lock(&conlock);
|
|
|
|
tmp = contexts;
|
|
|
|
tmp = contexts;
|
|
|
|
while(tmp) {
|
|
|
|
while(tmp) {
|
|
|
|
if (!strcasecmp(tmp->name, name)) {
|
|
|
|
if (!strcasecmp(tmp->name, name)) {
|
|
|
|
pthread_mutex_unlock(&conlock);
|
|
|
|
ast_pthread_mutex_unlock(&conlock);
|
|
|
|
ast_log(LOG_WARNING, "Tried to register context '%s', already in use\n", name);
|
|
|
|
ast_log(LOG_WARNING, "Tried to register context '%s', already in use\n", name);
|
|
|
|
return NULL;
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -813,6 +1098,7 @@ struct ast_context *ast_context_create(char *name)
|
|
|
|
pthread_mutex_init(&tmp->lock, NULL);
|
|
|
|
pthread_mutex_init(&tmp->lock, NULL);
|
|
|
|
strncpy(tmp->name, name, sizeof(tmp->name));
|
|
|
|
strncpy(tmp->name, name, sizeof(tmp->name));
|
|
|
|
tmp->root = NULL;
|
|
|
|
tmp->root = NULL;
|
|
|
|
|
|
|
|
tmp->registrar = registrar;
|
|
|
|
tmp->next = contexts;
|
|
|
|
tmp->next = contexts;
|
|
|
|
tmp->includes = NULL;
|
|
|
|
tmp->includes = NULL;
|
|
|
|
contexts = tmp;
|
|
|
|
contexts = tmp;
|
|
|
@ -823,11 +1109,11 @@ struct ast_context *ast_context_create(char *name)
|
|
|
|
} else
|
|
|
|
} else
|
|
|
|
ast_log(LOG_WARNING, "Out of memory\n");
|
|
|
|
ast_log(LOG_WARNING, "Out of memory\n");
|
|
|
|
|
|
|
|
|
|
|
|
pthread_mutex_unlock(&conlock);
|
|
|
|
ast_pthread_mutex_unlock(&conlock);
|
|
|
|
return tmp;
|
|
|
|
return tmp;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int ast_context_add_include2(struct ast_context *con, char *value)
|
|
|
|
int ast_context_add_include2(struct ast_context *con, char *value, char *registrar)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
struct ast_include *inc, *incc, *incl = NULL;
|
|
|
|
struct ast_include *inc, *incc, *incl = NULL;
|
|
|
|
inc = malloc(sizeof(struct ast_include));
|
|
|
|
inc = malloc(sizeof(struct ast_include));
|
|
|
@ -837,6 +1123,7 @@ int ast_context_add_include2(struct ast_context *con, char *value)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
strncpy(inc->name, value, sizeof(inc->name));
|
|
|
|
strncpy(inc->name, value, sizeof(inc->name));
|
|
|
|
inc->next = NULL;
|
|
|
|
inc->next = NULL;
|
|
|
|
|
|
|
|
inc->registrar = registrar;
|
|
|
|
pthread_mutex_lock(&con->lock);
|
|
|
|
pthread_mutex_lock(&con->lock);
|
|
|
|
incc = con->includes;
|
|
|
|
incc = con->includes;
|
|
|
|
while(incc) {
|
|
|
|
while(incc) {
|
|
|
@ -859,7 +1146,8 @@ int ast_context_add_include2(struct ast_context *con, char *value)
|
|
|
|
|
|
|
|
|
|
|
|
int ast_add_extension2(struct ast_context *con,
|
|
|
|
int ast_add_extension2(struct ast_context *con,
|
|
|
|
int replace, char *extension, int priority,
|
|
|
|
int replace, char *extension, int priority,
|
|
|
|
char *application, void *data, void (*datad)(void *))
|
|
|
|
char *application, void *data, void (*datad)(void *),
|
|
|
|
|
|
|
|
char *registrar)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
|
|
#define LOG { if (option_debug) \
|
|
|
|
#define LOG { if (option_debug) \
|
|
|
@ -884,13 +1172,14 @@ int ast_add_extension2(struct ast_context *con,
|
|
|
|
strncpy(tmp->app, application, sizeof(tmp->app));
|
|
|
|
strncpy(tmp->app, application, sizeof(tmp->app));
|
|
|
|
tmp->data = data;
|
|
|
|
tmp->data = data;
|
|
|
|
tmp->datad = datad;
|
|
|
|
tmp->datad = datad;
|
|
|
|
|
|
|
|
tmp->registrar = registrar;
|
|
|
|
tmp->peer = NULL;
|
|
|
|
tmp->peer = NULL;
|
|
|
|
tmp->next = NULL;
|
|
|
|
tmp->next = NULL;
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
ast_log(LOG_WARNING, "Out of memory\n");
|
|
|
|
ast_log(LOG_WARNING, "Out of memory\n");
|
|
|
|
return -1;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (pthread_mutex_lock(&con->lock)) {
|
|
|
|
if (ast_pthread_mutex_lock(&con->lock)) {
|
|
|
|
free(tmp);
|
|
|
|
free(tmp);
|
|
|
|
/* And properly destroy the data */
|
|
|
|
/* And properly destroy the data */
|
|
|
|
datad(data);
|
|
|
|
datad(data);
|
|
|
@ -926,7 +1215,7 @@ int ast_add_extension2(struct ast_context *con,
|
|
|
|
/* Destroy the old one */
|
|
|
|
/* Destroy the old one */
|
|
|
|
e->datad(e->data);
|
|
|
|
e->datad(e->data);
|
|
|
|
free(e);
|
|
|
|
free(e);
|
|
|
|
pthread_mutex_unlock(&con->lock);
|
|
|
|
ast_pthread_mutex_unlock(&con->lock);
|
|
|
|
/* And immediately return success. */
|
|
|
|
/* And immediately return success. */
|
|
|
|
LOG;
|
|
|
|
LOG;
|
|
|
|
return 0;
|
|
|
|
return 0;
|
|
|
@ -934,7 +1223,7 @@ int ast_add_extension2(struct ast_context *con,
|
|
|
|
ast_log(LOG_WARNING, "Unable to register extension '%s', priority %d in '%s', already in use\n", tmp->exten, tmp->priority, con->name);
|
|
|
|
ast_log(LOG_WARNING, "Unable to register extension '%s', priority %d in '%s', already in use\n", tmp->exten, tmp->priority, con->name);
|
|
|
|
tmp->datad(tmp->data);
|
|
|
|
tmp->datad(tmp->data);
|
|
|
|
free(tmp);
|
|
|
|
free(tmp);
|
|
|
|
pthread_mutex_unlock(&con->lock);
|
|
|
|
ast_pthread_mutex_unlock(&con->lock);
|
|
|
|
return -1;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else if (e->priority > tmp->priority) {
|
|
|
|
} else if (e->priority > tmp->priority) {
|
|
|
@ -956,7 +1245,7 @@ int ast_add_extension2(struct ast_context *con,
|
|
|
|
tmp->peer = con->root->peer;
|
|
|
|
tmp->peer = con->root->peer;
|
|
|
|
con->root = tmp;
|
|
|
|
con->root = tmp;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
pthread_mutex_unlock(&con->lock);
|
|
|
|
ast_pthread_mutex_unlock(&con->lock);
|
|
|
|
/* And immediately return success. */
|
|
|
|
/* And immediately return success. */
|
|
|
|
LOG;
|
|
|
|
LOG;
|
|
|
|
return 0;
|
|
|
|
return 0;
|
|
|
@ -967,7 +1256,7 @@ int ast_add_extension2(struct ast_context *con,
|
|
|
|
/* If we make it here, then it's time for us to go at the very end.
|
|
|
|
/* If we make it here, then it's time for us to go at the very end.
|
|
|
|
ep *must* be defined or we couldn't have gotten here. */
|
|
|
|
ep *must* be defined or we couldn't have gotten here. */
|
|
|
|
ep->peer = tmp;
|
|
|
|
ep->peer = tmp;
|
|
|
|
pthread_mutex_unlock(&con->lock);
|
|
|
|
ast_pthread_mutex_unlock(&con->lock);
|
|
|
|
/* And immediately return success. */
|
|
|
|
/* And immediately return success. */
|
|
|
|
LOG;
|
|
|
|
LOG;
|
|
|
|
return 0;
|
|
|
|
return 0;
|
|
|
@ -983,7 +1272,7 @@ int ast_add_extension2(struct ast_context *con,
|
|
|
|
/* We're at the top of the list */
|
|
|
|
/* We're at the top of the list */
|
|
|
|
con->root = tmp;
|
|
|
|
con->root = tmp;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
pthread_mutex_unlock(&con->lock);
|
|
|
|
ast_pthread_mutex_unlock(&con->lock);
|
|
|
|
/* And immediately return success. */
|
|
|
|
/* And immediately return success. */
|
|
|
|
LOG;
|
|
|
|
LOG;
|
|
|
|
return 0;
|
|
|
|
return 0;
|
|
|
@ -997,22 +1286,23 @@ int ast_add_extension2(struct ast_context *con,
|
|
|
|
el->next = tmp;
|
|
|
|
el->next = tmp;
|
|
|
|
else
|
|
|
|
else
|
|
|
|
con->root = tmp;
|
|
|
|
con->root = tmp;
|
|
|
|
pthread_mutex_unlock(&con->lock);
|
|
|
|
ast_pthread_mutex_unlock(&con->lock);
|
|
|
|
LOG;
|
|
|
|
LOG;
|
|
|
|
return 0;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void ast_context_destroy(struct ast_context *con)
|
|
|
|
void ast_context_destroy(struct ast_context *con, char *registrar)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
struct ast_context *tmp, *tmpl=NULL;
|
|
|
|
struct ast_context *tmp, *tmpl=NULL;
|
|
|
|
struct ast_include *tmpi, *tmpil= NULL;
|
|
|
|
struct ast_include *tmpi, *tmpil= NULL;
|
|
|
|
pthread_mutex_lock(&conlock);
|
|
|
|
ast_pthread_mutex_lock(&conlock);
|
|
|
|
tmp = contexts;
|
|
|
|
tmp = contexts;
|
|
|
|
while(tmp) {
|
|
|
|
while(tmp) {
|
|
|
|
if (tmp == con) {
|
|
|
|
if (((tmp == con) || !con) &&
|
|
|
|
|
|
|
|
(!registrar || !strcasecmp(registrar, tmp->registrar))) {
|
|
|
|
/* Okay, let's lock the structure to be sure nobody else
|
|
|
|
/* Okay, let's lock the structure to be sure nobody else
|
|
|
|
is searching through it. */
|
|
|
|
is searching through it. */
|
|
|
|
if (pthread_mutex_lock(&tmp->lock)) {
|
|
|
|
if (ast_pthread_mutex_lock(&tmp->lock)) {
|
|
|
|
ast_log(LOG_WARNING, "Unable to lock context lock\n");
|
|
|
|
ast_log(LOG_WARNING, "Unable to lock context lock\n");
|
|
|
|
return;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -1022,7 +1312,7 @@ void ast_context_destroy(struct ast_context *con)
|
|
|
|
contexts = tmp->next;
|
|
|
|
contexts = tmp->next;
|
|
|
|
/* Okay, now we're safe to let it go -- in a sense, we were
|
|
|
|
/* Okay, now we're safe to let it go -- in a sense, we were
|
|
|
|
ready to let it go as soon as we locked it. */
|
|
|
|
ready to let it go as soon as we locked it. */
|
|
|
|
pthread_mutex_unlock(&tmp->lock);
|
|
|
|
ast_pthread_mutex_unlock(&tmp->lock);
|
|
|
|
for (tmpi = tmp->includes; tmpi; ) {
|
|
|
|
for (tmpi = tmp->includes; tmpi; ) {
|
|
|
|
/* Free includes */
|
|
|
|
/* Free includes */
|
|
|
|
tmpil = tmpi;
|
|
|
|
tmpil = tmpi;
|
|
|
@ -1031,16 +1321,57 @@ void ast_context_destroy(struct ast_context *con)
|
|
|
|
tmpil = tmpi;
|
|
|
|
tmpil = tmpi;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
free(tmp);
|
|
|
|
free(tmp);
|
|
|
|
pthread_mutex_unlock(&conlock);
|
|
|
|
if (!con) {
|
|
|
|
|
|
|
|
/* Might need to get another one -- restart */
|
|
|
|
|
|
|
|
tmp = contexts;
|
|
|
|
|
|
|
|
tmpl = NULL;
|
|
|
|
|
|
|
|
tmpil = NULL;
|
|
|
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
ast_pthread_mutex_unlock(&conlock);
|
|
|
|
return;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
tmpl = tmp;
|
|
|
|
tmpl = tmp;
|
|
|
|
tmp = tmp->next;
|
|
|
|
tmp = tmp->next;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
pthread_mutex_unlock(&conlock);
|
|
|
|
ast_pthread_mutex_unlock(&conlock);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void wait_for_hangup(struct ast_channel *chan)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
int res;
|
|
|
|
|
|
|
|
struct ast_frame *f;
|
|
|
|
|
|
|
|
do {
|
|
|
|
|
|
|
|
res = ast_waitfor(chan, -1);
|
|
|
|
|
|
|
|
if (res < 0)
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
f = ast_read(chan);
|
|
|
|
|
|
|
|
if (f)
|
|
|
|
|
|
|
|
ast_frfree(f);
|
|
|
|
|
|
|
|
} while(f);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int pbx_builtin_answer(struct ast_channel *chan, void *data)
|
|
|
|
static int pbx_builtin_ringing(struct ast_channel *chan, void *data)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
ast_indicate(chan, AST_CONTROL_RINGING);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static int pbx_builtin_busy(struct ast_channel *chan, void *data)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
ast_indicate(chan, AST_CONTROL_BUSY);
|
|
|
|
|
|
|
|
wait_for_hangup(chan);
|
|
|
|
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static int pbx_builtin_congestion(struct ast_channel *chan, void *data)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
ast_indicate(chan, AST_CONTROL_CONGESTION);
|
|
|
|
|
|
|
|
wait_for_hangup(chan);
|
|
|
|
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static int pbx_builtin_answer(struct ast_channel *chan, void *data)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
if (chan->state != AST_STATE_RING) {
|
|
|
|
if (chan->state != AST_STATE_RING) {
|
|
|
|
if (option_debug)
|
|
|
|
if (option_debug)
|
|
|
@ -1050,20 +1381,20 @@ int pbx_builtin_answer(struct ast_channel *chan, void *data)
|
|
|
|
return ast_answer(chan);
|
|
|
|
return ast_answer(chan);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int pbx_builtin_setlanguage(struct ast_channel *chan, void *data)
|
|
|
|
static int pbx_builtin_setlanguage(struct ast_channel *chan, void *data)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
/* Copy the language as specified */
|
|
|
|
/* Copy the language as specified */
|
|
|
|
strncpy(chan->language, (char *)data, sizeof(chan->language));
|
|
|
|
strncpy(chan->language, (char *)data, sizeof(chan->language));
|
|
|
|
return 0;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int pbx_builtin_hangup(struct ast_channel *chan, void *data)
|
|
|
|
static int pbx_builtin_hangup(struct ast_channel *chan, void *data)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
/* Just return non-zero and it will hang up */
|
|
|
|
/* Just return non-zero and it will hang up */
|
|
|
|
return -1;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int pbx_builtin_stripmsd(struct ast_channel *chan, void *data)
|
|
|
|
static int pbx_builtin_stripmsd(struct ast_channel *chan, void *data)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
char newexten[AST_MAX_EXTENSION] = "";
|
|
|
|
char newexten[AST_MAX_EXTENSION] = "";
|
|
|
|
if (!data || !atoi(data)) {
|
|
|
|
if (!data || !atoi(data)) {
|
|
|
@ -1077,7 +1408,7 @@ int pbx_builtin_stripmsd(struct ast_channel *chan, void *data)
|
|
|
|
return 0;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int pbx_builtin_prefix(struct ast_channel *chan, void *data)
|
|
|
|
static int pbx_builtin_prefix(struct ast_channel *chan, void *data)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
char newexten[AST_MAX_EXTENSION] = "";
|
|
|
|
char newexten[AST_MAX_EXTENSION] = "";
|
|
|
|
if (!data || !strlen(data)) {
|
|
|
|
if (!data || !strlen(data)) {
|
|
|
@ -1086,10 +1417,12 @@ int pbx_builtin_prefix(struct ast_channel *chan, void *data)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
snprintf(newexten, sizeof(newexten), "%s%s", (char *)data, chan->exten);
|
|
|
|
snprintf(newexten, sizeof(newexten), "%s%s", (char *)data, chan->exten);
|
|
|
|
strncpy(chan->exten, newexten, sizeof(chan->exten));
|
|
|
|
strncpy(chan->exten, newexten, sizeof(chan->exten));
|
|
|
|
|
|
|
|
if (option_verbose > 2)
|
|
|
|
|
|
|
|
ast_verbose(VERBOSE_PREFIX_3 "Prepended prefix, new extension is %s\n", chan->exten);
|
|
|
|
return 0;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int pbx_builtin_wait(struct ast_channel *chan, void *data)
|
|
|
|
static int pbx_builtin_wait(struct ast_channel *chan, void *data)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
/* Wait for "n" seconds */
|
|
|
|
/* Wait for "n" seconds */
|
|
|
|
if (data && atoi((char *)data))
|
|
|
|
if (data && atoi((char *)data))
|
|
|
@ -1097,7 +1430,7 @@ int pbx_builtin_wait(struct ast_channel *chan, void *data)
|
|
|
|
return 0;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int pbx_builtin_background(struct ast_channel *chan, void *data)
|
|
|
|
static int pbx_builtin_background(struct ast_channel *chan, void *data)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
int res;
|
|
|
|
int res;
|
|
|
|
/* Answer if need be */
|
|
|
|
/* Answer if need be */
|
|
|
@ -1111,7 +1444,7 @@ int pbx_builtin_background(struct ast_channel *chan, void *data)
|
|
|
|
return res;
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int pbx_builtin_rtimeout(struct ast_channel *chan, void *data)
|
|
|
|
static int pbx_builtin_rtimeout(struct ast_channel *chan, void *data)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
/* Set the timeout for how long to wait between digits */
|
|
|
|
/* Set the timeout for how long to wait between digits */
|
|
|
|
chan->pbx->rtimeout = atoi((char *)data);
|
|
|
|
chan->pbx->rtimeout = atoi((char *)data);
|
|
|
@ -1120,7 +1453,7 @@ int pbx_builtin_rtimeout(struct ast_channel *chan, void *data)
|
|
|
|
return 0;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int pbx_builtin_dtimeout(struct ast_channel *chan, void *data)
|
|
|
|
static int pbx_builtin_dtimeout(struct ast_channel *chan, void *data)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
/* Set the timeout for how long to wait between digits */
|
|
|
|
/* Set the timeout for how long to wait between digits */
|
|
|
|
chan->pbx->dtimeout = atoi((char *)data);
|
|
|
|
chan->pbx->dtimeout = atoi((char *)data);
|
|
|
@ -1129,7 +1462,7 @@ int pbx_builtin_dtimeout(struct ast_channel *chan, void *data)
|
|
|
|
return 0;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int pbx_builtin_goto(struct ast_channel *chan, void *data)
|
|
|
|
static int pbx_builtin_goto(struct ast_channel *chan, void *data)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
char *s;
|
|
|
|
char *s;
|
|
|
|
char *exten, *pri, *context;
|
|
|
|
char *exten, *pri, *context;
|
|
|
@ -1161,7 +1494,7 @@ int pbx_builtin_goto(struct ast_channel *chan, void *data)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/* At this point we have a priority and maybe an extension and a context */
|
|
|
|
/* At this point we have a priority and maybe an extension and a context */
|
|
|
|
chan->priority = atoi(pri) - 1;
|
|
|
|
chan->priority = atoi(pri) - 1;
|
|
|
|
if (exten)
|
|
|
|
if (exten && strcasecmp(exten, "BYEXTENSION"))
|
|
|
|
strncpy(chan->exten, exten, sizeof(chan->exten));
|
|
|
|
strncpy(chan->exten, exten, sizeof(chan->exten));
|
|
|
|
if (context)
|
|
|
|
if (context)
|
|
|
|
strncpy(chan->context, context, sizeof(chan->context));
|
|
|
|
strncpy(chan->context, context, sizeof(chan->context));
|
|
|
@ -1169,6 +1502,7 @@ int pbx_builtin_goto(struct ast_channel *chan, void *data)
|
|
|
|
ast_verbose( VERBOSE_PREFIX_3 "Goto (%s,%s,%d)\n", chan->context,chan->exten, chan->priority+1);
|
|
|
|
ast_verbose( VERBOSE_PREFIX_3 "Goto (%s,%s,%d)\n", chan->context,chan->exten, chan->priority+1);
|
|
|
|
return 0;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int load_pbx(void)
|
|
|
|
int load_pbx(void)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
int x;
|
|
|
|
int x;
|
|
|
@ -1177,10 +1511,13 @@ int load_pbx(void)
|
|
|
|
ast_verbose( "Asterisk PBX Core Initializing\n");
|
|
|
|
ast_verbose( "Asterisk PBX Core Initializing\n");
|
|
|
|
ast_verbose( "Registering builtin applications:\n");
|
|
|
|
ast_verbose( "Registering builtin applications:\n");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
ast_cli_register(&showapps);
|
|
|
|
|
|
|
|
ast_cli_register(&showapp);
|
|
|
|
|
|
|
|
ast_cli_register(&showdialplan);
|
|
|
|
for (x=0;x<sizeof(builtins) / sizeof(struct pbx_builtin); x++) {
|
|
|
|
for (x=0;x<sizeof(builtins) / sizeof(struct pbx_builtin); x++) {
|
|
|
|
if (option_verbose)
|
|
|
|
if (option_verbose)
|
|
|
|
ast_verbose( VERBOSE_PREFIX_1 "[%s]\n", builtins[x].name);
|
|
|
|
ast_verbose( VERBOSE_PREFIX_1 "[%s]\n", builtins[x].name);
|
|
|
|
if (ast_register_application(builtins[x].name, builtins[x].execute)) {
|
|
|
|
if (ast_register_application(builtins[x].name, builtins[x].execute, builtins[x].synopsis, builtins[x].description)) {
|
|
|
|
ast_log(LOG_ERROR, "Unable to register builtin application '%s'\n", builtins[x].name);
|
|
|
|
ast_log(LOG_ERROR, "Unable to register builtin application '%s'\n", builtins[x].name);
|
|
|
|
return -1;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|