Newer
Older
ast_string_field_build(tmpchan, name, "AsyncGoto/%s", chan->name);
/* Make formats okay */
tmpchan->readformat = chan->readformat;
tmpchan->writeformat = chan->writeformat;
/* Setup proper location */
ast_explicit_goto(tmpchan,
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)
{
}
/*! \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, *ep = NULL;
int res;
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
4155
4156
4157
4158
4159
4160
4161
4162
4163
4164
4165
4166
4167
4168
4169
4170
4171
4172
4173
4174
4175
4176
4177
4178
/* 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);
}
4200
4201
4202
4203
4204
4205
4206
4207
4208
4209
4210
4211
4212
4213
4214
4215
4216
4217
4218
4219
4220
4221
4222
if (res == 0) {
/* We have an exact match, now we find where we are
and be sure there's no duplicates */
while(e) {
if (e->priority == tmp->priority) {
/* Can't have something exactly the same. Is this a
replacement? If so, replace, otherwise, bonk. */
if (replace) {
if (ep) {
/* We're in the peer list, insert ourselves */
ep->peer = tmp;
tmp->peer = e->peer;
} else if (el) {
/* We're the first extension. Take over e's functions */
el->next = tmp;
tmp->next = e->next;
tmp->peer = e->peer;
} else {
/* We're the very first extension. */
con->root = tmp;
tmp->next = e->next;
tmp->peer = e->peer;
}
if (tmp->priority == PRIORITY_HINT)
ast_change_hint(e,tmp);
/* Destroy the old one */
e->datad(e->data);
free(e);
ast_mutex_unlock(&con->lock);
if (tmp->priority == PRIORITY_HINT)
ast_change_hint(e, tmp);
/* And immediately return success. */
LOG;
return 0;
} else {
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);
ast_mutex_unlock(&con->lock);
return -1;
}
} else if (e->priority > tmp->priority) {
/* Slip ourselves in just before e */
if (ep) {
/* Easy enough, we're just in the peer list */
ep->peer = tmp;
tmp->peer = e;
} else if (el) {
/* We're the first extension in this peer list */
el->next = tmp;
tmp->next = e->next;
e->next = NULL;
tmp->peer = e;
} else {
/* We're the very first extension altogether */
tmp->next = con->root->next;
/* Con->root must always exist or we couldn't get here */
tmp->peer = con->root;
ast_mutex_unlock(&con->lock);
if (tmp->priority == PRIORITY_HINT)
LOG;
return 0;
}
ep = e;
e = e->peer;
}
/* 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->peer = tmp;
ast_mutex_unlock(&con->lock);
if (tmp->priority == PRIORITY_HINT)
/* And immediately return success. */
LOG;
return 0;
} else if (res > 0) {
/* Insert ourselves just before 'e'. We're the first extension of
this kind */
tmp->next = e;
if (el) {
/* We're in the list somewhere */
el->next = tmp;
} else {
/* We're at the top of the list */
con->root = tmp;
}
ast_mutex_unlock(&con->lock);
if (tmp->priority == PRIORITY_HINT)
/* And immediately return success. */
LOG;
return 0;
el = e;
}
/* If we fall all the way through to here, then we need to be on the end. */
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);
static void destroy_exten(struct ast_exten *e)
{
if (e->priority == PRIORITY_HINT)
ast_remove_hint(e);
if (e->datad)
e->datad(e->data);
free(e);
}
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);
4745
4746
4747
4748
4749
4750
4751
4752
4753
4754
4755
4756
4757
4758
4759
4760
4761
4762
4763
4764
4765
4766
4767
4768
4769
4770
4771
4772
4773
4774
4775
4776
4777
4778
for (tmp = contexts; tmp; ) {
struct ast_context *next; /* next starting point */
for (; tmp; tmpl = tmp, tmp = tmp->next) {
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);
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
*/