Skip to content
Snippets Groups Projects
pbx.c 166 KiB
Newer Older
  • Learn to ignore specific revisions
  • Mark Spencer's avatar
    Mark Spencer committed
    		as->timeout = timeout;
    
    		pthread_attr_init(&attr);
    		pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
    
    		if (ast_pthread_create(&as->p, &attr, async_wait, as)) {
    
    Mark Spencer's avatar
    Mark Spencer committed
    			ast_log(LOG_WARNING, "Failed to start async wait\n");
    			free(as);
    
    			if (channel)
    				*channel = NULL;
    
    Mark Spencer's avatar
    Mark Spencer committed
    			ast_hangup(chan);
    
    Mark Spencer's avatar
    Mark Spencer committed
    		}
    		res = 0;
    	}
    
    outgoing_exten_cleanup:
    	ast_variables_destroy(vars);
    
    Mark Spencer's avatar
    Mark Spencer committed
    	return res;
    }
    
    
    Mark Spencer's avatar
    Mark Spencer committed
    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 "Launching %s(%s) on %s\n", tmp->app, tmp->data, tmp->chan->name);
    
    Mark Spencer's avatar
    Mark Spencer committed
    		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, struct ast_variable *vars, struct ast_channel **locked_channel)
    
    Mark Spencer's avatar
    Mark Spencer committed
    {
    	struct ast_channel *chan;
    	struct async_stat *as;
    	struct app_tmp *tmp;
    
    	int res = -1, cdr_res = -1;
    
    	pthread_attr_t attr;
    	
    
    	if (locked_channel) 
    		*locked_channel = NULL;
    
    Mark Spencer's avatar
    Mark Spencer committed
    	if (sync) {
    
    		chan = __ast_request_and_dial(type, format, data, timeout, reason, cid_num, cid_name, &oh);
    
    Mark Spencer's avatar
    Mark Spencer committed
    		if (chan) {
    
    			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);
    
    				}
    				/* allocation of the cdr was successful */
    				ast_cdr_init(chan->cdr, chan);  /* initilize our channel's cdr */
    				ast_cdr_start(chan->cdr);
    			}
    
    Mark Spencer's avatar
    Mark Spencer committed
    			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));
    
    					ast_copy_string(tmp->app, app, sizeof(tmp->app));
    
    					if (appdata)
    						ast_copy_string(tmp->data, appdata, sizeof(tmp->data));
    
    Mark Spencer's avatar
    Mark Spencer committed
    					tmp->chan = chan;
    					if (sync > 1) {
    
    						if (locked_channel)
    							ast_mutex_unlock(&chan->lock);
    
    Mark Spencer's avatar
    Mark Spencer committed
    						ast_pbx_run_app(tmp);
    					} else {
    
    						pthread_attr_init(&attr);
    						pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
    
    						if (locked_channel) 
    							ast_mutex_lock(&chan->lock);
    
    						if (ast_pthread_create(&tmp->t, &attr, ast_pbx_run_app, tmp)) {
    
    Mark Spencer's avatar
    Mark Spencer committed
    							ast_log(LOG_WARNING, "Unable to spawn execute thread on %s: %s\n", chan->name, strerror(errno));
    							free(tmp);
    
    							if (locked_channel) 
    								ast_mutex_unlock(&chan->lock);
    
    Mark Spencer's avatar
    Mark Spencer committed
    							ast_hangup(chan);
    							res = -1;
    
    						} else {
    							if (locked_channel) 
    								*locked_channel = chan;
    
    Mark Spencer's avatar
    Mark Spencer committed
    						}
    					}
    				} else {
    
    					ast_log(LOG_ERROR, "Out of memory :(\n");
    
    Mark Spencer's avatar
    Mark Spencer committed
    					res = -1;
    				}
    			} 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);
    				}
    
    Mark Spencer's avatar
    Mark Spencer committed
    				ast_hangup(chan);
    			}
    		}
    
    		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) {
    					res = cdr_res;
    					goto outgoing_app_cleanup;
    				}
    
    Mark Spencer's avatar
    Mark Spencer committed
    	} else {
    		as = malloc(sizeof(struct async_stat));
    
    		if (!as) {
    			res = -1;
    			goto outgoing_app_cleanup;
    		}
    
    Mark Spencer's avatar
    Mark Spencer committed
    		memset(as, 0, sizeof(struct async_stat));
    
    		chan = __ast_request_and_dial(type, format, data, timeout, reason, cid_num, cid_name, &oh);
    
    Mark Spencer's avatar
    Mark Spencer committed
    		if (!chan) {
    			free(as);
    
    Mark Spencer's avatar
    Mark Spencer committed
    		}
    		as->chan = chan;
    
    		ast_copy_string(as->app, app, sizeof(as->app));
    
    Mark Spencer's avatar
    Mark Spencer committed
    		if (appdata)
    
    			ast_copy_string(as->appdata,  appdata, sizeof(as->appdata));
    
    Mark Spencer's avatar
    Mark Spencer committed
    		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 (locked_channel) 
    			ast_mutex_lock(&chan->lock);
    
    		if (ast_pthread_create(&as->p, &attr, async_wait, as)) {
    
    Mark Spencer's avatar
    Mark Spencer committed
    			ast_log(LOG_WARNING, "Failed to start async wait\n");
    			free(as);
    
    			if (locked_channel) 
    				ast_mutex_unlock(&chan->lock);
    
    Mark Spencer's avatar
    Mark Spencer committed
    			ast_hangup(chan);
    
    		} else {
    			if (locked_channel)
    				*locked_channel = chan;
    
    Mark Spencer's avatar
    Mark Spencer committed
    		}
    		res = 0;
    	}
    
    outgoing_app_cleanup:
    	ast_variables_destroy(vars);
    
    Mark Spencer's avatar
    Mark Spencer committed
    	return res;
    }
    
    
    static void destroy_exten(struct ast_exten *e)
    {
    
    Mark Spencer's avatar
    Mark Spencer committed
    	if (e->priority == PRIORITY_HINT)
    		ast_remove_hint(e);
    
    
    void __ast_context_destroy(struct ast_context *con, const char *registrar)
    
    Mark Spencer's avatar
    Mark Spencer committed
    {
    	struct ast_context *tmp, *tmpl=NULL;
    
    Mark Spencer's avatar
    Mark Spencer committed
    	struct ast_include *tmpi, *tmpil= NULL;
    
    Mark Spencer's avatar
    Mark Spencer committed
    	struct ast_sw *sw, *swl= NULL;
    
    	struct ast_exten *e, *el, *en;
    
    Mark Spencer's avatar
    Mark Spencer committed
    	struct ast_ignorepat *ipi, *ipl = NULL;
    
    Mark Spencer's avatar
    Mark Spencer committed
    	tmp = contexts;
    	while(tmp) {
    
    		if (((tmp->name && con && con->name && !strcasecmp(tmp->name, con->name)) || !con) &&
    
    Mark Spencer's avatar
    Mark Spencer committed
    		    (!registrar || !strcasecmp(registrar, tmp->registrar))) {
    
    Mark Spencer's avatar
    Mark Spencer committed
    			/* Okay, let's lock the structure to be sure nobody else
    			   is searching through it. */
    
    Mark Spencer's avatar
    Mark Spencer committed
    				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. */
    
    Mark Spencer's avatar
    Mark Spencer committed
    			for (tmpi = tmp->includes; tmpi; ) {
    				/* Free includes */
    				tmpil = tmpi;
    				tmpi = tmpi->next;
    				free(tmpil);
    
    Mark Spencer's avatar
    Mark Spencer committed
    			}
    			for (ipi = tmp->ignorepats; ipi; ) {
    
    				/* Free ignorepats */
    
    Mark Spencer's avatar
    Mark Spencer committed
    				ipl = ipi;
    				ipi = ipi->next;
    				free(ipl);
    
    Mark Spencer's avatar
    Mark Spencer committed
    			}
    
    Mark Spencer's avatar
    Mark Spencer committed
    			for (sw = tmp->alts; sw; ) {
    
    				/* Free switches */
    
    Mark Spencer's avatar
    Mark Spencer committed
    				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);
    			}
    
    			ast_mutex_destroy(&tmp->lock);
    
    Mark Spencer's avatar
    Mark Spencer committed
    			free(tmp);
    
    Mark Spencer's avatar
    Mark Spencer committed
    			if (!con) {
    				/* Might need to get another one -- restart */
    				tmp = contexts;
    				tmpl = NULL;
    				tmpil = NULL;
    				continue;
    			}
    
    Mark Spencer's avatar
    Mark Spencer committed
    			return;
    		}
    		tmpl = tmp;
    		tmp = tmp->next;
    	}
    
    void ast_context_destroy(struct ast_context *con, const char *registrar)
    
    static void wait_for_hangup(struct ast_channel *chan, void *data)
    
    Mark Spencer's avatar
    Mark Spencer committed
    {
    	int res;
    	struct ast_frame *f;
    
    	if (ast_strlen_zero(data) || (sscanf(data, "%d", &waittime) != 1) || (waittime < 0))
    
    		waittime = -1;
    	if (waittime > -1) {
    		ast_safe_sleep(chan, waittime * 1000);
    	} else do {
    
    Mark Spencer's avatar
    Mark Spencer committed
    		res = ast_waitfor(chan, -1);
    		if (res < 0)
    			return;
    		f = ast_read(chan);
    		if (f)
    			ast_frfree(f);
    	} while(f);
    }
    
    
    /*!
     * \ingroup applications
     */
    
    Mark Spencer's avatar
    Mark Spencer committed
    static int pbx_builtin_progress(struct ast_channel *chan, void *data)
    {
    	ast_indicate(chan, AST_CONTROL_PROGRESS);
    	return 0;
    }
    
    
    /*!
     * \ingroup applications
     */
    
    Mark Spencer's avatar
    Mark Spencer committed
    static int pbx_builtin_ringing(struct ast_channel *chan, void *data)
    {
    	ast_indicate(chan, AST_CONTROL_RINGING);
    	return 0;
    }
    
    
    /*!
     * \ingroup applications
     */
    
    Mark Spencer's avatar
    Mark Spencer committed
    static int pbx_builtin_busy(struct ast_channel *chan, void *data)
    {
    	ast_indicate(chan, AST_CONTROL_BUSY);		
    
    	wait_for_hangup(chan, data);
    
    Mark Spencer's avatar
    Mark Spencer committed
    	return -1;
    }
    
    
    /*!
     * \ingroup applications
     */
    
    Mark Spencer's avatar
    Mark Spencer committed
    static int pbx_builtin_congestion(struct ast_channel *chan, void *data)
    {
    	ast_indicate(chan, AST_CONTROL_CONGESTION);
    
    	wait_for_hangup(chan, data);
    
    Mark Spencer's avatar
    Mark Spencer committed
    	return -1;
    }
    
    
    /*!
     * \ingroup applications
     */
    
    Mark Spencer's avatar
    Mark Spencer committed
    static int pbx_builtin_answer(struct ast_channel *chan, void *data)
    
    Mark Spencer's avatar
    Mark Spencer committed
    {
    
    	if (chan->_state == AST_STATE_UP)
    		delay = 0;
    
    	else if (!ast_strlen_zero(data))
    		delay = atoi(data);
    
    
    	res = ast_answer(chan);
    	if (res)
    		return res;
    
    	if (delay)
    		res = ast_safe_sleep(chan, delay);
    
    AST_APP_OPTIONS(resetcdr_opts, {
    	AST_APP_OPTION('w', AST_CDR_FLAG_POSTED),
    	AST_APP_OPTION('a', AST_CDR_FLAG_LOCKED),
    	AST_APP_OPTION('v', AST_CDR_FLAG_KEEP_VARS),
    });
    
    
    /*!
     * \ingroup applications
     */
    
    static int pbx_builtin_resetcdr(struct ast_channel *chan, void *data)
    {
    
    	char *args;
    	struct ast_flags flags = { 0 };
    	
    	if (!ast_strlen_zero(data)) {
    		args = ast_strdupa(data);
    		if (!args) {
    			ast_log(LOG_ERROR, "Out of memory!\n");
    			return -1;
    		}
    		ast_app_parse_options(resetcdr_opts, &flags, NULL, args);
    	}
    
    	ast_cdr_reset(chan->cdr, &flags);
    
    
    /*!
     * \ingroup applications
     */
    
    static int pbx_builtin_setamaflags(struct ast_channel *chan, void *data)
    {
    	/* Copy the AMA Flags as specified */
    	if (data)
    
    Russell Bryant's avatar
    Russell Bryant committed
    		ast_cdr_setamaflags(chan, data);
    
    	else
    		ast_cdr_setamaflags(chan, "");
    	return 0;
    }
    
    
    /*!
     * \ingroup applications
     */
    
    Mark Spencer's avatar
    Mark Spencer committed
    static int pbx_builtin_hangup(struct ast_channel *chan, void *data)
    
    Mark Spencer's avatar
    Mark Spencer committed
    {
    	/* Just return non-zero and it will hang up */
    
    	if (!chan->hangupcause)
    		chan->hangupcause = AST_CAUSE_NORMAL_CLEARING;
    
    Mark Spencer's avatar
    Mark Spencer committed
    	return -1;
    }
    
    
    /*!
     * \ingroup applications
     */
    
    static int pbx_builtin_gotoiftime(struct ast_channel *chan, void *data)
    {
    	int res=0;
    	char *s, *ts;
    
    	struct ast_timing timing;
    
    		ast_log(LOG_WARNING, "GotoIfTime requires an argument:\n  <time range>|<days of week>|<days of month>|<months>?[[context|]extension|]priority\n");
    		return -1;
    	}
    
    
    Russell Bryant's avatar
    Russell Bryant committed
    	if ((s = ast_strdupa(data))) {
    
    		ts = s;
    
    		/* Separate the Goto path */
    		strsep(&ts,"?");
    
    		/* struct ast_include include contained garbage here, fixed by zeroing it on get_timerange */
    		if (ast_build_timing(&timing, s) && ast_check_timing(&timing))
    			res = pbx_builtin_goto(chan, (void *)ts);
    	} else {
    		ast_log(LOG_ERROR, "Memory Error!\n");
    	}
    	return res;
    }
    
    
    /*!
     * \ingroup applications
     */
    
    static int pbx_builtin_execiftime(struct ast_channel *chan, void *data)
    {
    	int res = 0;
    	char *ptr1, *ptr2;
    	struct ast_timing timing;
    
    	const char *usage = "ExecIfTime requires an argument:\n  <time range>|<days of week>|<days of month>|<months>?<appname>[|<appargs>]";
    
    		ast_log(LOG_WARNING, "%s\n", usage);	
    
    	ptr1 = ast_strdupa(data);
    
    	if (!ptr1) {
    		ast_log(LOG_ERROR, "Out of Memory!\n");
    		return -1;	
    	}
    
    	ptr2 = ptr1;
    	/* Separate the Application data ptr1 is the time spec ptr2 is the app|data */
    	strsep(&ptr2,"?");
    	if(!ast_build_timing(&timing, ptr1)) {
    		ast_log(LOG_WARNING, "Invalid Time Spec: %s\nCorrect usage: %s\n", ptr1, usage);
    		res = -1;
    	}
    		
    	if (!res && ast_check_timing(&timing)) {
    		if (!ptr2) {
    			ast_log(LOG_WARNING, "%s\n", usage);
    		}
    
    		/* ptr2 is now the app name 
    		   we're done with ptr1 now so recycle it and use it to point to the app args */
    		if((ptr1 = strchr(ptr2, '|'))) {
    			*ptr1 = '\0';
    			ptr1++;
    
    		if ((app = pbx_findapp(ptr2))) {
    			res = pbx_exec(chan, app, ptr1 ? ptr1 : "", 1);
    		} else {
    			ast_log(LOG_WARNING, "Cannot locate application %s\n", ptr2);
    			res = -1;
    
    /*!
     * \ingroup applications
     */
    
    Mark Spencer's avatar
    Mark Spencer committed
    static int pbx_builtin_wait(struct ast_channel *chan, void *data)
    
    Mark Spencer's avatar
    Mark Spencer committed
    {
    
    Mark Spencer's avatar
    Mark Spencer committed
    	int ms;
    
    Mark Spencer's avatar
    Mark Spencer committed
    	/* Wait for "n" seconds */
    
    	if (data && atof((char *)data)) {
    		ms = atof((char *)data) * 1000;
    
    Mark Spencer's avatar
    Mark Spencer committed
    		return ast_safe_sleep(chan, ms);
    
    Mark Spencer's avatar
    Mark Spencer committed
    	return 0;
    }
    
    
    /*!
     * \ingroup applications
     */
    
    static int pbx_builtin_waitexten(struct ast_channel *chan, void *data)
    {
    
    	int ms, res, argc;
    	char *args;
    	char *argv[2];
    	char *options = NULL; 
    	char *timeout = NULL;
    	struct ast_flags flags = {0};
    
    	if ((argc = ast_app_separate_args(args, '|', argv, sizeof(argv) / sizeof(argv[0])))) {
    
    	if (options)
    		ast_app_parse_options(waitexten_opts, &flags, opts, options);
    
    		ast_moh_start(chan, opts[0]);
    
    	/* Wait for "n" seconds */
    
    	if (timeout && atof((char *)timeout)) 
    		ms = atof((char *)timeout) * 1000;
    
    Mark Spencer's avatar
    Mark Spencer committed
    	else if (chan->pbx)
    		ms = chan->pbx->rtimeout * 1000;
    	else
    		ms = 10000;
    	res = ast_waitfordigit(chan, ms);
    	if (!res) {
    
    		if (ast_exists_extension(chan, chan->context, chan->exten, chan->priority + 1, chan->cid.cid_num)) {
    
    Mark Spencer's avatar
    Mark Spencer committed
    			if (option_verbose > 2)
    
    				ast_verbose(VERBOSE_PREFIX_3 "Timeout on %s, continuing...\n", chan->name);
    		} else if (ast_exists_extension(chan, chan->context, "t", 1, chan->cid.cid_num)) {
    			if (option_verbose > 2)
    				ast_verbose(VERBOSE_PREFIX_3 "Timeout on %s, going to 't'\n", chan->name);
    
    			ast_copy_string(chan->exten, "t", sizeof(chan->exten));
    
    Mark Spencer's avatar
    Mark Spencer committed
    			chan->priority = 0;
    		} else {
    			ast_log(LOG_WARNING, "Timeout but no rule 't' in context '%s'\n", chan->context);
    			res = -1;
    		}
    
    
    	if (ast_test_flag(&flags, WAITEXTEN_MOH))
    		ast_moh_stop(chan);
    
    
    Mark Spencer's avatar
    Mark Spencer committed
    	return res;
    
    /*!
     * \ingroup applications
     */
    
    Mark Spencer's avatar
    Mark Spencer committed
    static int pbx_builtin_background(struct ast_channel *chan, void *data)
    
    Mark Spencer's avatar
    Mark Spencer committed
    {
    
    James Golovich's avatar
    James Golovich committed
    	int res = 0;
    
    	char *parse;
    
    	char *filename = NULL;
    	char *front = NULL, *back = NULL;
    
    	parse = ast_strdupa(data);
    
    
    	if ((argc = ast_app_separate_args(parse, '|', argv, sizeof(argv) / sizeof(argv[0])))) {
    
    		switch (argc) {
    		case 4:
    			context = argv[3];
    		case 3:
    			lang = argv[2];
    		case 2:
    			options = argv[1];
    		case 1:
    
    			ast_log(LOG_WARNING, "Background requires an argument (filename)\n");
    
    	if (options) {
    		if (!strcasecmp(options, "skip"))
    			flags.flags = BACKGROUND_SKIP;
    		else if (!strcasecmp(options, "noanswer"))
    			flags.flags = BACKGROUND_NOANSWER;
    		else
    
    			ast_app_parse_options(background_opts, &flags, NULL, options);
    
    James Golovich's avatar
    James Golovich committed
    
    	/* Answer if need be */
    	if (chan->_state != AST_STATE_UP) {
    
    		if (ast_test_flag(&flags, BACKGROUND_SKIP)) {
    
    James Golovich's avatar
    James Golovich committed
    			return 0;
    
    		} else if (!ast_test_flag(&flags, BACKGROUND_NOANSWER)) {
    
    James Golovich's avatar
    James Golovich committed
    			res = ast_answer(chan);
    		}
    	}
    
    	if (!res) {
    		/* Stop anything playing */
    		ast_stopstream(chan);
    		/* Stream a file */
    
    		front = filename;
    		while(!res && front) {
    			if((back = strchr(front, '&'))) {
    				*back = '\0';
    				back++;
    			}
    			res = ast_streamfile(chan, front, lang);
    			if (!res) {
    
    				if (ast_test_flag(&flags, BACKGROUND_PLAYBACK)) {
    					res = ast_waitstream(chan, "");
    				} else {
    					if (ast_test_flag(&flags, BACKGROUND_MATCHEXTEN)) {
    						res = ast_waitstream_exten(chan, context);
    					} else {
    						res = ast_waitstream(chan, AST_DIGIT_ANY);
    					}
    				}
    
    				ast_stopstream(chan);
    			} else {
    				ast_log(LOG_WARNING, "ast_streamfile failed on %s for %s\n", chan->name, (char*)data);
    				res = 0;
    				break;
    			}
    			front = back;
    
    	if (context != chan->context && res) {
    		snprintf(chan->exten, sizeof(chan->exten), "%c", res);
    		ast_copy_string(chan->context, context, sizeof(chan->context));
    		chan->priority = 0;
    		return 0;
    	} else {
    		return res;
    	}
    
    /*! Goto
     * \ingroup applications
     */
    
    Mark Spencer's avatar
    Mark Spencer committed
    static int pbx_builtin_goto(struct ast_channel *chan, void *data)
    
    Mark Spencer's avatar
    Mark Spencer committed
    {
    
    	int res;
    	res = ast_parseable_goto(chan, (const char *) data);
    	if (!res && (option_verbose > 2))
    
    Mark Spencer's avatar
    Mark Spencer committed
    		ast_verbose( VERBOSE_PREFIX_3 "Goto (%s,%s,%d)\n", chan->context,chan->exten, chan->priority+1);
    
    Mark Spencer's avatar
    Mark Spencer committed
    }
    
    int pbx_builtin_serialize_variables(struct ast_channel *chan, char *buf, size_t size) 
    {
    	struct ast_var_t *variables;
    
    	if (!chan)
    		return 0;
    
    	memset(buf, 0, size);
    
    	AST_LIST_TRAVERSE(&chan->varshead, variables, entries) {
    		if(variables &&
    		   (var=ast_var_name(variables)) && (val=ast_var_value(variables)) &&
    		   !ast_strlen_zero(var) && !ast_strlen_zero(val)) {
    			if (ast_build_string(&buf, &size, "%s=%s\n", var, val)) {
    				ast_log(LOG_ERROR, "Data Buffer Size Exceeded!\n");
    
    const char *pbx_builtin_getvar_helper(struct ast_channel *chan, const char *name) 
    
    Mark Spencer's avatar
    Mark Spencer committed
    	struct ast_var_t *variables;
    	struct varshead *headp;
    
    
    	if (chan)
    		headp=&chan->varshead;
    
    	else
    		headp=&globals;
    
    	if (name) {
    
    Mark Spencer's avatar
    Mark Spencer committed
    		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);
    			}
    		}
    	}
    
    Mark Spencer's avatar
    Mark Spencer committed
    	return NULL;
    }
    
    
    Kevin P. Fleming's avatar
    Kevin P. Fleming committed
    void pbx_builtin_pushvar_helper(struct ast_channel *chan, const char *name, const char *value)
    {
    	struct ast_var_t *newvariable;
    	struct varshead *headp;
    
    	if (name[strlen(name)-1] == ')') {
    		ast_log(LOG_WARNING, "Cannot push a value onto a function\n");
    		return ast_func_write(chan, name, value);
    	}
    
    	headp = (chan) ? &chan->varshead : &globals;
    
    	if (value) {
    		if ((option_verbose > 1) && (headp == &globals))
    			ast_verbose(VERBOSE_PREFIX_2 "Setting global variable '%s' to '%s'\n", name, value);
    		newvariable = ast_var_assign(name, value);	
    		AST_LIST_INSERT_HEAD(headp, newvariable, entries);
    	}
    }
    
    
    void pbx_builtin_setvar_helper(struct ast_channel *chan, const char *name, const char *value)
    
    Mark Spencer's avatar
    Mark Spencer committed
    	struct ast_var_t *newvariable;
    
    	struct varshead *headp;
    
    	if (name[strlen(name)-1] == ')')
    		return ast_func_write(chan, name, value);
    
    
    	headp = (chan) ? &chan->varshead : &globals;
    
    	/* For comparison purposes, we have to strip leading underscores */
    	if (*nametail == '_') {
    		nametail++;
    		if (*nametail == '_') 
    			nametail++;
    	}
    
    
    	AST_LIST_TRAVERSE (headp, newvariable, entries) {
    
    		if (strcasecmp(ast_var_name(newvariable), nametail) == 0) {
    
    Mark Spencer's avatar
    Mark Spencer committed
    			/* there is already such a variable, delete it */
    
    			AST_LIST_REMOVE(headp, newvariable, entries);
    
    Mark Spencer's avatar
    Mark Spencer committed
    			ast_var_delete(newvariable);
    			break;
    		}
    	} 
    
    	if (value) {
    		if ((option_verbose > 1) && (headp == &globals))
    
    			ast_verbose(VERBOSE_PREFIX_2 "Setting global variable '%s' to '%s'\n", name, value);
    
    		newvariable = ast_var_assign(name, value);	
    		AST_LIST_INSERT_HEAD(headp, newvariable, entries);
    
    int pbx_builtin_setvar(struct ast_channel *chan, void *data)
    
    Mark Spencer's avatar
    Mark Spencer committed
    {
    
    	char *name, *value, *mydata;
    	int argc;
    	char *argv[24];		/* this will only support a maximum of 24 variables being set in a single operation */
    	int global = 0;
    	int x;
    
    		ast_log(LOG_WARNING, "Set requires at least one variable name/value pair.\n");
    
    	argc = ast_app_separate_args(mydata, '|', argv, sizeof(argv) / sizeof(argv[0]));
    
    
    	/* check for a trailing flags argument */
    	if ((argc > 1) && !strchr(argv[argc-1], '=')) {
    		argc--;
    		if (strchr(argv[argc], 'g'))
    			global = 1;
    
    Mark Spencer's avatar
    Mark Spencer committed
    	}
    
    
    	for (x = 0; x < argc; x++) {
    		name = argv[x];
    		if ((value = strchr(name, '='))) {
    			*value = '\0';
    			value++;
    			pbx_builtin_setvar_helper((global) ? NULL : chan, name, value);
    		} else
    			ast_log(LOG_WARNING, "Ignoring entry '%s' with no = (and not last 'options' entry)\n", name);
    	}
    
    
    int pbx_builtin_importvar(struct ast_channel *chan, void *data)
    {
    	char *name;
    	char *value;
    	char *stringp=NULL;
    	char *channel;
    
    	char tmp[VAR_BUF_SIZE]="";
    
    		ast_log(LOG_WARNING, "Ignoring, since there is no variable to set\n");
    		return 0;
    	}
    
    	stringp = ast_strdupa(data);
    	name = strsep(&stringp,"=");
    	channel = strsep(&stringp,"|"); 
    	value = strsep(&stringp,"\0");
    	if (channel && value && name) {
    
    		chan2 = ast_get_channel_by_name_locked(channel);
    
    		if (chan2) {
    			s = alloca(strlen(value) + 4);
    			if (s) {
    				sprintf(s, "${%s}", value);
    				pbx_substitute_variables_helper(chan2, s, tmp, sizeof(tmp) - 1);
    			}
    			ast_mutex_unlock(&chan2->lock);
    		}
    		pbx_builtin_setvar_helper(chan, name, tmp);
    	}
    
    	return(0);
    }
    
    
    static int pbx_builtin_setglobalvar(struct ast_channel *chan, void *data)
    {
    	char *name;
    	char *value;
    
    		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_REMOVE_HEAD(&globals, entries);
    
    		ast_var_delete(vardata);
    	}
    }
    
    
    static int pbx_checkcondition(char *condition) 
    {
    
    Mark Spencer's avatar
    Mark Spencer committed
    	if (condition) {
    		if (*condition == '\0') {
    			/* Empty strings are false */
    			return 0;
    		} else if (*condition >= '0' && *condition <= '9') {
    			/* Numbers are evaluated for truth */
    			return atoi(condition);
    		} else {
    			/* Strings are true */
    			return 1;
    		}
    	} else {
    		/* NULL is also false */
    		return 0;
    	}
    
    Mark Spencer's avatar
    Mark Spencer committed
    }
    
    static int pbx_builtin_gotoif(struct ast_channel *chan, void *data)
    {
    
    	char *condition, *branch1, *branch2, *branch;
    
    Mark Spencer's avatar
    Mark Spencer committed
    	char *s;
    	int rc;
    
    Mark Spencer's avatar
    Mark Spencer committed
    	char *stringp=NULL;
    
    		ast_log(LOG_WARNING, "Ignoring, since there is no variable to check\n");
    
    Mark Spencer's avatar
    Mark Spencer committed
    		return 0;
    	}
    	
    
    	s = ast_strdupa(data);
    	stringp = s;
    	condition = strsep(&stringp,"?");
    	branch1 = strsep(&stringp,":");
    	branch2 = strsep(&stringp,"");
    
    	branch = pbx_checkcondition(condition) ? branch1 : branch2;
    
    		ast_log(LOG_DEBUG, "Not taking any branch\n");
    
    	rc = pbx_builtin_goto(chan, branch);
    
    Mark Spencer's avatar
    Mark Spencer committed
    }           
    
    Mark Spencer's avatar
    Mark Spencer committed
    
    static int pbx_builtin_saynumber(struct ast_channel *chan, void *data)
    {
    	int res = 0;
    
    	char tmp[256];
    	char *number = (char *) NULL;
    	char *options = (char *) NULL;
    
    	
    
    		ast_log(LOG_WARNING, "SayNumber requires an argument (number)\n");
    		return -1;
    	}
    
    	ast_copy_string(tmp, (char *) data, sizeof(tmp));
    
    	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);
    
    Mark Spencer's avatar
    Mark Spencer committed
    }
    
    static int pbx_builtin_saydigits(struct ast_channel *chan, void *data)
    {
    	int res = 0;
    
    Mark Spencer's avatar
    Mark Spencer committed
    	if (data)
    		res = ast_say_digit_str(chan, (char *)data, "", chan->language);
    
    Mark Spencer's avatar
    Mark Spencer committed
    	return res;
    }
    
    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;
    }
    	
    
    Mark Spencer's avatar
    Mark Spencer committed
    int load_pbx(void)
    {
    	int x;
    
    Mark Spencer's avatar
    Mark Spencer committed
    	/* Initialize the PBX */
    	if (option_verbose) {
    		ast_verbose( "Asterisk PBX Core Initializing\n");
    		ast_verbose( "Registering builtin applications:\n");
    	}