Newer
Older
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;
}
4014
4015
4016
4017
4018
4019
4020
4021
4022
4023
4024
4025
4026
4027
4028
4029
4030
4031
4032
4033
4034
4035
4036
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;
}
Martin Pycko
committed
int ast_pbx_outgoing_app(char *type, int format, void *data, int timeout, char *app, char *appdata, int *reason, int sync, char *callerid, char *variable, char *account)
{
struct ast_channel *chan;
struct async_stat *as;
struct app_tmp *tmp;
if (!app || ast_strlen_zero(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;
vartmp = ast_strdupa(variable);
for (var = strtok_r(vartmp, "|", &vartmp); var; var = strtok_r(NULL, "|", &vartmp))
pbx_builtin_setvar( chan, var );
/* 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);
}
Mark Spencer
committed
ast_mutex_destroy(&tmp->lock);
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);
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_progress(struct ast_channel *chan, void *data)
{
ast_indicate(chan, AST_CONTROL_PROGRESS);
return 0;
}
4232
4233
4234
4235
4236
4237
4238
4239
4240
4241
4242
4243
4244
4245
4246
4247
4248
4249
4250
4251
4252
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 account code as specified */
Mark Spencer
committed
if (data)
ast_cdr_setaccount(chan, (char *)data);
else
ast_cdr_setaccount(chan, "");
return 0;
}
static int pbx_builtin_setamaflags(struct ast_channel *chan, void *data)
{
/* Copy the AMA Flags as specified */
if (data)
ast_cdr_setamaflags(chan, (char *)data);
else
ast_cdr_setamaflags(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)
if (!data || ast_strlen_zero(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);
static int pbx_builtin_suffix(struct ast_channel *chan, void *data)
{
char newexten[AST_MAX_EXTENSION] = "";
if (!data || ast_strlen_zero(data)) {
4332
4333
4334
4335
4336
4337
4338
4339
4340
4341
4342
4343
4344
4345
4346
4347
4348
4349
4350
4351
4352
4353
4354
4355
4356
4357
4358
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;
if (!data || ast_strlen_zero(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;
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 varshead *headp;
if (chan)
headp=&chan->varshead;
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 || ast_strlen_zero(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);
}
static int pbx_builtin_setglobalvar(struct ast_channel *chan, void *data)
{
char *name;
char *value;
char *stringp=NULL;
if (!data || ast_strlen_zero(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);
}
}
static int pbx_checkcondition(char *condition)
{
char *s;
int ret;
s=strdup(condition);
ret=1;
if ((strcasecmp(s,"0")) || ast_strlen_zero(s)) {
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;
if (!data || ast_strlen_zero(data)) {
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) || ast_strlen_zero(branch)) {
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
char tmp[256];
char *number = (char *) NULL;
char *options = (char *) NULL;
if (!data || ast_strlen_zero((char *)data)) {
Mark Spencer
committed
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);
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
4810
4811
4812
4813
4814
4815
4816
4817
4818
4819
4820
4821
4822
4823
4824
4825
4826
4827
4828
4829
4830
4831
4832
4833
4834
4835
4836
4837
4838
4839
4840
4841
4842
4843
4844
4845
4846
4847
4848
4849
4850
4851
4852
4853
4854
4855
4856
4857
4858
4859
4860
4861
4862
4863
4864
4865
4866
4867
4868
4869
4870
}
/*
* 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;
}