Newer
Older
{
struct ast_channel *chan;
struct async_stat *as;
struct app_tmp *tmp;
if (!app || !strlen(app))
return -1;
if (sync) {
chan = ast_request_and_dial(type, format, data, timeout, reason, callerid);
if (chan) {
pbx_builtin_setaccount(chan, account);
if (variable) {
vartmp = ast_strdupa(variable);
for (var = strtok_r(vartmp, "|", &vartmp); var; var = strtok_r(NULL, "|", &vartmp)) {
pbx_builtin_setvar( chan, var );
}
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 = malloc(sizeof(struct app_tmp));
if (tmp) {
memset(tmp, 0, sizeof(struct app_tmp));
strncpy(tmp->app, app, sizeof(tmp->app) - 1);
strncpy(tmp->data, appdata, sizeof(tmp->data) - 1);
tmp->chan = chan;
if (sync > 1) {
ast_pbx_run_app(tmp);
} else {
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
if (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_hangup(chan);
res = -1;
}
}
} else {
ast_log(LOG_ERROR, "Out of memory :(\n");
res = -1;
}
} else {
if (option_verbose > 3)
ast_verbose(VERBOSE_PREFIX_4 "Channel %s was never answered.\n", chan->name);
ast_hangup(chan);
}
}
} 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, callerid);
if (!chan) {
free(as);
return -1;
}
pbx_builtin_setaccount(chan, account);
as->chan = chan;
strncpy(as->app, app, sizeof(as->app) - 1);
if (appdata)
strncpy(as->appdata, appdata, sizeof(as->appdata) - 1);
as->timeout = timeout;
/* Start a new thread, and get something handling this channel. */
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
if (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;
}
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);
}
Mark Spencer
committed
void __ast_context_destroy(struct ast_context *con, char *registrar)
struct ast_exten *e, *el, *en;
Mark Spencer
committed
ast_mutex_lock(&conlock);
if (((tmp->name && con && con->name && !strcasecmp(tmp->name, con->name)) || !con) &&
(!registrar || !strcasecmp(registrar, tmp->registrar))) {
/* Okay, let's lock the structure to be sure nobody else
is searching through it. */
if (ast_mutex_lock(&tmp->lock)) {
ast_log(LOG_WARNING, "Unable to lock context lock\n");
return;
}
if (tmpl)
tmpl->next = tmp->next;
else
contexts = tmp->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 */
tmpil = tmpi;
tmpi = tmpi->next;
free(tmpil);
ipl = ipi;
ipi = ipi->next;
free(ipl);
swl = sw;
sw = sw->next;
free(swl);
swl = 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);
}
if (!con) {
/* Might need to get another one -- restart */
tmp = contexts;
tmpl = NULL;
tmpil = NULL;
continue;
}
Mark Spencer
committed
ast_mutex_unlock(&conlock);
return;
}
tmpl = tmp;
tmp = tmp->next;
}
Mark Spencer
committed
ast_mutex_unlock(&conlock);
}
void ast_context_destroy(struct ast_context *con, char *registrar)
{
Mark Spencer
committed
__ast_context_destroy(con,registrar);
4169
4170
4171
4172
4173
4174
4175
4176
4177
4178
4179
4180
4181
4182
4183
4184
4185
4186
4187
4188
4189
4190
4191
4192
4193
4194
4195
4196
4197
4198
4199
4200
4201
4202
4203
static void wait_for_hangup(struct ast_channel *chan)
{
int res;
struct ast_frame *f;
do {
res = ast_waitfor(chan, -1);
if (res < 0)
return;
f = ast_read(chan);
if (f)
ast_frfree(f);
} while(f);
}
static int pbx_builtin_ringing(struct ast_channel *chan, void *data)
{
ast_indicate(chan, AST_CONTROL_RINGING);
return 0;
}
static int pbx_builtin_busy(struct ast_channel *chan, void *data)
{
ast_indicate(chan, AST_CONTROL_BUSY);
wait_for_hangup(chan);
return -1;
}
static int pbx_builtin_congestion(struct ast_channel *chan, void *data)
{
ast_indicate(chan, AST_CONTROL_CONGESTION);
wait_for_hangup(chan);
return -1;
}
static int pbx_builtin_answer(struct ast_channel *chan, void *data)
static int pbx_builtin_setlanguage(struct ast_channel *chan, void *data)
strncpy(chan->language, (char *)data, sizeof(chan->language)-1);
static int pbx_builtin_resetcdr(struct ast_channel *chan, void *data)
{
/* Reset the CDR as specified */
if (data)
ast_cdr_reset(chan->cdr, strchr((char *)data, 'w') ? 1 : 0);
else
ast_cdr_reset(chan->cdr, 0);
return 0;
}
Mark Spencer
committed
static int pbx_builtin_setaccount(struct ast_channel *chan, void *data)
{
/* Copy the language as specified */
if (data)
ast_cdr_setaccount(chan, (char *)data);
else
ast_cdr_setaccount(chan, "");
return 0;
}
static int pbx_builtin_hangup(struct ast_channel *chan, void *data)
{
/* Just return non-zero and it will hang up */
return -1;
}
static int pbx_builtin_stripmsd(struct ast_channel *chan, void *data)
{
char newexten[AST_MAX_EXTENSION] = "";
if (!data || !atoi(data)) {
ast_log(LOG_DEBUG, "Ignoring, since number of digits to strip is 0\n");
return 0;
}
if (strlen(chan->exten) > atoi(data)) {
strncpy(newexten, chan->exten + atoi(data), sizeof(newexten)-1);
strncpy(chan->exten, newexten, sizeof(chan->exten)-1);
static int pbx_builtin_prefix(struct ast_channel *chan, void *data)
{
char newexten[AST_MAX_EXTENSION] = "";
if (!data || !strlen(data)) {
ast_log(LOG_DEBUG, "Ignoring, since there is no prefix to add\n");
return 0;
}
snprintf(newexten, sizeof(newexten), "%s%s", (char *)data, chan->exten);
strncpy(chan->exten, newexten, sizeof(chan->exten)-1);
if (option_verbose > 2)
ast_verbose(VERBOSE_PREFIX_3 "Prepended prefix, new extension is %s\n", chan->exten);
4269
4270
4271
4272
4273
4274
4275
4276
4277
4278
4279
4280
4281
4282
4283
4284
4285
4286
4287
4288
4289
4290
4291
4292
4293
4294
4295
4296
4297
4298
4299
static int pbx_builtin_suffix(struct ast_channel *chan, void *data)
{
char newexten[AST_MAX_EXTENSION] = "";
if (!data || !strlen(data)) {
ast_log(LOG_DEBUG, "Ignoring, since there is no suffix to add\n");
return 0;
}
snprintf(newexten, sizeof(newexten), "%s%s", chan->exten, (char *)data);
strncpy(chan->exten, newexten, sizeof(chan->exten)-1);
if (option_verbose > 2)
ast_verbose(VERBOSE_PREFIX_3 "Appended suffix, new extension is %s\n", chan->exten);
return 0;
}
static int pbx_builtin_gotoiftime(struct ast_channel *chan, void *data)
{
int res=0;
char *s, *ts;
struct ast_include include;
if (!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;
}
s = strdup((char *) data);
ts = s;
/* Separate the Goto path */
strsep(&ts,"?");
// [PHM 07/01/03]
// struct ast_include include contained garbage here, fixed by zeroing it on get_timerange
build_timing(&include, s);
if (include_valid(&include))
res = pbx_builtin_goto(chan, (void *)ts);
free(s);
return res;
}
static int pbx_builtin_wait(struct ast_channel *chan, void *data)
if (data && atof((char *)data)) {
ms = atof((char *)data) * 1000;
static int pbx_builtin_waitexten(struct ast_channel *chan, void *data)
{
int ms;
/* Wait for "n" seconds */
if (data && atof((char *)data)) {
ms = atof((char *)data) * 1000;
return ast_waitfordigit(chan, ms);
}
return 0;
}
static int pbx_builtin_background(struct ast_channel *chan, void *data)
/* Stop anything playing */
ast_stopstream(chan);
/* Stream a file */
res = ast_streamfile(chan, (char *)data, chan->language);
if (!res) {
res = ast_waitstream(chan, AST_DIGIT_ANY);
ast_stopstream(chan);
}
static int pbx_builtin_atimeout(struct ast_channel *chan, void *data)
{
int x = atoi((char *) data);
/* Set the absolute maximum time how long a call can be connected */
ast_channel_setwhentohangup(chan,x);
if (option_verbose > 2)
ast_verbose( VERBOSE_PREFIX_3 "Set Absolute Timeout to %d\n", x);
return 0;
}
static int pbx_builtin_rtimeout(struct ast_channel *chan, void *data)
{
/* Set the timeout for how long to wait between digits */
chan->pbx->rtimeout = atoi((char *)data);
if (option_verbose > 2)
ast_verbose( VERBOSE_PREFIX_3 "Set Response Timeout to %d\n", chan->pbx->rtimeout);
return 0;
}
static int pbx_builtin_dtimeout(struct ast_channel *chan, void *data)
{
/* Set the timeout for how long to wait between digits */
chan->pbx->dtimeout = atoi((char *)data);
if (option_verbose > 2)
ast_verbose( VERBOSE_PREFIX_3 "Set Digit Timeout to %d\n", chan->pbx->dtimeout);
return 0;
}
static int pbx_builtin_goto(struct ast_channel *chan, void *data)
{
char *s;
char *exten, *pri, *context;
char *stringp=NULL;
if (!data || !strlen(data)) {
ast_log(LOG_WARNING, "Goto requires an argument (optional context|optional extension|priority)\n");
return -1;
}
s = ast_strdupa((void *) data);
stringp=s;
context = strsep(&stringp, "|");
exten = strsep(&stringp, "|");
if (!exten) {
/* Only a priority in this one */
pri = context;
exten = NULL;
context = NULL;
} else {
if (!pri) {
/* Only an extension and priority in this one */
pri = exten;
exten = context;
context = NULL;
}
}
if (atoi(pri) < 0) {
ast_log(LOG_WARNING, "Priority '%s' must be a number > 0\n", pri);
return -1;
}
/* At this point we have a priority and maybe an extension and a context */
chan->priority = atoi(pri) - 1;
strncpy(chan->exten, exten, sizeof(chan->exten)-1);
strncpy(chan->context, context, sizeof(chan->context)-1);
if (option_verbose > 2)
ast_verbose( VERBOSE_PREFIX_3 "Goto (%s,%s,%d)\n", chan->context,chan->exten, chan->priority+1);
ast_cdr_update(chan);
char *pbx_builtin_getvar_helper(struct ast_channel *chan, char *name) {
struct ast_var_t *variables;
struct varshead *headp;
if (chan)
headp=&chan->varshead;
else
headp=&globals;
AST_LIST_TRAVERSE(headp,variables,entries) {
if (!strcmp(name, ast_var_name(variables)))
return ast_var_value(variables);
}
if (headp != &globals) {
/* Check global variables if we haven't already */
headp = &globals;
AST_LIST_TRAVERSE(headp,variables,entries) {
if (!strcmp(name, ast_var_name(variables)))
return ast_var_value(variables);
}
}
}
void pbx_builtin_setvar_helper(struct ast_channel *chan, char *name, char *value) {
struct ast_var_t *newvariable;
struct varshead *headp;
AST_LIST_TRAVERSE (headp,newvariable,entries) {
if (strcasecmp(ast_var_name(newvariable),name)==0) {
/* there is already such a variable, delete it */
AST_LIST_REMOVE(headp,newvariable,ast_var_t,entries);
ast_var_delete(newvariable);
break;
}
}
if (value) {
if ((option_verbose > 1) && (headp == &globals))
ast_verbose(VERBOSE_PREFIX_3 "Setting global variable '%s' to '%s'\n",name, value);
newvariable=ast_var_assign(name,value);
AST_LIST_INSERT_HEAD(headp,newvariable,entries);
}
Martin Pycko
committed
int pbx_builtin_setvar(struct ast_channel *chan, void *data)
if (!data || !strlen(data)) {
ast_log(LOG_WARNING, "Ignoring, since there is no variable to set\n");
return 0;
}
stringp=data;
name=strsep(&stringp,"=");
value=strsep(&stringp,"\0");
pbx_builtin_setvar_helper(chan,name,value);
return(0);
}
4491
4492
4493
4494
4495
4496
4497
4498
4499
4500
4501
4502
4503
4504
4505
4506
4507
4508
4509
4510
4511
static int pbx_builtin_setglobalvar(struct ast_channel *chan, void *data)
{
char *name;
char *value;
char *stringp=NULL;
if (!data || !strlen(data)) {
ast_log(LOG_WARNING, "Ignoring, since there is no variable to set\n");
return 0;
}
stringp=data;
name=strsep(&stringp,"=");
value=strsep(&stringp,"\0");
pbx_builtin_setvar_helper(NULL,name,value);
return(0);
}
static int pbx_builtin_noop(struct ast_channel *chan, void *data)
{
return 0;
}
void pbx_builtin_clear_globals(void)
{
struct ast_var_t *vardata;
while (!AST_LIST_EMPTY(&globals)) {
vardata = AST_LIST_FIRST(&globals);
AST_LIST_REMOVE_HEAD(&globals, entries);
ast_var_delete(vardata);
}
}
4528
4529
4530
4531
4532
4533
4534
4535
4536
4537
4538
4539
4540
4541
4542
4543
4544
4545
4546
4547
4548
static int pbx_checkcondition(char *condition) {
char *s;
int ret;
s=strdup(condition);
ret=1;
if ((strcasecmp(s,"0")) || (strlen(s)==0)) {
ret=0;
}
free(s);
return(ret);
}
static int pbx_builtin_gotoif(struct ast_channel *chan, void *data)
{
char *condition,*branch1,*branch2,*branch;
char *s;
int rc;
ast_log(LOG_WARNING, "Ignoring, since there is no variable to check\n");
stringp=s;
condition=strsep(&stringp,"?");
branch1=strsep(&stringp,":");
branch2=strsep(&stringp,"");
if (pbx_checkcondition(condition)) {
branch=branch2;
} else {
branch=branch1;
}
if ((branch==NULL) || (strlen(branch)==0)) {
ast_log(LOG_NOTICE, "Not taking any branch\n");
return(0);
}
rc=pbx_builtin_goto(chan,branch);
free(s);
return(rc);
}
static int pbx_builtin_saynumber(struct ast_channel *chan, void *data)
{
int res = 0;
Mark Spencer
committed
4581
4582
4583
4584
4585
4586
4587
4588
4589
4590
4591
4592
4593
4594
4595
4596
4597
4598
4599
4600
4601
4602
4603
char tmp[256];
char *number = (char *) NULL;
char *options = (char *) NULL;
if (!data || !strlen((char *)data)) {
ast_log(LOG_WARNING, "SayNumber requires an argument (number)\n");
return -1;
}
strncpy(tmp, (char *)data, sizeof(tmp)-1);
number=tmp;
strsep(&number, "|");
options = strsep(&number, "|");
if (options) {
if ( strcasecmp(options, "f") && strcasecmp(options,"m") &&
strcasecmp(options, "c") && strcasecmp(options, "n") ) {
ast_log(LOG_WARNING, "SayNumber gender option is either 'f', 'm', 'c' or 'n'\n");
return -1;
}
}
return res = ast_say_number(chan, atoi((char *) tmp), "", chan->language, options);
}
static int pbx_builtin_saydigits(struct ast_channel *chan, void *data)
{
int res = 0;
if (data)
res = ast_say_digit_str(chan, (char *)data, "", chan->language);
static int pbx_builtin_saycharacters(struct ast_channel *chan, void *data)
{
int res = 0;
if (data)
res = ast_say_character_str(chan, (char *)data, "", chan->language);
return res;
}
static int pbx_builtin_sayphonetic(struct ast_channel *chan, void *data)
{
int res = 0;
if (data)
res = ast_say_phonetic_str(chan, (char *)data, "", chan->language);
return res;
}
int load_pbx(void)
{
int x;
/* Initialize the PBX */
if (option_verbose) {
ast_verbose( "Asterisk PBX Core Initializing\n");
ast_verbose( "Registering builtin applications:\n");
}
ast_cli_register(&show_applications_cli);
ast_cli_register(&show_application_cli);
ast_cli_register(&show_dialplan_cli);
ast_cli_register(&show_switches_cli);
for (x=0;x<sizeof(builtins) / sizeof(struct pbx_builtin); x++) {
if (option_verbose)
ast_verbose( VERBOSE_PREFIX_1 "[%s]\n", builtins[x].name);
if (ast_register_application(builtins[x].name, builtins[x].execute, builtins[x].synopsis, builtins[x].description)) {
ast_log(LOG_ERROR, "Unable to register builtin application '%s'\n", builtins[x].name);
return -1;
}
}
return 0;
}
/*
* Lock context list functions ...
*/
int ast_lock_contexts()
{
return ast_mutex_lock(&conlock);
return ast_mutex_unlock(&conlock);
}
/*
* Lock context ...
*/
int ast_lock_context(struct ast_context *con)
{
return ast_mutex_lock(&con->lock);
}
int ast_unlock_context(struct ast_context *con)
{
return ast_mutex_unlock(&con->lock);
4677
4678
4679
4680
4681
4682
4683
4684
4685
4686
4687
4688
4689
4690
4691
4692
4693
4694
4695
4696
4697
4698
4699
4700
4701
4702
4703
4704
4705
4706
4707
4708
4709
4710
4711
4712
4713
4714
4715
4716
4717
4718
4719
4720
4721
4722
4723
4724
4725
4726
4727
4728
4729
4730
4731
4732
4733
4734
4735
4736
4737
4738
4739
4740
4741
4742
4743
4744
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
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
}
/*
* Name functions ...
*/
char *ast_get_context_name(struct ast_context *con)
{
return con ? con->name : NULL;
}
char *ast_get_extension_name(struct ast_exten *exten)
{
return exten ? exten->exten : NULL;
}
char *ast_get_include_name(struct ast_include *inc)
{
return inc ? inc->name : NULL;
}
char *ast_get_ignorepat_name(struct ast_ignorepat *ip)
{
return ip ? ip->pattern : NULL;
}
int ast_get_extension_priority(struct ast_exten *exten)
{
return exten ? exten->priority : -1;
}
/*
* Registrar info functions ...
*/
char *ast_get_context_registrar(struct ast_context *c)
{
return c ? c->registrar : NULL;
}
char *ast_get_extension_registrar(struct ast_exten *e)
{
return e ? e->registrar : NULL;
}
char *ast_get_include_registrar(struct ast_include *i)
{
return i ? i->registrar : NULL;
}
char *ast_get_ignorepat_registrar(struct ast_ignorepat *ip)
{
return ip ? ip->registrar : NULL;
}
char *ast_get_extension_app(struct ast_exten *e)
{
return e ? e->app : NULL;
}
void *ast_get_extension_app_data(struct ast_exten *e)
{
return e ? e->data : NULL;
}
char *ast_get_switch_name(struct ast_sw *sw)
{
return sw ? sw->name : NULL;
}
char *ast_get_switch_data(struct ast_sw *sw)
{
return sw ? sw->data : NULL;
}
char *ast_get_switch_registrar(struct ast_sw *sw)
{
return sw ? sw->registrar : NULL;
}
/*
* Walking functions ...
*/
struct ast_context *ast_walk_contexts(struct ast_context *con)
{
if (!con)
return contexts;
else
return con->next;
}
struct ast_exten *ast_walk_context_extensions(struct ast_context *con,
struct ast_exten *exten)
{
if (!exten)
return con ? con->root : NULL;
else
return exten->next;
}
struct ast_sw *ast_walk_context_switches(struct ast_context *con,
struct ast_sw *sw)
{
if (!sw)
return con ? con->alts : NULL;
else
return sw->next;
}
struct ast_exten *ast_walk_extension_priorities(struct ast_exten *exten,
struct ast_exten *priority)
{
if (!priority)
return exten;
else
return priority->peer;
}
struct ast_include *ast_walk_context_includes(struct ast_context *con,
struct ast_include *inc)
{
if (!inc)
return con ? con->includes : NULL;
else
return inc->next;
}
struct ast_ignorepat *ast_walk_context_ignorepats(struct ast_context *con,
struct ast_ignorepat *ip)
{
if (!ip)
return con ? con->ignorepats : NULL;
else
return ip->next;
}
int ast_context_verify_includes(struct ast_context *con)
{
struct ast_include *inc;
int res = 0;
for (inc = ast_walk_context_includes(con, NULL); inc; inc = ast_walk_context_includes(con, inc))
if (!ast_context_find(inc->rname)) {
res = -1;
ast_log(LOG_WARNING, "Context '%s' tries includes non-existant context '%s'\n",
ast_get_context_name(con), inc->rname);
}
return res;
}