Newer
Older
if (c) {
if (sscanf(c, "%d", &e) != 1) {
ast_log(LOG_WARNING, "Invalid day '%s', assuming none\n", c);
return 0;
}
if ((e < 1) || (e > 31)) {
ast_log(LOG_WARNING, "Invalid day '%s', assuming none\n", c);
return 0;
}
e--;
} else
e = s;
mask = 0;
4015
4016
4017
4018
4019
4020
4021
4022
4023
4024
4025
4026
4027
4028
4029
4030
4031
4032
4033
4034
4035
4036
4037
4038
4039
4040
4041
4042
mask |= (1 << x);
}
mask |= (1 << x);
return mask;
}
static char *months[] =
{
"jan",
"feb",
"mar",
"apr",
"may",
"jun",
"jul",
"aug",
"sep",
"oct",
"nov",
"dec",
};
static unsigned int get_month(char *mon)
{
char *c;
/* The following line is coincidence, really! */
int s, e, x;
unsigned int mask;
if (ast_strlen_zero(mon) || !strcmp(mon, "*"))
4046
4047
4048
4049
4050
4051
4052
4053
4054
4055
4056
4057
4058
4059
4060
4061
4062
4063
4064
4065
4066
4067
4068
4069
return (1 << 12) - 1;
/* Get start and ending days */
c = strchr(mon, '-');
if (c) {
*c = '\0';
c++;
}
/* Find the start */
s = 0;
while((s < 12) && strcasecmp(mon, months[s])) s++;
if (s >= 12) {
ast_log(LOG_WARNING, "Invalid month '%s', assuming none\n", mon);
return 0;
}
if (c) {
e = 0;
while((e < 12) && strcasecmp(mon, months[e])) e++;
if (e >= 12) {
ast_log(LOG_WARNING, "Invalid month '%s', assuming none\n", c);
return 0;
}
} else
e = s;
mask = 0;
mask |= (1 << x);
}
/* One last one */
mask |= (1 << x);
return mask;
}
int ast_build_timing(struct ast_timing *i, char *info_in)
char info_save[256];
char *info;
if (ast_strlen_zero(info_in))
return 0;
/* make a copy just in case we were passed a static string */
ast_copy_string(info_save, info_in, sizeof(info_save));
/* Assume everything except time */
i->monthmask = (1 << 12) - 1;
i->daymask = (1 << 30) - 1 + (1 << 30);
i->dowmask = (1 << 7) - 1;
FIND_NEXT;
/* Info has the time range, start with that */
get_timerange(i, info);
info = c;
if (!info)
FIND_NEXT;
/* Now check for day of week */
i->dowmask = get_dow(info);
info = c;
if (!info)
FIND_NEXT;
/* Now check for the day of the month */
i->daymask = get_day(info);
info = c;
if (!info)
FIND_NEXT;
/* And finally go for the month */
i->monthmask = get_month(info);
4117
4118
4119
4120
4121
4122
4123
4124
4125
4126
4127
4128
4129
4130
4131
4132
4133
4134
4135
4136
4137
4138
4139
4140
4141
4142
4143
4144
4145
4146
4147
4148
4149
4150
4151
4152
4153
4154
4155
return 1;
}
int ast_check_timing(struct ast_timing *i)
{
struct tm tm;
time_t t;
time(&t);
localtime_r(&t,&tm);
/* If it's not the right month, return */
if (!(i->monthmask & (1 << tm.tm_mon))) {
return 0;
}
/* If it's not that time of the month.... */
/* Warning, tm_mday has range 1..31! */
if (!(i->daymask & (1 << (tm.tm_mday-1))))
return 0;
/* If it's not the right day of the week */
if (!(i->dowmask & (1 << tm.tm_wday)))
return 0;
/* Sanity check the hour just to be safe */
if ((tm.tm_hour < 0) || (tm.tm_hour > 23)) {
ast_log(LOG_WARNING, "Insane time...\n");
return 0;
}
/* Now the tough part, we calculate if it fits
in the right time based on min/hour */
if (!(i->minmask[tm.tm_hour] & (1 << (tm.tm_min / 2))))
return 0;
/* 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();
Kevin P. Fleming
committed
int ast_explicit_goto(struct ast_channel *chan, const char *context, const char *exten, int priority)
{
if (!chan)
return -1;
if (!ast_strlen_zero(context))
ast_copy_string(chan->context, context, sizeof(chan->context));
if (!ast_strlen_zero(exten))
ast_copy_string(chan->exten, exten, sizeof(chan->exten));
Kevin P. Fleming
committed
if (priority > -1) {
chan->priority = priority;
/* see flag description in channel.h for explanation */
if (ast_test_flag(chan, AST_FLAG_IN_AUTOLOOP))
chan->priority--;
Kevin P. Fleming
committed
return 0;
int ast_async_goto(struct ast_channel *chan, const char *context, const char *exten, int priority)
Kevin P. Fleming
committed
Mark Spencer
committed
ast_mutex_lock(&chan->lock);
if (chan->pbx) {
/* This channel is currently in the PBX */
Kevin P. Fleming
committed
ast_explicit_goto(chan, context, exten, priority);
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,
(!ast_strlen_zero(context)) ? context : chan->context,
(!ast_strlen_zero(exten)) ? exten : chan->exten,
Kevin P. Fleming
committed
priority);
/* 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)
Kevin P. Fleming
committed
chan = ast_get_channel_by_name_locked(channame);
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';
static void null_datad(void *foo)
{
}
/*
* 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 */
if (datad == NULL)
datad = null_datad;
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);
}
4743
4744
4745
4746
4747
4748
4749
4750
4751
4752
4753
4754
4755
4756
4757
4758
4759
4760
4761
4762
4763
4764
4765
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_CONTEXT];
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 "Launching %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))
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;
}
4930
4931
4932
4933
4934
4935
4936
4937
4938
4939
4940
4941
4942
4943
4944
4945
4946
4947
4948
4949
4950
4951
4952
4953
4954
4955
4956
4957
4958
4959
/*! 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.
*
*/
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_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, 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(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);
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;