Newer
Older
/* 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;
/* Con->root must always exist or we couldn't get here */
tmp->peer = con->root->peer;
con->root = tmp;
}
/* And immediately return success. */
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;
/* 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;
}
/* 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;
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 (strlen(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 (strlen(as->context))
strncpy(chan->context, as->context, sizeof(chan->context) - 1);
if (strlen(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_WARNING, "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;
}
int ast_pbx_outgoing_exten(char *type, int format, void *data, int timeout, char *context, char *exten, int priority, int *reason, int sync, char *callerid, char *variable )
{
struct ast_channel *chan;
struct async_stat *as;
int res = -1;
chan = ast_request_and_dial(type, format, data, timeout, reason, callerid);
/* JDG chanvar */
tmp = variable;
/* FIXME replace this call with strsep NOT*/
while( (var = strtok_r(NULL, "|", &tmp)) ) {
pbx_builtin_setvar( chan, var );
} /* /JDG */
if (chan->_state == AST_STATE_UP) {
res = 0;
if (option_verbose > 3)
ast_verbose(VERBOSE_PREFIX_4 "Channel %s was answered.\n", chan->name);
if (context && strlen(context))
strncpy(chan->context, context, sizeof(chan->context) - 1);
if (exten && strlen(exten))
strncpy(chan->exten, exten, sizeof(chan->exten) - 1);
if (priority > 0)
chan->priority = priority;
if (sync > 1) {
if (ast_pbx_run(chan)) {
ast_log(LOG_WARNING, "Unable to run PBX on %s\n", chan->name);
ast_hangup(chan);
res = -1;
}
} else {
if (ast_pbx_start(chan)) {
ast_log(LOG_WARNING, "Unable to start PBX on %s\n", chan->name);
ast_hangup(chan);
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, 0, reason, callerid);
if (!chan) {
free(as);
return -1;
}
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 (pthread_create(&as->p, NULL, async_wait, as)) {
ast_log(LOG_WARNING, "Failed to start async wait\n");
free(as);
ast_hangup(chan);
return -1;
}
res = 0;
}
return res;
}
3203
3204
3205
3206
3207
3208
3209
3210
3211
3212
3213
3214
3215
3216
3217
3218
3219
3220
3221
3222
3223
3224
3225
3226
3227
3228
3229
3230
3231
3232
3233
3234
3235
3236
3237
3238
3239
3240
3241
3242
3243
3244
3245
3246
3247
3248
3249
3250
3251
3252
3253
3254
3255
3256
3257
3258
3259
3260
3261
3262
3263
3264
3265
3266
3267
3268
3269
3270
3271
3272
3273
3274
3275
3276
3277
3278
3279
3280
3281
3282
3283
3284
3285
3286
3287
3288
3289
3290
3291
3292
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(char *type, int format, void *data, int timeout, char *app, char *appdata, int *reason, int sync, char *callerid)
{
struct ast_channel *chan;
struct async_stat *as;
struct app_tmp *tmp;
int res = -1;
if (!app || !strlen(app))
return -1;
if (sync) {
chan = ast_request_and_dial(type, format, data, timeout, reason, callerid);
if (chan) {
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 {
if (pthread_create(&tmp->t, NULL, 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_WARNING, "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, 0, reason, callerid);
if (!chan) {
free(as);
return -1;
}
as->chan = chan;
strncpy(as->app, app, sizeof(as->app) - 1);
if (appdata)
strncpy(as->appdata, appdata, sizeof(as->appdata) - 1);
as->timeout = timeout;
if (pthread_create(&as->p, NULL, async_wait, as)) {
ast_log(LOG_WARNING, "Failed to start async wait\n");
free(as);
ast_hangup(chan);
return -1;
}
res = 0;
}
return res;
}
void ast_context_destroy(struct ast_context *con, char *registrar)
if (((tmp == con) || !con) &&
(!registrar || !strcasecmp(registrar, tmp->registrar))) {
/* Okay, let's lock the structure to be sure nobody else
is searching through it. */
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. */
for (tmpi = tmp->includes; tmpi; ) {
/* Free includes */
tmpil = tmpi;
tmpi = tmpi->next;
free(tmpil);
tmpil = tmpi;
}
for (sw = tmp->alts; sw; ) {
swl = sw;
sw = sw->next;
free(swl);
swl = sw;
}
if (!con) {
/* Might need to get another one -- restart */
tmp = contexts;
tmpl = NULL;
tmpil = NULL;
continue;
}
ast_pthread_mutex_unlock(&conlock);
return;
}
tmpl = tmp;
tmp = tmp->next;
}
3346
3347
3348
3349
3350
3351
3352
3353
3354
3355
3356
3357
3358
3359
3360
3361
3362
3363
3364
3365
3366
3367
3368
3369
3370
3371
3372
3373
3374
3375
3376
3377
3378
3379
3380
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_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);
static int pbx_builtin_wait(struct ast_channel *chan, void *data)
if (data && atoi((char *)data)) {
ms = atoi((char *)data) * 1000;
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 timeout for how long to wait between digits */
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 = strdup((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);
free(s);
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);
return 0;
}
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);
}
}
static int pbx_builtin_setvar(struct ast_channel *chan, void *data)
{
char *name;
char *value;
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);
}
3597
3598
3599
3600
3601
3602
3603
3604
3605
3606
3607
3608
3609
3610
3611
3612
3613
3614
3615
3616
3617
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);
}
}
3634
3635
3636
3637
3638
3639
3640
3641
3642
3643
3644
3645
3646
3647
3648
3649
3650
3651
3652
3653
3654
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;
if (!data || !strlen(data)) {
ast_log(LOG_WARNING, "Ignoring, since there is no variable to set\n");
return 0;
}
s=strdup(data);
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_WARNING, "Not taking any branch\n");
return(0);
}
rc=pbx_builtin_goto(chan,branch);
free(s);
return(rc);
}
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;
}
3707
3708
3709
3710
3711
3712
3713
3714
3715
3716
3717
3718
3719
3720
3721
3722
3723
3724
3725
3726
3727
3728
3729
3730
3731
3732
3733
3734
3735
3736
3737
3738
3739
3740
3741
3742
3743
3744
3745
3746
3747
3748
3749
3750
3751
3752
3753
3754
3755
3756
3757
3758
3759
3760
3761
3762
3763
3764
3765
3766
3767
3768
3769
3770
3771
3772
3773
3774
3775
3776
3777
3778
3779
3780
3781
3782
3783
3784
3785
3786
3787
3788
3789
3790
3791
3792
3793
3794
3795
3796
3797
3798
3799
3800
3801
3802
3803
3804
3805
3806
3807
3808
3809
3810
3811
3812
3813
3814
3815
3816
3817
3818
3819
3820
3821
3822
3823
3824
3825
3826
3827
3828
3829
3830
3831
3832
3833
3834
3835
3836
3837
3838
3839
3840
3841
3842
3843
3844
3845
3846
3847
3848
3849
3850
3851
3852
3853
3854
3855
3856
3857
3858
3859
3860
3861
3862
3863
/*
* Lock context list functions ...
*/
int ast_lock_contexts()
{
return ast_pthread_mutex_lock(&conlock);
}
int ast_unlock_contexts()
{
return ast_pthread_mutex_unlock(&conlock);
}
/*
* Lock context ...
*/
int ast_lock_context(struct ast_context *con)
{
return ast_pthread_mutex_lock(&con->lock);
}
int ast_unlock_context(struct ast_context *con)
{
return ast_pthread_mutex_unlock(&con->lock);
}
/*
* 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;
}