Newer
Older
/* If we got this far, then we're good */
return 1;
/*
* errno values
* ENOMEM - out of memory
* EBUSY - can't lock
* EEXIST - already included
* EINVAL - there is no existence of context for inclusion
*/
int ast_context_add_include2(struct ast_context *con, const char *value,
const char *registrar)
struct ast_include *i, *il = NULL; /* include, include_last */
int length;
char *p;
length = sizeof(struct ast_include);
length += 2 * (strlen(value) + 1);
if (!(new_include = malloc(length))) {
ast_log(LOG_ERROR, "Out of memory\n");
errno = ENOMEM;
return -1;
}
/* ... fill in this structure ... */
memset(new_include, 0, length);
p = new_include->stuff;
new_include->name = p;
strcpy(new_include->name, value);
p += strlen(value) + 1;
new_include->rname = p;
strcpy(new_include->rname, value);
c = new_include->rname;
/* Strip off timing info */
while(*c && (*c != '|'))
c++;
new_include->hastime = ast_build_timing(&(new_include->timing), c+1);
new_include->next = NULL;
new_include->registrar = registrar;
/* ... try to lock this context ... */
if (ast_mutex_lock(&con->lock)) {
free(new_include);
errno = EBUSY;
return -1;
}
/* ... go to last include and check if context is already included too... */
i = con->includes;
while (i) {
if (!strcasecmp(i->name, new_include->name)) {
free(new_include);
ast_mutex_unlock(&con->lock);
errno = EEXIST;
return -1;
}
il = i;
i = i->next;
}
/* ... include new context into context list, unlock, return */
if (il)
il->next = new_include;
else
con->includes = new_include;
if (option_verbose > 2)
ast_verbose(VERBOSE_PREFIX_3 "Including context '%s' in context '%s'\n", new_include->name, ast_get_context_name(con));
ast_mutex_unlock(&con->lock);
return 0;
}
/*
* errno values
* EBUSY - can't lock
int ast_context_add_switch(const char *context, const char *sw, const char *data, int eval, const char *registrar)
{
struct ast_context *c;
if (ast_lock_contexts()) {
errno = EBUSY;
return -1;
}
/* walk contexts ... */
c = ast_walk_contexts(NULL);
while (c) {
/* ... search for the right one ... */
if (!strcmp(ast_get_context_name(c), context)) {
int ret = ast_context_add_switch2(c, sw, data, eval, registrar);
/* ... unlock contexts list and return */
ast_unlock_contexts();
return ret;
}
c = ast_walk_contexts(c);
}
/* we can't find the right context */
ast_unlock_contexts();
return -1;
}
/*
* errno values
* ENOMEM - out of memory
* EBUSY - can't lock
* EEXIST - already included
* EINVAL - there is no existence of context for inclusion
*/
int ast_context_add_switch2(struct ast_context *con, const char *value,
const char *data, int eval, const char *registrar)
struct ast_sw *new_sw;
struct ast_sw *i, *il = NULL; /* sw, sw_last */
int length;
char *p;
length = sizeof(struct ast_sw);
length += strlen(value) + 1;
if (data)
length += strlen(data);
length++;
if (eval) {
/* Create buffer for evaluation of variables */
length += SWITCH_DATA_LENGTH;
length++;
}
if (!(new_sw = malloc(length))) {
ast_log(LOG_ERROR, "Out of memory\n");
memset(new_sw, 0, length);
p = new_sw->stuff;
new_sw->name = p;
strcpy(new_sw->name, value);
p += strlen(value) + 1;
new_sw->data = p;
if (data) {
strcpy(new_sw->data, data);
p += strlen(data) + 1;
} else {
strcpy(new_sw->data, "");
p++;
}
if (eval)
new_sw->tmpdata = p;
new_sw->eval = eval;
new_sw->registrar = registrar;
/* ... try to lock this context ... */
if (ast_mutex_lock(&con->lock)) {
free(new_sw);
errno = EBUSY;
return -1;
}
/* ... go to last sw and check if context is already swd too... */
i = con->alts;
while (i) {
if (!strcasecmp(i->name, new_sw->name) && !strcasecmp(i->data, new_sw->data)) {
ast_mutex_unlock(&con->lock);
errno = EEXIST;
return -1;
}
il = i;
i = i->next;
}
/* ... sw new context into context list, unlock, return */
if (il)
il->next = new_sw;
else
con->alts = new_sw;
if (option_verbose > 2)
ast_verbose(VERBOSE_PREFIX_3 "Including switch '%s/%s' in context '%s'\n", new_sw->name, new_sw->data, ast_get_context_name(con));
ast_mutex_unlock(&con->lock);
return 0;
}
/*
* EBUSY - can't lock
int ast_context_remove_ignorepat(const char *context, const char *ignorepat, const char *registrar)
{
struct ast_context *c;
if (ast_lock_contexts()) {
errno = EBUSY;
return -1;
}
c = ast_walk_contexts(NULL);
while (c) {
if (!strcmp(ast_get_context_name(c), context)) {
int ret = ast_context_remove_ignorepat2(c, ignorepat, registrar);
ast_unlock_contexts();
return ret;
}
c = ast_walk_contexts(c);
}
ast_unlock_contexts();
int ast_context_remove_ignorepat2(struct ast_context *con, const char *ignorepat, const char *registrar)
{
struct ast_ignorepat *ip, *ipl = NULL;
if (ast_mutex_lock(&con->lock)) {
errno = EBUSY;
return -1;
}
ip = con->ignorepats;
while (ip) {
if (!strcmp(ip->pattern, ignorepat) &&
Mark Spencer
committed
(!registrar || (registrar == ip->registrar))) {
if (ipl) {
ipl->next = ip->next;
free(ip);
} else {
con->ignorepats = ip->next;
free(ip);
}
ast_mutex_unlock(&con->lock);
return 0;
}
ipl = ip; ip = ip->next;
}
ast_mutex_unlock(&con->lock);
errno = EINVAL;
return -1;
}
/*
* EBUSY - can't lock
int ast_context_add_ignorepat(const char *con, const char *value, const char *registrar)
{
struct ast_context *c;
if (ast_lock_contexts()) {
errno = EBUSY;
return -1;
}
c = ast_walk_contexts(NULL);
while (c) {
if (!strcmp(ast_get_context_name(c), con)) {
int ret = ast_context_add_ignorepat2(c, value, registrar);
ast_unlock_contexts();
return ret;
}
c = ast_walk_contexts(c);
}
ast_unlock_contexts();
int ast_context_add_ignorepat2(struct ast_context *con, const char *value, const char *registrar)
{
struct ast_ignorepat *ignorepat, *ignorepatc, *ignorepatl = NULL;
int length;
length = sizeof(struct ast_ignorepat);
length += strlen(value) + 1;
ignorepat = malloc(length);
ast_log(LOG_ERROR, "Out of memory\n");
memset(ignorepat, 0, length);
strcpy(ignorepat->pattern, value);
ignorepat->next = NULL;
ignorepat->registrar = registrar;
ast_mutex_lock(&con->lock);
ignorepatc = con->ignorepats;
while(ignorepatc) {
ignorepatl = ignorepatc;
if (!strcasecmp(ignorepatc->pattern, value)) {
ast_mutex_unlock(&con->lock);
if (ignorepatl)
ignorepatl->next = ignorepat;
ast_mutex_unlock(&con->lock);
int ast_ignore_pattern(const char *context, const char *pattern)
{
struct ast_context *con;
struct ast_ignorepat *pat;
con = ast_context_find(context);
if (con) {
pat = con->ignorepats;
while (pat) {
if (ast_extension_match(pat->pattern, pattern))
return 1;
pat = pat->next;
}
}
return 0;
}
/*
* EBUSY - can't lock
int ast_add_extension(const char *context, int replace, const char *extension, int priority, const char *label, const char *callerid,
const char *application, void *data, void (*datad)(void *), const char *registrar)
{
struct ast_context *c;
if (ast_lock_contexts()) {
errno = EBUSY;
return -1;
}
c = ast_walk_contexts(NULL);
while (c) {
if (!strcmp(context, ast_get_context_name(c))) {
int ret = ast_add_extension2(c, replace, extension, priority, label, callerid,
application, data, datad, registrar);
ast_unlock_contexts();
return ret;
}
c = ast_walk_contexts(c);
}
ast_unlock_contexts();
int ast_explicit_goto(struct ast_channel *chan, const char *context, const char *exten, int priority) {
if (context && !ast_strlen_zero(context))
strncpy(chan->context, context, sizeof(chan->context) - 1);
if (exten && !ast_strlen_zero(exten))
strncpy(chan->exten, exten, sizeof(chan->context) - 1);
if(priority > -1)
chan->priority = priority;
return 0;
}
return -1;
}
int ast_async_goto(struct ast_channel *chan, const char *context, const char *exten, int priority)
Mark Spencer
committed
ast_mutex_lock(&chan->lock);
if (chan->pbx) {
/* This channel is currently in the PBX */
ast_explicit_goto(chan, context, exten, priority - 1);
ast_softhangup_nolock(chan, AST_SOFTHANGUP_ASYNCGOTO);
} else {
/* In order to do it when the channel doesn't really exist within
the PBX, we have to make a new channel, masquerade, and start the PBX
at the new location */
struct ast_channel *tmpchan;
tmpchan = ast_channel_alloc(0);
if (tmpchan) {
snprintf(tmpchan->name, sizeof(tmpchan->name), "AsyncGoto/%s", chan->name);
/* Make formats okay */
tmpchan->readformat = chan->readformat;
tmpchan->writeformat = chan->writeformat;
/* Setup proper location */
ast_explicit_goto(tmpchan,
(context && !ast_strlen_zero(context)) ? context : chan->context,
(exten && !ast_strlen_zero(exten)) ? exten : chan->exten,
/* Masquerade into temp channel */
ast_channel_masquerade(tmpchan, chan);
/* Grab the locks and get going */
ast_mutex_lock(&tmpchan->lock);
Mark Spencer
committed
ast_do_masquerade(tmpchan);
ast_mutex_unlock(&tmpchan->lock);
/* 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;
}
} else {
res = -1;
}
}
Mark Spencer
committed
ast_mutex_unlock(&chan->lock);
int ast_async_goto_by_name(const char *channame, const char *context, const char *exten, int priority)
int res = -1;
chan = ast_channel_walk_locked(NULL);
while(chan) {
if (!strcasecmp(channame, chan->name))
break;
ast_mutex_unlock(&chan->lock);
chan = ast_channel_walk_locked(chan);
if (chan) {
res = ast_async_goto(chan, context, exten, priority);
ast_mutex_unlock(&chan->lock);
}
return res;
static int ext_strncpy(char *dst, const char *src, int len)
while(*src && (count < len - 1)) {
switch(*src) {
case ' ':
/* otherwise exten => [a-b],1,... doesn't work */
/* case '-': */
/* Ignore */
break;
default:
*dst = *src;
dst++;
}
src++;
count++;
}
*dst = '\0';
}
/*
* EBUSY - can't lock
* EEXIST - extension with the same priority exist and no replace is set
*
*/
int 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;
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
length ++;
/* Be optimistic: Build the extension structure first */
tmp = malloc(length);
memset(tmp, 0, length);
p = tmp->stuff;
if (label) {
tmp->label = p;
strcpy(tmp->label, label);
p += strlen(label) + 1;
}
tmp->exten = p;
p += ext_strncpy(tmp->exten, extension, strlen(extension) + 1) + 1;
tmp->cidmatch = p;
p += ext_strncpy(tmp->cidmatch, callerid, strlen(callerid) + 1) + 1;
tmp->cidmatch[0] = '\0';
tmp->app = p;
strcpy(tmp->app, application);
tmp->parent = con;
tmp->peer = NULL;
tmp->next = NULL;
} else {
ast_log(LOG_ERROR, "Out of memory\n");
if (ast_mutex_lock(&con->lock)) {
free(tmp);
/* And properly destroy the data */
datad(data);
ast_log(LOG_WARNING, "Failed to lock context '%s'\n", con->name);
return -1;
}
e = con->root;
while(e) {
/* Make sure patterns are always last! */
if ((e->exten[0] != '_') && (extension[0] == '_'))
res = -1;
else if ((e->exten[0] == '_') && (extension[0] != '_'))
res = 1;
else
res= strcmp(e->exten, extension);
if (!res) {
if (!e->matchcid && !tmp->matchcid)
res = 0;
else if (tmp->matchcid && !e->matchcid)
res = 1;
else if (e->matchcid && !tmp->matchcid)
res = -1;
else
res = strcasecmp(e->cidmatch, tmp->cidmatch);
}
4585
4586
4587
4588
4589
4590
4591
4592
4593
4594
4595
4596
4597
4598
4599
4600
4601
4602
4603
4604
4605
4606
4607
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;
e = e->next;
}
/* 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_EXTENSION];
char exten[AST_MAX_EXTENSION];
int priority;
int timeout;
char app[AST_MAX_EXTENSION];
};
static void *async_wait(void *data)
{
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)) {
res = ast_waitfor(chan, timeout);
if (res < 1)
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 "Lauching %s(%s) on %s\n", as->app, as->appdata, chan->name);
pbx_exec(chan, app, as->appdata, 1);
} else
ast_log(LOG_WARNING, "No such application '%s'\n", as->app);
if (!ast_strlen_zero(as->context))
strncpy(chan->context, as->context, sizeof(chan->context) - 1);
if (!ast_strlen_zero(as->exten))
strncpy(chan->exten, as->exten, sizeof(chan->exten) - 1);
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;
}
4772
4773
4774
4775
4776
4777
4778
4779
4780
4781
4782
4783
4784
4785
4786
4787
4788
4789
4790
4791
4792
4793
4794
4795
4796
4797
4798
4799
4800
4801
4802
4803
4804
4805
4806
4807
4808
4809
/*! Function to update the cdr after a spool call fails.
*
* This function updates the cdr for a failed spool call
* and takes the channel of the failed call as an argument.
*
* \param chan the channel for the failed call.
*/
int ast_pbx_outgoing_cdr_failed(void)
{
/* allocate a channel */
struct ast_channel *chan = ast_channel_alloc(0);
if(!chan) {
/* allocation of the channel failed, let some peeps know */
ast_log(LOG_WARNING, "Unable to allocate channel structure for CDR record\n");
return -1; /* failure */
}
chan->cdr = ast_cdr_alloc(); /* allocate a cdr for the channel */
if(!chan->cdr) {
/* allocation of the cdr failed */
ast_log(LOG_WARNING, "Unable to create Call Detail Record\n");
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_post(chan->cdr); /* post the record */
ast_cdr_free(chan->cdr); /* free the cdr */
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, const char *variable, 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_mutex_lock(&chan->lock);
}
if (account)
ast_cdr_setaccount(chan, account);
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 */
ast_log(LOG_WARNING, "Unable to create Call Detail Record\n");
free(chan->pbx);
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);
}
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_log(LOG_ERROR, "Unable to run PBX on %s\n", chan->name);
ast_hangup(chan);
res = -1;
}
} else {
if (ast_pbx_start(chan)) {
ast_log(LOG_ERROR, "Unable to start PBX on %s\n", chan->name);
} 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)
return cdr_res;
}
/* 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 (context && !ast_strlen_zero(context))
strncpy(chan->context, context, sizeof(chan->context) - 1);
strncpy(chan->exten, "failed", sizeof(chan->exten) - 1);
chan->priority = 1;
if (variable) {
tmp = ast_strdupa(variable);
for (var = strtok_r(tmp, "|", &tmp); var; var = strtok_r(NULL, "|", &tmp)) {
pbx_builtin_setvar( chan, var );
}
}
ast_log(LOG_WARNING, "Can't allocate the channel structure, skipping execution of extension 'failed'\n");
}
}
} else {
as = malloc(sizeof(struct async_stat));
if (!as)
return -1;
memset(as, 0, sizeof(struct async_stat));
chan = ast_request_and_dial(type, format, data, timeout, reason, cid_num, cid_name);
if (channel) {
*channel = chan;
if (chan)
ast_mutex_lock(&chan->lock);
}
if (!chan) {
free(as);
return -1;
}
if (account)
ast_cdr_setaccount(chan, account);
as->chan = chan;
strncpy(as->context, context, sizeof(as->context) - 1);
strncpy(as->exten, exten, sizeof(as->exten) - 1);
as->priority = priority;
as->timeout = timeout;
if (variable) {
tmp = ast_strdupa(variable);
for (var = strtok_r(tmp, "|", &tmp); var; var = strtok_r(NULL, "|", &tmp))
pbx_builtin_setvar( chan, var );
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);
ast_hangup(chan);
return -1;
}
res = 0;
}
return res;
}
4949
4950
4951
4952
4953
4954
4955
4956
4957
4958
4959
4960
4961
4962
4963
4964
4965
4966
4967
4968
4969
4970
4971
struct app_tmp {
char app[256];
char data[256];
struct ast_channel *chan;
pthread_t t;
};
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 "Lauching %s(%s) on %s\n", tmp->app, tmp->data, tmp->chan->name);
pbx_exec(tmp->chan, app, tmp->data, 1);
} 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, const char *variable, const char *account, struct ast_channel **locked_channel)
{
struct ast_channel *chan;
struct async_stat *as;
struct app_tmp *tmp;
if (locked_channel)
*locked_channel = NULL;
if (!app || ast_strlen_zero(app))
chan = ast_request_and_dial(type, format, data, timeout, reason, cid_num, cid_name);
if (account)
ast_cdr_setaccount(chan, account);
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 */
ast_log(LOG_WARNING, "Unable to create Call Detail Record\n");
free(chan->pbx);
return -1; /* return failure */
}