Newer
Older
Russell Bryant
committed
AST_LIST_UNLOCK(&hints);
return res;
/*! \brief ast_get_hint: Get hint for channel */
int ast_get_hint(char *hint, int hintsize, char *name, int namesize, struct ast_channel *c, const char *context, const char *exten)
struct ast_exten *e = ast_hint_extension(c, context, exten);
ast_copy_string(hint, ast_get_extension_app(e), hintsize);
const char *tmp = ast_get_extension_app_data(e);
}
return 0;
}
int ast_exists_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, HELPER_EXISTS);
int ast_findlabel_extension(struct ast_channel *c, const char *context, const char *exten, const char *label, const char *callerid)
return pbx_extension_helper(c, NULL, context, exten, 0, label, callerid, HELPER_FINDLABEL);
}
int ast_findlabel_extension2(struct ast_channel *c, struct ast_context *con, const char *exten, const char *label, const char *callerid)
{
return pbx_extension_helper(c, con, NULL, exten, 0, label, callerid, HELPER_FINDLABEL);
int ast_canmatch_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, HELPER_CANMATCH);
int ast_matchmore_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, HELPER_MATCHMORE);
}
int ast_spawn_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
{
return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, HELPER_SPAWN);
/* helper function to set extension and priority */
static void set_ext_pri(struct ast_channel *c, const char *exten, int pri)
{
ast_copy_string(c->exten, exten, sizeof(c->exten));
c->priority = pri;
}
Kevin P. Fleming
committed
int digit;
char exten[256];
int pos;
int waittime;
Kevin P. Fleming
committed
int autoloopflag;
/* A little initial setup here */
if (c->pbx)
ast_log(LOG_WARNING, "%s already has PBX structure??\n", c->name);
Russell Bryant
committed
if (!(c->pbx = ast_calloc(1, sizeof(*c->pbx))))
c->cdr = ast_cdr_alloc();
if (!c->cdr) {
ast_log(LOG_WARNING, "Unable to create Call Detail Record\n");
free(c->pbx);
return -1;
}
ast_cdr_init(c->cdr, c);
}
}
/* Set reasonable defaults */
c->pbx->rtimeout = 10;
c->pbx->dtimeout = 5;
Kevin P. Fleming
committed
autoloopflag = ast_test_flag(c, AST_FLAG_IN_AUTOLOOP);
ast_set_flag(c, AST_FLAG_IN_AUTOLOOP);
/* Start by trying whatever the channel is set to */
if (!ast_exists_extension(c, c->context, c->exten, c->priority, c->cid.cid_num)) {
Kevin P. Fleming
committed
/* If not successful fall back to 's' */
if (option_verbose > 1)
ast_verbose( VERBOSE_PREFIX_2 "Starting %s at %s,%s,%d failed so falling back to exten 's'\n", c->name, c->context, c->exten, c->priority);
/* XXX the original code used the existing priority in the call to
* ast_exists_extension(), and reset it to 1 afterwards.
* I believe the correct thing is to set it to 1 immediately.
*/
set_ext_pri(c, "s", 1);
if (!ast_exists_extension(c, c->context, c->exten, c->priority, c->cid.cid_num)) {
/* JK02: And finally back to default if everything else failed */
if (option_verbose > 1)
ast_verbose( VERBOSE_PREFIX_2 "Starting %s at %s,%s,%d still failed so falling back to context 'default'\n", c->name, c->context, c->exten, c->priority);
ast_copy_string(c->context, "default", sizeof(c->context));
if (c->cdr && ast_tvzero(c->cdr->start))
while (ast_exists_extension(c, c->context, c->exten, c->priority, c->cid.cid_num)) {
if ((res = ast_spawn_extension(c, c->context, c->exten, c->priority, c->cid.cid_num))) {
/* Something bad happened, or a hangup has been requested. */
if (((res >= '0') && (res <= '9')) || ((res >= 'A') && (res <= 'F')) ||
(res == '*') || (res == '#')) {
ast_log(LOG_DEBUG, "Oooh, got something to jump out with ('%c')!\n", res);
switch(res) {
case AST_PBX_KEEPALIVE:
if (option_debug)
ast_log(LOG_DEBUG, "Spawn extension (%s,%s,%d) exited KEEPALIVE on '%s'\n", c->context, c->exten, c->priority, c->name);
else if (option_verbose > 1)
ast_verbose( VERBOSE_PREFIX_2 "Spawn extension (%s, %s, %d) exited KEEPALIVE on '%s'\n", c->context, c->exten, c->priority, c->name);
default:
if (option_debug)
ast_log(LOG_DEBUG, "Spawn extension (%s,%s,%d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
else if (option_verbose > 1)
ast_verbose( VERBOSE_PREFIX_2 "Spawn extension (%s, %s, %d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
if (c->_softhangup == AST_SOFTHANGUP_ASYNCGOTO) {
c->_softhangup =0;
break;
}
/* atimeout */
if (c->_softhangup == AST_SOFTHANGUP_TIMEOUT) {
break;
}
if (c->cdr) {
ast_cdr_update(c);
}
if (c->_softhangup == AST_SOFTHANGUP_TIMEOUT && ast_exists_extension(c,c->context,"T",1,c->cid.cid_num)) {
set_ext_pri(c, "T", 0); /* 0 will become 1 with the c->priority++; at the end */
/* If the AbsoluteTimeout is not reset to 0, we'll get an infinite loop */
c->whentohangup = 0;
ast_log(LOG_DEBUG, "Extension %s, priority %d returned normally even though call was hung up\n",
if (!ast_exists_extension(c, c->context, c->exten, 1, c->cid.cid_num)) {
/* If there is no match at priority 1, it is not a valid extension anymore.
* Try to continue at "i", 1 or exit if the latter does not exist.
*/
if (ast_exists_extension(c, c->context, "i", 1, c->cid.cid_num)) {
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);
pbx_builtin_setvar_helper(c, "INVALID_EXTEN", c->exten);
set_ext_pri(c, "i", 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);
} else if (c->_softhangup == AST_SOFTHANGUP_TIMEOUT) {
/* If we get this far with AST_SOFTHANGUP_TIMEOUT, then we know that the "T" extension is next. */
c->_softhangup = 0;
if (waittime) {
while (ast_matchmore_extension(c, c->context, exten, 1, c->cid.cid_num)) {
/* 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);
if (c->_softhangup == AST_SOFTHANGUP_ASYNCGOTO) {
c->_softhangup = 0;
if (!digit)
/* No entry */
break;
if (digit < 0)
/* Error, maybe a hangup */
goto out;
exten[pos++] = digit;
waittime = c->pbx->dtimeout;
}
if (ast_exists_extension(c, c->context, exten, 1, c->cid.cid_num)) {
/* Prepare the next cycle */
set_ext_pri(c, exten, 1);
/* No such extension */
if (!ast_strlen_zero(exten)) {
/* An invalid extension */
if (ast_exists_extension(c, c->context, "i", 1, c->cid.cid_num)) {
if (option_verbose > 2)
ast_verbose( VERBOSE_PREFIX_3 "Invalid extension '%s' in context '%s' on %s\n", exten, c->context, c->name);
pbx_builtin_setvar_helper(c, "INVALID_EXTEN", exten);
set_ext_pri(c, "i", 1);
} else {
ast_log(LOG_WARNING, "Invalid extension '%s', but no rule 'i' in context '%s'\n", exten, c->context);
goto out;
}
/* A simple timeout */
if (ast_exists_extension(c, c->context, "t", 1, c->cid.cid_num)) {
if (option_verbose > 2)
ast_verbose( VERBOSE_PREFIX_3 "Timeout on %s\n", c->name);
set_ext_pri(c, "t", 1);
} else {
ast_log(LOG_WARNING, "Timeout, but no rule 't' in context '%s'\n", c->context);
goto out;
}
}
}
if (c->cdr) {
if (option_verbose > 2)
ast_verbose(VERBOSE_PREFIX_2 "CDR updated on %s\n",c->name);
ast_cdr_update(c);
}
} else {
const char *status;
Kevin P. Fleming
committed
status = pbx_builtin_getvar_helper(c, "DIALSTATUS");
if (!status)
status = "UNKNOWN";
if (option_verbose > 2)
ast_verbose(VERBOSE_PREFIX_2 "Auto fallthrough, channel '%s' status is '%s'\n", c->name, status);
if (!strcasecmp(status, "CONGESTION"))
res = pbx_builtin_congestion(c, "10");
else if (!strcasecmp(status, "CHANUNAVAIL"))
res = pbx_builtin_congestion(c, "10");
else if (!strcasecmp(status, "BUSY"))
res = pbx_builtin_busy(c, "10");
goto out;
}
}
if (firstpass)
ast_log(LOG_WARNING, "Don't know what to do with '%s'\n", c->name);
out:
if ((res != AST_PBX_KEEPALIVE) && ast_exists_extension(c, c->context, "h", 1, c->cid.cid_num)) {
if (c->cdr && ast_opt_end_cdr_before_h_exten)
ast_cdr_end(c->cdr);
set_ext_pri(c, "h", 1);
while(ast_exists_extension(c, c->context, c->exten, c->priority, c->cid.cid_num)) {
if ((res = ast_spawn_extension(c, c->context, c->exten, c->priority, c->cid.cid_num))) {
/* Something bad happened, or a hangup has been requested. */
if (option_debug)
ast_log(LOG_DEBUG, "Spawn extension (%s,%s,%d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
else if (option_verbose > 1)
ast_verbose( VERBOSE_PREFIX_2 "Spawn extension (%s, %s, %d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
break;
}
c->priority++;
}
}
Kevin P. Fleming
committed
ast_set2_flag(c, autoloopflag, AST_FLAG_IN_AUTOLOOP);
if (res != AST_PBX_KEEPALIVE)
ast_hangup(c);
Kevin P. Fleming
committed
/* Returns 0 on success, non-zero if call limit was reached */
static int increase_call_count(const struct ast_channel *c)
{
int failed = 0;
double curloadavg;
Kevin P. Fleming
committed
ast_mutex_lock(&maxcalllock);
if (option_maxcalls) {
if (countcalls >= option_maxcalls) {
ast_log(LOG_NOTICE, "Maximum call limit of %d calls exceeded by '%s'!\n", option_maxcalls, c->name);
failed = -1;
}
}
if (option_maxload) {
getloadavg(&curloadavg, 1);
if (curloadavg >= option_maxload) {
ast_log(LOG_NOTICE, "Maximum loadavg limit of %f load exceeded by '%s' (currently %f)!\n", option_maxload, c->name, curloadavg);
failed = -1;
}
}
Kevin P. Fleming
committed
if (!failed)
countcalls++;
ast_mutex_unlock(&maxcalllock);
return failed;
}
static void decrease_call_count(void)
{
ast_mutex_lock(&maxcalllock);
if (countcalls > 0)
countcalls--;
ast_mutex_unlock(&maxcalllock);
}
static void *pbx_thread(void *data)
{
/* Oh joyeous kernel, we're a new thread, with nothing to do but
answer this channel and get it going.
*/
Kevin P. Fleming
committed
/* NOTE:
The launcher of this function _MUST_ increment 'countcalls'
before invoking the function; it will be decremented when the
PBX has finished running on the channel
*/
Kevin P. Fleming
committed
__ast_pbx_run(c);
decrease_call_count();
Kevin P. Fleming
committed
Kevin P. Fleming
committed
enum ast_pbx_result ast_pbx_start(struct ast_channel *c)
Kevin P. Fleming
committed
if (!c) {
ast_log(LOG_WARNING, "Asked to start thread on NULL channel?\n");
Kevin P. Fleming
committed
return AST_PBX_FAILED;
Kevin P. Fleming
committed
if (increase_call_count(c))
return AST_PBX_CALL_LIMIT;
/* Start a new thread, and get something handling this channel. */
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
if (ast_pthread_create(&t, &attr, pbx_thread, c)) {
ast_log(LOG_WARNING, "Failed to create new channel thread\n");
Kevin P. Fleming
committed
return AST_PBX_FAILED;
Kevin P. Fleming
committed
return AST_PBX_SUCCESS;
Kevin P. Fleming
committed
enum ast_pbx_result ast_pbx_run(struct ast_channel *c)
Kevin P. Fleming
committed
enum ast_pbx_result res = AST_PBX_SUCCESS;
if (increase_call_count(c))
return AST_PBX_CALL_LIMIT;
res = __ast_pbx_run(c);
decrease_call_count();
return res;
}
int ast_active_calls(void)
{
return countcalls;
}
int oldval = autofallthrough;
autofallthrough = newval;
/* lookup for a context with a given name,
* return with conlock held if found, NULL if not found
*/
static struct ast_context *find_context_locked(const char *context)
{
struct ast_context *c = NULL;
if (ast_lock_contexts()) {
errno = EBUSY;
return NULL;
}
while ( (c = ast_walk_contexts(c)) ) {
if (!strcmp(ast_get_context_name(c), context))
return c;
}
ast_unlock_contexts();
errno = ENOENT;
return NULL;
}
* This function locks contexts list by &conlist, search for the right 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(const char *context, const char *include, const char *registrar)
int ret = -1;
struct ast_context *c = find_context_locked(context);
if (c) {
/* found, remove include from this context ... */
ret = ast_context_remove_include2(c, include, registrar);
ast_unlock_contexts();
}
/*
* 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, const char *include, const char *registrar)
/* find our include */
if (!strcmp(i->name, include) &&
Mark Spencer
committed
(!registrar || !strcmp(i->registrar, registrar))) {
/* remove from list */
if (pi)
pi->next = i->next;
else
con->includes = i->next;
/* free include and return */
free(i);
ast_mutex_unlock(&con->lock);
return 0;
}
}
/* we can't find the right include */
ast_mutex_unlock(&con->lock);
/*!
* \note 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(const char *context, const char *sw, const char *data, const char *registrar)
struct ast_context *c = find_context_locked(context);
if (c) {
/* remove switch from this context ... */
ret = ast_context_remove_switch2(c, sw, data, registrar);
ast_unlock_contexts();
/*!
* \brief This function locks given context, removes switch, unlock context and
* return.
* \note 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.
*
*/
int ast_context_remove_switch2(struct ast_context *con, const char *sw, const char *data, const char *registrar)
if (ast_mutex_lock(&con->lock))
return -1;
if (!strcmp(i->name, sw) && !strcmp(i->data, data) &&
Mark Spencer
committed
(!registrar || !strcmp(i->registrar, registrar))) {
/* found, remove from list */
if (pi)
pi->next = i->next;
else
con->alts = i->next;
free(i); /* free switch and return */
ret = 0;
break;
ast_mutex_unlock(&con->lock);
* \note 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(const char *context, const char *extension, int priority, const char *registrar)
struct ast_context *c = find_context_locked(context);
if (c) { /* ... remove extension ... */
ret = ast_context_remove_extension2(c, extension, priority, registrar);
ast_unlock_contexts();
/*!
* \brief 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.
* \note 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.
*
int ast_context_remove_extension2(struct ast_context *con, const char *extension, int priority, const char *registrar)
{
struct ast_exten *exten, *prev_exten = NULL;
if (ast_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) &&
Mark Spencer
committed
(!registrar || !strcmp(exten->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;
if (!peer->priority==PRIORITY_HINT)
ast_remove_hint(peer);
peer->datad(peer->data);
free(peer);
peer = exten;
}
ast_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 &&
Mark Spencer
committed
(!registrar || !strcmp(peer->registrar, registrar) )) {
2596
2597
2598
2599
2600
2601
2602
2603
2604
2605
2606
2607
2608
2609
2610
2611
2612
2613
2614
2615
2616
2617
2618
2619
2620
2621
2622
/* 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 */
if (peer->priority==PRIORITY_HINT)
ast_remove_hint(peer);
ast_mutex_unlock(&con->lock);
return 0;
} else {
/* this is not right extension, skip to next peer */
previous_peer = peer;
peer = peer->peer;
}
}
ast_mutex_unlock(&con->lock);
return -1;
}
}
prev_exten = exten;
exten = exten->next;
}
/* we can't find right extension */
ast_mutex_unlock(&con->lock);
/*! \brief Dynamically register a new dial plan application */
int ast_register_application(const char *app, int (*execute)(struct ast_channel *, void *), const char *synopsis, const char *description)
Mark Spencer
committed
struct ast_app *tmp, *prev, *cur;
int length;
length = sizeof(struct ast_app);
length += strlen(app) + 1;
if (ast_mutex_lock(&applock)) {
ast_log(LOG_ERROR, "Unable to lock application list\n");
return -1;
}
if (!strcasecmp(app, tmp->name)) {
ast_log(LOG_WARNING, "Already have an application '%s'\n", app);
ast_mutex_unlock(&applock);
Russell Bryant
committed
if (!(tmp = ast_calloc(1, length))) {
ast_mutex_unlock(&applock);
strcpy(tmp->name, app);
tmp->execute = execute;
tmp->synopsis = synopsis;
tmp->description = description;
/* Store in alphabetical order */
prev = NULL;
for (cur = apps; cur; cur = cur->next) {
if (strcasecmp(tmp->name, cur->name) < 0)
break;
prev = cur;
}
if (prev) {
tmp->next = prev->next;
prev->next = tmp;
} else {
tmp->next = apps;
apps = tmp;
}
ast_verbose( VERBOSE_PREFIX_2 "Registered application '%s'\n", term_color(tmps, tmp->name, COLOR_BRCYAN, 0, sizeof(tmps)));
ast_mutex_unlock(&applock);
/*
* Append to the list. We don't have a tail pointer because we need
* to scan the list anyways to check for duplicates during insertion.
*/
if (ast_mutex_lock(&switchlock)) {
ast_log(LOG_ERROR, "Unable to lock switch lock\n");
for (tmp = switches; tmp; prev = tmp, tmp = tmp->next) {
if (!strcasecmp(tmp->name, sw->name))
break;
ast_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_mutex_unlock(&switchlock);
void ast_unregister_switch(struct ast_switch *sw)
if (ast_mutex_lock(&switchlock)) {
ast_log(LOG_ERROR, "Unable to lock switch lock\n");
return;
for (tmp = switches; tmp; prev = tmp, tmp = tmp->next) {
if (tmp == sw) {
if (prev)
prev->next = tmp->next;
else
switches = tmp->next;
tmp->next = NULL;
break;
ast_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 show_functions_help[] =
"Usage: show functions [like <text>]\n"
" List builtin functions, optionally only those matching a given string\n";
static char show_function_help[] =
"Usage: show function <function>\n"
" Describe a particular dialplan function.\n";
"Usage: show applications [{like|describing} <text>]\n"
" List applications which are currently available.\n"
" If 'like', <text> will be a substring of the app name\n"
" If 'describing', <text> will be a substring of the description\n";
static char show_dialplan_help[] =
"Usage: show dialplan [exten@][context]\n"
" Show dialplan\n";
static char show_switches_help[] =
"Usage: show switches\n"
" Show registered switches\n";
static char show_hints_help[] =
"Usage: show hints\n"
" Show registered hints\n";
static char show_globals_help[] =
"Usage: show globals\n"
" Show current global dialplan variables and their values\n";
static char set_global_help[] =
"Usage: set global <name> <value>\n"
" Set global dialplan variable <name> to <value>\n";
/*
* IMPLEMENTATION OF CLI FUNCTIONS IS IN THE SAME ORDER AS COMMANDS HELPS
*
*/
/*
* \brief '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 ...
*/
Russell Bryant
committed
static char *complete_show_application(const char *line, const char *word, int pos, int state)
char *ret = NULL;
int wordlen = strlen(word);
if (ast_mutex_lock(&applock)) {
ast_log(LOG_ERROR, "Unable to lock application list\n");
Russell Bryant
committed
/* return the n-th [partial] matching entry */
for (a = apps; a && !ret; a = a->next) {
if (!strncasecmp(word, a->name, wordlen) && ++which > state)
ret = strdup(a->name);
ast_mutex_unlock(&applock);
return ret;
}
static int handle_show_application(int fd, int argc, char *argv[])
{
if (argc < 3) return RESULT_SHOWUSAGE;
/* try to lock applications list ... */
if (ast_mutex_lock(&applock)) {
ast_log(LOG_ERROR, "Unable to lock application list\n");
return -1;
}
/* ... compare this application name with all arguments given
* to 'show application' command ... */
for (app = 2; app < argc; app++) {
if (!strcasecmp(a->name, argv[app])) {
/* Maximum number of characters added by terminal coloring is 22 */
char infotitle[64 + AST_MAX_APP + 22], syntitle[40], destitle[40];
char info[64 + AST_MAX_APP], *synopsis = NULL, *description = NULL;
int synopsis_size, description_size;
if (a->synopsis)
synopsis_size = strlen(a->synopsis) + 23;
else
synopsis_size = strlen("Not available") + 23;
synopsis = alloca(synopsis_size);
if (a->description)
description_size = strlen(a->description) + 23;
else
description_size = strlen("Not available") + 23;
description = alloca(description_size);
if (synopsis && description) {
snprintf(info, 64 + AST_MAX_APP, "\n -= Info about application '%s' =- \n\n", a->name);
term_color(infotitle, info, COLOR_MAGENTA, 0, 64 + AST_MAX_APP + 22);
term_color(syntitle, "[Synopsis]\n", COLOR_MAGENTA, 0, 40);
term_color(destitle, "[Description]\n", COLOR_MAGENTA, 0, 40);
term_color(synopsis,
a->synopsis ? a->synopsis : "Not available",
COLOR_CYAN, 0, synopsis_size);
term_color(description,
a->description ? a->description : "Not available",
COLOR_CYAN, 0, description_size);
ast_cli(fd,"%s%s%s\n\n%s%s\n", infotitle, syntitle, synopsis, destitle, description);
} else {
/* ... one of our applications, show info ...*/
ast_cli(fd,"\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_mutex_unlock(&applock);
/* 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;
}
/*! \brief handle_show_hints: CLI support for listing registred dial plan hints */
static int handle_show_hints(int fd, int argc, char *argv[])
{
struct ast_hint *hint;
int num = 0;
Kevin P. Fleming
committed
int watchers;
struct ast_state_cb *watcher;
Russell Bryant
committed
if (AST_LIST_EMPTY(&hints)) {
ast_cli(fd, "There are no registered dialplan hints\n");
return RESULT_SUCCESS;
}
/* ... we have hints ... */
ast_cli(fd, "\n -= Registered Asterisk Dial Plan Hints =-\n");
Russell Bryant
committed
if (AST_LIST_LOCK(&hints)) {
ast_log(LOG_ERROR, "Unable to lock hints\n");
return -1;
}
Russell Bryant
committed
AST_LIST_TRAVERSE(&hints, hint, list) {
Kevin P. Fleming
committed
watchers = 0;
for (watcher = hint->callbacks; watcher; watcher = watcher->next)
watchers++;
ast_cli(fd, " %20s@%-20.20s: %-20.20s State:%-15.15s Watchers %2d\n",
ast_get_extension_name(hint->exten),
ast_get_context_name(ast_get_extension_context(hint->exten)),
ast_get_extension_app(hint->exten),
num++;
}
ast_cli(fd, "----------------\n");
ast_cli(fd, "- %d hints registered\n", num);
Russell Bryant
committed
AST_LIST_UNLOCK(&hints);
/*! \brief handle_show_switches: CLI support for listing registred dial plan switches */
static int handle_show_switches(int fd, int argc, char *argv[])
struct ast_switch *sw;
if (!switches) {
ast_cli(fd, "There are no registered alternative switches\n");
return RESULT_SUCCESS;
}
/* ... we have applications ... */
ast_cli(fd, "\n -= Registered Asterisk Alternative Switches =-\n");
if (ast_mutex_lock(&switchlock)) {
ast_log(LOG_ERROR, "Unable to lock switches\n");
return -1;
}
ast_cli(fd, "%s: %s\n", sw->name, sw->description);
ast_mutex_unlock(&switchlock);
return RESULT_SUCCESS;
}
/*
* 'show applications' CLI command implementation functions ...
*/
static int handle_show_applications(int fd, int argc, char *argv[])
{
struct ast_app *a;
int total_match = 0; /* Number of matches in like clause */
int total_apps = 0; /* Number of apps registered */
if (ast_mutex_lock(&applock)) {
ast_log(LOG_ERROR, "Unable to lock application list\n");
return -1;
}
/* ... have we got at least one application (first)? no? */
if (!apps) {
ast_cli(fd, "There are no registered applications\n");
ast_mutex_unlock(&applock);
/* show applications like <keyword> */
if ((argc == 4) && (!strcmp(argv[2], "like"))) {
like = 1;
} else if ((argc > 3) && (!strcmp(argv[2], "describing"))) {
describing = 1;
}
/* show applications describing <keyword1> [<keyword2>] [...] */
if ((!like) && (!describing)) {
ast_cli(fd, " -= Registered Asterisk Applications =-\n");
} else {
ast_cli(fd, " -= Matching Asterisk Applications =-\n");
}
for (a = apps; a; a = a->next) {
/* ... show informations about applications ... */