Newer
Older
S_OR(context, chan->context), S_OR(exten, chan->exten), priority);
/* Masquerade into temp channel */
ast_channel_masquerade(tmpchan, chan);
/* Grab the locks and get going */
ast_channel_lock(tmpchan);
Mark Spencer
committed
ast_do_masquerade(tmpchan);
ast_channel_unlock(tmpchan);
/* Start the PBX going on our stolen channel */
if (ast_pbx_start(tmpchan)) {
ast_log(LOG_WARNING, "Unable to start PBX on %s\n", tmpchan->name);
ast_hangup(tmpchan);
res = -1;
}
}
}
ast_channel_unlock(chan);
int ast_async_goto_by_name(const char *channame, const char *context, const char *exten, int priority)
Kevin P. Fleming
committed
chan = ast_get_channel_by_name_locked(channame);
if (chan) {
res = ast_async_goto(chan, context, exten, priority);
ast_channel_unlock(chan);
/*! \brief copy a string skipping whitespace */
static int ext_strncpy(char *dst, const char *src, int len)
/* otherwise exten => [a-b],1,... doesn't work */
/* case '-': */
/* Ignore */
break;
default:
*dst = *src;
dst++;
}
src++;
count++;
}
*dst = '\0';
static void null_datad(void *foo)
{
}
4063
4064
4065
4066
4067
4068
4069
4070
4071
4072
4073
4074
4075
4076
4077
4078
4079
4080
4081
4082
4083
4084
4085
4086
4087
4088
4089
4090
4091
4092
4093
4094
4095
4096
4097
4098
4099
4100
4101
4102
4103
4104
4105
4106
4107
4108
4109
4110
4111
4112
4113
4114
4115
4116
4117
4118
4119
4120
/*! \brief add the extension in the priority chain */
static int add_pri(struct ast_context *con, struct ast_exten *tmp,
struct ast_exten *el, struct ast_exten *e, int replace)
{
struct ast_exten *ep;
for (ep = NULL; e ; ep = e, e = e->peer) {
if (e->priority >= tmp->priority)
break;
}
if (!e) { /* go at the end, and ep is surely set because the list is not empty */
ep->peer = tmp;
return 0; /* success */
}
if (e->priority == tmp->priority) {
/* Can't have something exactly the same. Is this a
replacement? If so, replace, otherwise, bonk. */
if (!replace) {
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);
free(tmp);
return -1;
}
/* we are replacing e, so copy the link fields and then update
* whoever pointed to e to point to us
*/
tmp->next = e->next; /* not meaningful if we are not first in the peer list */
tmp->peer = e->peer; /* always meaningful */
if (ep) /* We're in the peer list, just insert ourselves */
ep->peer = tmp;
else if (el) /* We're the first extension. Take over e's functions */
el->next = tmp;
else /* We're the very first extension. */
con->root = tmp;
if (tmp->priority == PRIORITY_HINT)
ast_change_hint(e,tmp);
/* Destroy the old one */
e->datad(e->data);
free(e);
} else { /* Slip ourselves in just before e */
tmp->peer = e;
tmp->next = e->next; /* extension chain, or NULL if e is not the first extension */
if (ep) /* Easy enough, we're just in the peer list */
ep->peer = tmp;
else { /* we are the first in some peer list, so link in the ext list */
if (el)
el->next = tmp; /* in the middle... */
else
con->root = tmp; /* ... or at the head */
e->next = NULL; /* e is no more at the head, so e->next must be reset */
}
/* And immediately return success. */
if (tmp->priority == PRIORITY_HINT)
ast_add_hint(tmp);
}
return 0;
}
/*! \brief
* Main interface to add extensions to the list for out context.
*
* We sort extensions in order of matching preference, so that we can
* stop the search as soon as we find a suitable match.
* This ordering also takes care of wildcards such as '.' (meaning
* "one or more of any character") and '!' (which is 'earlymatch',
* meaning "zero or more of any character" but also impacts the
* return value from CANMATCH and EARLYMATCH.
* The extension match rules defined in the devmeeting 2006.05.05 are
* quite simple: WE SELECT THE LONGEST MATCH.
* In detail, "longest" means the number of matched characters in
* the extension. In case of ties (e.g. _XXX and 333) in the length
* of a pattern, we give priority to entries with the smallest cardinality
* (e.g, [5-9] comes before [2-8] before the former has only 5 elements,
* while the latter has 7, etc.
* In case of same cardinality, the first element in the range counts.
* If we still have a tie, any final '!' will make this as a possibly
* less specific pattern.
*
* EBUSY - can't lock
* EEXIST - extension with the same priority exist and no replace is set
*
*/
int replace, const char *extension, int priority, const char *label, const char *callerid,
const char *application, void *data, void (*datad)(void *),
const char *registrar)
#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
* in order by the extension number. Then, extensions of different
* priorities (same extension) are kept in a list, according to the
* peer pointer.
*/
struct ast_exten *tmp, *e, *el = NULL;
int length;
char *p;
char expand_buf[VAR_BUF_SIZE] = { 0, };
/* if we are adding a hint, and there are global variables, and the hint
contains variable references, then expand them
*/
ast_mutex_lock(&globalslock);
if ((priority == PRIORITY_HINT) && AST_LIST_FIRST(&globals) && strstr(application, "${")) {
pbx_substitute_variables_varshead(&globals, application, expand_buf, sizeof(expand_buf));
application = expand_buf;
}
ast_mutex_unlock(&globalslock);
length = sizeof(struct ast_exten);
length += strlen(extension) + 1;
length += strlen(application) + 1;
if (label)
length += strlen(label) + 1;
if (callerid)
length += strlen(callerid) + 1;
else
/* Be optimistic: Build the extension structure first */
if (datad == NULL)
datad = null_datad;
Russell Bryant
committed
if (!(tmp = ast_calloc(1, length)))
Russell Bryant
committed
4204
4205
4206
4207
4208
4209
4210
4211
4212
4213
4214
4215
4216
4217
4218
4219
4220
4221
4222
4223
4224
4225
4226
4227
/* use p as dst in assignments, as the fields are const char * */
p = tmp->stuff;
if (label) {
tmp->label = p;
strcpy(p, label);
p += strlen(label) + 1;
}
tmp->exten = p;
p += ext_strncpy(p, extension, strlen(extension) + 1) + 1;
tmp->priority = priority;
tmp->cidmatch = p; /* but use p for assignments below */
if (callerid) {
p += ext_strncpy(p, callerid, strlen(callerid) + 1) + 1;
tmp->matchcid = 1;
} else {
*p++ = '\0';
tmp->matchcid = 0;
}
tmp->app = p;
strcpy(p, application);
tmp->parent = con;
tmp->data = data;
tmp->datad = datad;
tmp->registrar = registrar;
ast_mutex_lock(&con->lock);
for (e = con->root; e; el = e, e = e->next) { /* scan the extension list */
/* XXX should use ext_cmp() to sort patterns correctly */
/* almost strcmp, but make sure patterns are always last! */
if (e->exten[0] != '_' && extension[0] == '_')
else if (e->exten[0] == '_' && extension[0] != '_')
res = 1;
else
res= strcmp(e->exten, extension);
if (res == 0) { /* extension match, now look at cidmatch */
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)
break;
}
if (e && res == 0) { /* exact match, insert in the pri chain */
int ret = add_pri(con, tmp, el, e, replace);
ast_mutex_unlock(&con->lock);
if (ret < 0)
errno = EEXIST;
else {
LOG;
/* ok found the insertion place, right before 'e' (if any) */
tmp->next = e;
if (el)
el->next = tmp;
else
con->root = tmp;
ast_mutex_unlock(&con->lock);
if (tmp->priority == PRIORITY_HINT)
struct async_stat {
pthread_t p;
struct ast_channel *chan;
char context[AST_MAX_CONTEXT];
char exten[AST_MAX_EXTENSION];
int priority;
int timeout;
char app[AST_MAX_EXTENSION];
{
struct async_stat *as = data;
struct ast_channel *chan = as->chan;
int timeout = as->timeout;
int res;
struct ast_frame *f;
while (timeout && (chan->_state != AST_STATE_UP)) {
break;
if (timeout > -1)
timeout = res;
f = ast_read(chan);
if (!f)
break;
if (f->frametype == AST_FRAME_CONTROL) {
if ((f->subclass == AST_CONTROL_BUSY) ||
(f->subclass == AST_CONTROL_CONGESTION) )
break;
}
ast_frfree(f);
}
if (chan->_state == AST_STATE_UP) {
if (!ast_strlen_zero(as->app)) {
app = pbx_findapp(as->app);
if (app) {
if (option_verbose > 2)
ast_verbose(VERBOSE_PREFIX_3 "Launching %s(%s) on %s\n", as->app, as->appdata, chan->name);
pbx_exec(chan, app, as->appdata);
} else
ast_log(LOG_WARNING, "No such application '%s'\n", as->app);
if (!ast_strlen_zero(as->context))
ast_copy_string(chan->context, as->context, sizeof(chan->context));
if (!ast_strlen_zero(as->exten))
ast_copy_string(chan->exten, as->exten, sizeof(chan->exten));
if (as->priority > 0)
chan->priority = as->priority;
/* Run the PBX */
if (ast_pbx_run(chan)) {
ast_log(LOG_ERROR, "Failed to start PBX on %s\n", chan->name);
} else {
/* PBX will have taken care of this */
chan = NULL;
}
}
}
free(as);
if (chan)
ast_hangup(chan);
return NULL;
}
Joshua Colp
committed
/*! Function to post an empty cdr after a spool call fails.
Joshua Colp
committed
* This function posts an empty cdr for a failed spool call
*
*/
int ast_pbx_outgoing_cdr_failed(void)
{
/* allocate a channel */
struct ast_channel *chan = ast_channel_alloc(0);
Russell Bryant
committed
if (!chan)
return -1; /* failure */
chan->cdr = ast_cdr_alloc(); /* allocate a cdr for the channel */
/* allocation of the cdr failed */
ast_channel_free(chan); /* free the channel */
return -1; /* return failure */
}
/* allocation of the cdr was successful */
ast_cdr_init(chan->cdr, chan); /* initilize our channel's cdr */
ast_cdr_start(chan->cdr); /* record the start and stop time */
ast_cdr_end(chan->cdr);
ast_cdr_failed(chan->cdr); /* set the status to failed */
ast_cdr_detach(chan->cdr); /* post and free the record */
ast_channel_free(chan); /* free the channel */
return 0; /* success */
}
int ast_pbx_outgoing_exten(const char *type, int format, void *data, int timeout, const char *context, const char *exten, int priority, int *reason, int sync, const char *cid_num, const char *cid_name, struct ast_variable *vars, const char *account, struct ast_channel **channel)
{
struct ast_channel *chan;
struct async_stat *as;
Martin Pycko
committed
struct outgoing_helper oh;
Martin Pycko
committed
LOAD_OH(oh);
chan = __ast_request_and_dial(type, format, data, timeout, reason, cid_num, cid_name, &oh);
if (channel) {
*channel = chan;
if (chan)
ast_channel_lock(chan);
if (chan->cdr) { /* check if the channel already has a cdr record, if not give it one */
ast_log(LOG_WARNING, "%s already has a call record??\n", chan->name);
} else {
chan->cdr = ast_cdr_alloc(); /* allocate a cdr for the channel */
if (!chan->cdr) {
/* allocation of the cdr failed */
free(chan->pbx);
res = -1;
goto outgoing_exten_cleanup;
}
/* allocation of the cdr was successful */
ast_cdr_init(chan->cdr, chan); /* initilize our channel's cdr */
ast_cdr_start(chan->cdr);
}
Martin Pycko
committed
res = 0;
if (option_verbose > 3)
ast_verbose(VERBOSE_PREFIX_4 "Channel %s was answered.\n", chan->name);
Martin Pycko
committed
ast_channel_unlock(chan);
ast_log(LOG_ERROR, "Unable to run PBX on %s\n", chan->name);
if (channel)
*channel = NULL;
ast_hangup(chan);
res = -1;
}
} else {
if (ast_pbx_start(chan)) {
ast_log(LOG_ERROR, "Unable to start PBX on %s\n", chan->name);
*channel = NULL;
ast_channel_unlock(chan);
} else {
if (option_verbose > 3)
ast_verbose(VERBOSE_PREFIX_4 "Channel %s was never answered.\n", chan->name);
if(chan->cdr) { /* update the cdr */
/* here we update the status of the call, which sould be busy.
* if that fails then we set the status to failed */
if (ast_cdr_disposition(chan->cdr, chan->hangupcause))
ast_cdr_failed(chan->cdr);
}
*channel = NULL;
ast_channel_unlock(chan);
if (res < 0) { /* the call failed for some reason */
if (*reason == 0) { /* if the call failed (not busy or no answer)
* update the cdr with the failed message */
cdr_res = ast_pbx_outgoing_cdr_failed();
if (cdr_res != 0) {
res = cdr_res;
goto outgoing_exten_cleanup;
}
/* create a fake channel and execute the "failed" extension (if it exists) within the requested context */
/* check if "failed" exists */
if (ast_exists_extension(chan, context, "failed", 1, NULL)) {
chan = ast_channel_alloc(0);
if (chan) {
ast_string_field_set(chan, name, "OutgoingSpoolFailed");
if (!ast_strlen_zero(context))
ast_copy_string(chan->context, context, sizeof(chan->context));
set_ext_pri(chan, "failed", 1);
ast_set_variables(chan, vars);
if (account)
ast_cdr_setaccount(chan, account);
Russell Bryant
committed
if (!(as = ast_calloc(1, sizeof(*as)))) {
res = -1;
goto outgoing_exten_cleanup;
chan = ast_request_and_dial(type, format, data, timeout, reason, cid_num, cid_name);
if (channel) {
*channel = chan;
if (chan)
ast_channel_lock(chan);
res = -1;
goto outgoing_exten_cleanup;
ast_copy_string(as->context, context, sizeof(as->context));
set_ext_pri(as->chan, exten, priority);
ast_set_variables(chan, vars);
if (account)
ast_cdr_setaccount(chan, account);
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
if (ast_pthread_create(&as->p, &attr, async_wait, as)) {
ast_log(LOG_WARNING, "Failed to start async wait\n");
free(as);
*channel = NULL;
ast_channel_unlock(chan);
res = -1;
goto outgoing_exten_cleanup;
outgoing_exten_cleanup:
ast_variables_destroy(vars);
struct app_tmp {
char app[256];
char data[256];
struct ast_channel *chan;
pthread_t t;
};
/*! \brief run the application and free the descriptor once done */
static void *ast_pbx_run_app(void *data)
{
struct app_tmp *tmp = data;
struct ast_app *app;
app = pbx_findapp(tmp->app);
if (app) {
if (option_verbose > 3)
ast_verbose(VERBOSE_PREFIX_4 "Launching %s(%s) on %s\n", tmp->app, tmp->data, tmp->chan->name);
pbx_exec(tmp->chan, app, tmp->data);
} else
ast_log(LOG_WARNING, "No such application '%s'\n", tmp->app);
ast_hangup(tmp->chan);
free(tmp);
return NULL;
}
int ast_pbx_outgoing_app(const char *type, int format, void *data, int timeout, const char *app, const char *appdata, int *reason, int sync, const char *cid_num, const char *cid_name, struct ast_variable *vars, const char *account, struct ast_channel **locked_channel)
{
struct ast_channel *chan;
struct app_tmp *tmp;
struct outgoing_helper oh;
memset(&oh, 0, sizeof(oh));
*locked_channel = NULL;
if (ast_strlen_zero(app)) {
res = -1;
}
chan = __ast_request_and_dial(type, format, data, timeout, reason, cid_num, cid_name, &oh);
if (chan->cdr) { /* check if the channel already has a cdr record, if not give it one */
ast_log(LOG_WARNING, "%s already has a call record??\n", chan->name);
} else {
chan->cdr = ast_cdr_alloc(); /* allocate a cdr for the channel */
if(!chan->cdr) {
/* allocation of the cdr failed */
free(chan->pbx);
res = -1;
goto outgoing_app_cleanup;
}
/* allocation of the cdr was successful */
ast_cdr_init(chan->cdr, chan); /* initilize our channel's cdr */
ast_cdr_start(chan->cdr);
}
ast_set_variables(chan, vars);
if (account)
ast_cdr_setaccount(chan, account);
if (chan->_state == AST_STATE_UP) {
res = 0;
if (option_verbose > 3)
ast_verbose(VERBOSE_PREFIX_4 "Channel %s was answered.\n", chan->name);
tmp = ast_calloc(1, sizeof(*tmp));
if (!tmp)
res = -1;
else {
ast_copy_string(tmp->app, app, sizeof(tmp->app));
if (appdata)
ast_copy_string(tmp->data, appdata, sizeof(tmp->data));
ast_channel_unlock(chan);
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
ast_channel_lock(chan);
if (ast_pthread_create(&tmp->t, &attr, ast_pbx_run_app, tmp)) {
ast_log(LOG_WARNING, "Unable to spawn execute thread on %s: %s\n", chan->name, strerror(errno));
free(tmp);
ast_channel_unlock(chan);
} else {
*locked_channel = chan;
}
}
}
} else {
if (option_verbose > 3)
ast_verbose(VERBOSE_PREFIX_4 "Channel %s was never answered.\n", chan->name);
if (chan->cdr) { /* update the cdr */
/* here we update the status of the call, which sould be busy.
* if that fails then we set the status to failed */
if (ast_cdr_disposition(chan->cdr, chan->hangupcause))
ast_cdr_failed(chan->cdr);
}
if (res < 0) { /* the call failed for some reason */
if (*reason == 0) { /* if the call failed (not busy or no answer)
* update the cdr with the failed message */
cdr_res = ast_pbx_outgoing_cdr_failed();
if (cdr_res != 0) {
res = cdr_res;
goto outgoing_app_cleanup;
}
struct async_stat *as;
Russell Bryant
committed
if (!(as = ast_calloc(1, sizeof(*as)))) {
res = -1;
goto outgoing_app_cleanup;
}
chan = __ast_request_and_dial(type, format, data, timeout, reason, cid_num, cid_name, &oh);
res = -1;
goto outgoing_app_cleanup;
ast_copy_string(as->app, app, sizeof(as->app));
ast_copy_string(as->appdata, appdata, sizeof(as->appdata));
ast_set_variables(chan, vars);
if (account)
ast_cdr_setaccount(chan, account);
/* Start a new thread, and get something handling this channel. */
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
ast_channel_lock(chan);
if (ast_pthread_create(&as->p, &attr, async_wait, as)) {
ast_log(LOG_WARNING, "Failed to start async wait\n");
free(as);
ast_channel_unlock(chan);
res = -1;
goto outgoing_app_cleanup;
} else {
if (locked_channel)
*locked_channel = chan;
outgoing_app_cleanup:
ast_variables_destroy(vars);
void __ast_context_destroy(struct ast_context *con, const char *registrar)
struct ast_sw *sw;
struct ast_exten *e, *el, *en;
Mark Spencer
committed
ast_mutex_lock(&conlock);
for (tmp = contexts; tmp; ) {
struct ast_context *next; /* next starting point */
for (; tmp; tmpl = tmp, tmp = tmp->next) {
ast_log(LOG_WARNING, "check ctx %s %s\n", tmp->name, tmp->registrar);
if ( (!registrar || !strcasecmp(registrar, tmp->registrar)) &&
(!con || !strcasecmp(tmp->name, con->name)) )
break; /* found it */
}
if (!tmp) /* not found, we are done */
break;
ast_mutex_lock(&tmp->lock);
ast_log(LOG_WARNING, "delete ctx %s %s\n", tmp->name, tmp->registrar);
4704
4705
4706
4707
4708
4709
4710
4711
4712
4713
4714
4715
4716
4717
4718
4719
4720
4721
4722
4723
4724
4725
4726
4727
next = tmp->next;
if (tmpl)
tmpl->next = next;
else
contexts = next;
/* 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. */
ast_mutex_unlock(&tmp->lock);
for (tmpi = tmp->includes; tmpi; ) { /* Free includes */
struct ast_include *tmpil = tmpi;
tmpi = tmpi->next;
free(tmpil);
}
for (ipi = tmp->ignorepats; ipi; ) { /* Free ignorepats */
struct ast_ignorepat *ipl = ipi;
ipi = ipi->next;
free(ipl);
}
while ((sw = AST_LIST_REMOVE_HEAD(&tmp->alts, list)))
free(sw);
for (e = tmp->root; e;) {
for (en = e->peer; en;) {
el = en;
en = en->peer;
destroy_exten(el);
}
el = e;
e = e->next;
destroy_exten(el);
ast_mutex_destroy(&tmp->lock);
free(tmp);
/* if we have a specific match, we are done, otherwise continue */
tmp = con ? NULL : next;
Mark Spencer
committed
ast_mutex_unlock(&conlock);
void ast_context_destroy(struct ast_context *con, const char *registrar)
Mark Spencer
committed
__ast_context_destroy(con,registrar);
static void wait_for_hangup(struct ast_channel *chan, void *data)
if (ast_strlen_zero(data) || (sscanf(data, "%d", &waittime) != 1) || (waittime < 0))
waittime = -1;
if (waittime > -1) {
ast_safe_sleep(chan, waittime * 1000);
} else do {
res = ast_waitfor(chan, -1);
if (res < 0)
return;
f = ast_read(chan);
if (f)
ast_frfree(f);
} while(f);
}
/*!
* \ingroup applications
*/
static int pbx_builtin_progress(struct ast_channel *chan, void *data)
{
ast_indicate(chan, AST_CONTROL_PROGRESS);
return 0;
}
/*!
* \ingroup applications
*/
static int pbx_builtin_ringing(struct ast_channel *chan, void *data)
{
ast_indicate(chan, AST_CONTROL_RINGING);
return 0;
}
/*!
* \ingroup applications
*/
static int pbx_builtin_busy(struct ast_channel *chan, void *data)
{
Kevin P. Fleming
committed
ast_setstate(chan, AST_STATE_BUSY);
wait_for_hangup(chan, data);
/*!
* \ingroup applications
*/
static int pbx_builtin_congestion(struct ast_channel *chan, void *data)
{
ast_indicate(chan, AST_CONTROL_CONGESTION);
Kevin P. Fleming
committed
ast_setstate(chan, AST_STATE_BUSY);
wait_for_hangup(chan, data);
/*!
* \ingroup applications
*/
static int pbx_builtin_answer(struct ast_channel *chan, void *data)
int delay = 0;
int res;
if (chan->_state == AST_STATE_UP)
delay = 0;
else if (!ast_strlen_zero(data))
delay = atoi(data);
res = ast_answer(chan);
if (res)
return res;
if (delay)
res = ast_safe_sleep(chan, delay);
return res;
AST_APP_OPTIONS(resetcdr_opts, {
AST_APP_OPTION('w', AST_CDR_FLAG_POSTED),
AST_APP_OPTION('a', AST_CDR_FLAG_LOCKED),
AST_APP_OPTION('v', AST_CDR_FLAG_KEEP_VARS),
});
/*!
* \ingroup applications
*/
static int pbx_builtin_resetcdr(struct ast_channel *chan, void *data)
{
char *args;
struct ast_flags flags = { 0 };
if (!ast_strlen_zero(data)) {
if (!(args = ast_strdupa(data)))
Russell Bryant
committed
return -1;
ast_app_parse_options(resetcdr_opts, &flags, NULL, args);
}
ast_cdr_reset(chan->cdr, &flags);
/*!
* \ingroup applications
*/
static int pbx_builtin_setamaflags(struct ast_channel *chan, void *data)
{
/* Copy the AMA Flags as specified */
ast_cdr_setamaflags(chan, data ? data : "");
/*!
* \ingroup applications
*/
static int pbx_builtin_hangup(struct ast_channel *chan, void *data)
{
/* Just return non-zero and it will hang up */
if (!chan->hangupcause)
chan->hangupcause = AST_CAUSE_NORMAL_CLEARING;
/*!
* \ingroup applications
*/
static int pbx_builtin_gotoiftime(struct ast_channel *chan, void *data)
{
Russell Bryant
committed
int res=0;
if (ast_strlen_zero(data)) {
ast_log(LOG_WARNING, "GotoIfTime requires an argument:\n <time range>|<days of week>|<days of month>|<months>?[[context|]extension|]priority\n");
return -1;
}
Russell Bryant
committed
if ((s = ast_strdupa(data))) {
ts = s;
Russell Bryant
committed
/* Separate the Goto path */
strsep(&ts,"?");
Russell Bryant
committed
/* struct ast_include include contained garbage here, fixed by zeroing it on get_timerange */
if (ast_build_timing(&timing, s) && ast_check_timing(&timing))
res = pbx_builtin_goto(chan, (void *)ts);
}
return res;
}
/*!
* \ingroup applications
*/
static int pbx_builtin_execiftime(struct ast_channel *chan, void *data)
{
struct ast_timing timing;
struct ast_app *app;
static const char *usage = "ExecIfTime requires an argument:\n <time range>|<days of week>|<days of month>|<months>?<appname>[|<appargs>]";
if (ast_strlen_zero(data)) {
s = strsep(&appname,"?"); /* Separate the timerange and application name/data */
if (!appname) { /* missing application */
ast_log(LOG_WARNING, "%s\n", usage);
return -1;
}
if (!ast_build_timing(&timing, s)) {
ast_log(LOG_WARNING, "Invalid Time Spec: %s\nCorrect usage: %s\n", s, usage);
return -1;
}
if (!ast_check_timing(&timing)) /* outside the valid time window, just return */
return 0;
/* now split appname|appargs */
if ((s = strchr(appname, '|')))
*s++ = '\0';
if ((app = pbx_findapp(appname))) {
return pbx_exec(chan, app, S_OR(s, ""));
} else {
ast_log(LOG_WARNING, "Cannot locate application %s\n", appname);
return -1;
/*!
* \ingroup applications
*/
static int pbx_builtin_wait(struct ast_channel *chan, void *data)
if (data && atof((char *)data)) {
ms = atof((char *)data) * 1000;
/*!
* \ingroup applications
*/
static int pbx_builtin_waitexten(struct ast_channel *chan, void *data)
{
int ms, res;
Mark Spencer
committed
struct ast_flags flags = {0};
char *opts[1] = { NULL };
char *parse;
AST_DECLARE_APP_ARGS(args,
AST_APP_ARG(timeout);
AST_APP_ARG(options);
);
Mark Spencer
committed
if (!ast_strlen_zero(data)) {
if (!(parse = ast_strdupa(data)))
return -1;
AST_STANDARD_APP_ARGS(args, parse);
} else
memset(&args, 0, sizeof(args));
Mark Spencer
committed
if (args.options)
ast_app_parse_options(waitexten_opts, &flags, opts, args.options);
Mark Spencer
committed
if (ast_test_flag(&flags, WAITEXTEN_MOH))
ast_moh_start(chan, opts[0]);
Mark Spencer
committed
if (args.timeout && atof(args.timeout))
ms = atof(args.timeout) * 1000;
else if (chan->pbx)
ms = chan->pbx->rtimeout * 1000;
else
ms = 10000;
res = ast_waitfordigit(chan, ms);
if (!res) {
Mark Spencer
committed
if (ast_exists_extension(chan, chan->context, chan->exten, chan->priority + 1, chan->cid.cid_num)) {
Mark Spencer
committed
ast_verbose(VERBOSE_PREFIX_3 "Timeout on %s, continuing...\n", chan->name);