Skip to content
Snippets Groups Projects
pbx.c 129 KiB
Newer Older
  • Learn to ignore specific revisions
  • Martin Pycko's avatar
     
    Martin Pycko committed
    			/* check if "failed" exists */
    			if (ast_exists_extension(chan, context, "failed", 1, NULL)) {
    				chan = ast_channel_alloc(0);
    				if (chan) {
    					strncpy(chan->name, "OutgoingSpoolFailed", sizeof(chan->name) - 1);
    
    					if (context && !ast_strlen_zero(context))
    
    Martin Pycko's avatar
     
    Martin Pycko committed
    						strncpy(chan->context, context, sizeof(chan->context) - 1);
    					strncpy(chan->exten, "failed", sizeof(chan->exten) - 1);
    					chan->priority = 1;
    
    					if (variable) {
    						tmp = ast_strdupa(variable);
    						for (var = strtok_r(tmp, "|", &tmp); var; var = strtok_r(NULL, "|", &tmp)) {
    							pbx_builtin_setvar( chan, var );
    						}
    					}
    
    Martin Pycko's avatar
     
    Martin Pycko committed
    					ast_pbx_run(chan);	
    				} else
    					ast_log(LOG_WARNING, "Can't allocate the channel structure, skipping execution of extension 'failed'\n");
    			}
    
    Mark Spencer's avatar
    Mark Spencer committed
    		}
    	} 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);
    
    Mark Spencer's avatar
    Mark Spencer committed
    		if (!chan) {
    			free(as);
    			return -1;
    		}
    
    		pbx_builtin_setaccount(chan, account);
    
    Mark Spencer's avatar
    Mark Spencer committed
    		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 (variable) {
    			tmp = ast_strdupa(variable);
    
    			for (var = strtok_r(tmp, "|", &tmp); var; var = strtok_r(NULL, "|", &tmp))
    				pbx_builtin_setvar( chan, var );
    
    		pthread_attr_init(&attr);
    		pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
    		if (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);
    			ast_hangup(chan);
    			return -1;
    		}
    		res = 0;
    	}
    	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 "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, char *variable, char *account)
    
    Mark Spencer's avatar
    Mark Spencer committed
    {
    	struct ast_channel *chan;
    	struct async_stat *as;
    	struct app_tmp *tmp;
    
    	char *var, *vartmp;
    
    Mark Spencer's avatar
    Mark Spencer committed
    	int res = -1;
    
    	pthread_attr_t attr;
    	
    
    	if (!app || ast_strlen_zero(app))
    
    Mark Spencer's avatar
    Mark Spencer committed
    		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 );
    				}
    
    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));
    					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)) {
    
    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);
    							ast_hangup(chan);
    							res = -1;
    						}
    					}
    				} 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);
    				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);
    
    Mark Spencer's avatar
    Mark Spencer committed
    		if (!chan) {
    			free(as);
    			return -1;
    		}
    
    		pbx_builtin_setaccount(chan, account);
    
    Mark Spencer's avatar
    Mark Spencer committed
    		as->chan = chan;
    		strncpy(as->app, app, sizeof(as->app) - 1);
    		if (appdata)
    			strncpy(as->appdata,  appdata, sizeof(as->appdata) - 1);
    		as->timeout = timeout;
    
    James Golovich's avatar
    James Golovich committed
    			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)) {
    
    Mark Spencer's avatar
    Mark Spencer committed
    			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)
    {
    
    Mark Spencer's avatar
    Mark Spencer committed
    	if (e->priority == PRIORITY_HINT)
    		ast_remove_hint(e);
    
    
    void __ast_context_destroy(struct ast_context *con, 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);
    			}
    
    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, 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;
    
    	int waittime;
    	
    	if (!data || !strlen(data) || (sscanf(data, "%i", &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);
    }
    
    
    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;
    }
    
    
    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;
    }
    
    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;
    }
    
    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;
    }
    
    static int pbx_builtin_answer(struct ast_channel *chan, void *data)
    
    Mark Spencer's avatar
    Mark Spencer committed
    {
    
    Mark Spencer's avatar
    Mark Spencer committed
    	return ast_answer(chan);
    
    Mark Spencer's avatar
    Mark Spencer committed
    static int pbx_builtin_setlanguage(struct ast_channel *chan, void *data)
    
    Mark Spencer's avatar
    Mark Spencer committed
    {
    	/* Copy the language as specified */
    
    Mark Spencer's avatar
    Mark Spencer committed
    	strncpy(chan->language, (char *)data, sizeof(chan->language)-1);
    
    Mark Spencer's avatar
    Mark Spencer committed
    	return 0;
    }
    
    
    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;
    }
    
    
    static int pbx_builtin_setaccount(struct ast_channel *chan, void *data)
    {
    
    	/* Copy the account code  as specified */
    
    	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;
    }
    
    
    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 */
    	return -1;
    }
    
    
    Mark Spencer's avatar
    Mark Spencer committed
    static int pbx_builtin_stripmsd(struct ast_channel *chan, void *data)
    
    Mark Spencer's avatar
    Mark Spencer committed
    {
    	char newexten[AST_MAX_EXTENSION] = "";
    
    Mark Spencer's avatar
    Mark Spencer committed
    	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)) {
    
    Mark Spencer's avatar
    Mark Spencer committed
    		strncpy(newexten, chan->exten + atoi(data), sizeof(newexten)-1);
    
    Mark Spencer's avatar
    Mark Spencer committed
    	}
    
    Mark Spencer's avatar
    Mark Spencer committed
    	strncpy(chan->exten, newexten, sizeof(chan->exten)-1);
    
    Mark Spencer's avatar
    Mark Spencer committed
    	return 0;
    }
    
    
    Mark Spencer's avatar
    Mark Spencer committed
    static int pbx_builtin_prefix(struct ast_channel *chan, void *data)
    
    Mark Spencer's avatar
    Mark Spencer committed
    {
    	char newexten[AST_MAX_EXTENSION] = "";
    
    	if (!data || ast_strlen_zero(data)) {
    
    Mark Spencer's avatar
    Mark Spencer committed
    		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);
    
    Mark Spencer's avatar
    Mark Spencer committed
    	strncpy(chan->exten, newexten, sizeof(chan->exten)-1);
    
    Mark Spencer's avatar
    Mark Spencer committed
    	if (option_verbose > 2)
    		ast_verbose(VERBOSE_PREFIX_3 "Prepended prefix, new extension is %s\n", chan->exten);
    
    Mark Spencer's avatar
    Mark Spencer committed
    	return 0;
    }
    
    
    static int pbx_builtin_suffix(struct ast_channel *chan, void *data)
    {
    	char newexten[AST_MAX_EXTENSION] = "";
    
    	if (!data || ast_strlen_zero(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,"?");
    
    
    	/* 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;
    }
    
    
    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;
    }
    
    
    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;
    }
    
    
    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
    {
    
            int res = 0;
            int option_skip = 0;
            int option_noanswer = 0;
            char filename[256] = "";
            char* stringp;
            char* options;
    
            if (!data || ast_strlen_zero(data)) {
                    ast_log(LOG_WARNING, "Background requires an argument(filename)\n");
                    return -1;
            }
    
            strncpy(filename, (char*)data, sizeof(filename) - 1);
            stringp = filename;
            strsep(&stringp, "|");
            options = strsep(&stringp, "|");
    
            if (options && !strcasecmp(options, "skip"))
                    option_skip = 1;
            if (options && !strcasecmp(options, "noanswer"))
                    option_noanswer = 1;
    
            /* Answer if need be */
            if (chan->_state != AST_STATE_UP) {
                    if (option_skip) {
                            return 0;
                    } else if (!option_noanswer) {
                            res = ast_answer(chan);
                    }
            }
    
            if (!res) {
                    /* Stop anything playing */
                    ast_stopstream(chan);
                    /* Stream a file */
                    res = ast_streamfile(chan, filename, chan->language);
                    if (!res) {
                            res = ast_waitstream(chan, AST_DIGIT_ANY);
                            ast_stopstream(chan);
                    } else {
                            ast_log(LOG_WARNING, "ast_streamfile failed on %s fro %s\n", chan->name, (char*)data);
                            res = 0;
                    }
            }
    
    Mark Spencer's avatar
    Mark Spencer committed
    	return res;
    }
    
    
    Mark Spencer's avatar
    Mark Spencer committed
    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 */
    
    Mark Spencer's avatar
    Mark Spencer committed
    	ast_channel_setwhentohangup(chan,x);
    	if (option_verbose > 2)
    		ast_verbose( VERBOSE_PREFIX_3 "Set Absolute Timeout to %d\n", x);
    	return 0;
    }
    
    
    Mark Spencer's avatar
    Mark Spencer committed
    static int pbx_builtin_rtimeout(struct ast_channel *chan, void *data)
    
    Mark Spencer's avatar
    Mark Spencer committed
    {
    	/* 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;
    }
    
    
    Mark Spencer's avatar
    Mark Spencer committed
    static int pbx_builtin_dtimeout(struct ast_channel *chan, void *data)
    
    Mark Spencer's avatar
    Mark Spencer committed
    {
    	/* 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;
    }
    
    
    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
    {
    	char *s;
    	char *exten, *pri, *context;
    
    Mark Spencer's avatar
    Mark Spencer committed
    	char *stringp=NULL;
    
    	if (!data || ast_strlen_zero(data)) {
    
    Mark Spencer's avatar
    Mark Spencer committed
    		ast_log(LOG_WARNING, "Goto requires an argument (optional context|optional extension|priority)\n");
    		return -1;
    	}
    
    	s = ast_strdupa((void *) data);
    
    Mark Spencer's avatar
    Mark Spencer committed
    	stringp=s;
    	context = strsep(&stringp, "|");
    	exten = strsep(&stringp, "|");
    
    Mark Spencer's avatar
    Mark Spencer committed
    	if (!exten) {
    		/* Only a priority in this one */
    		pri = context;
    		exten = NULL;
    		context = NULL;
    	} else {
    
    Mark Spencer's avatar
    Mark Spencer committed
    		pri = strsep(&stringp, "|");
    
    Mark Spencer's avatar
    Mark Spencer committed
    		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;
    
    Mark Spencer's avatar
    Mark Spencer committed
    	if (exten && strcasecmp(exten, "BYEXTENSION"))
    
    Mark Spencer's avatar
    Mark Spencer committed
    		strncpy(chan->exten, exten, sizeof(chan->exten)-1);
    
    Mark Spencer's avatar
    Mark Spencer committed
    	if (context)
    
    Mark Spencer's avatar
    Mark Spencer committed
    		strncpy(chan->context, context, sizeof(chan->context)-1);
    
    Mark Spencer's avatar
    Mark Spencer committed
    	if (option_verbose > 2)
    		ast_verbose( VERBOSE_PREFIX_3 "Goto (%s,%s,%d)\n", chan->context,chan->exten, chan->priority+1);
    
    Mark Spencer's avatar
    Mark Spencer committed
    	return 0;
    }
    
    char *pbx_builtin_getvar_helper(struct ast_channel *chan, 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;
    }
    
    
    void pbx_builtin_setvar_helper(struct ast_channel *chan, char *name, char *value) 
    {
    
    Mark Spencer's avatar
    Mark Spencer committed
    	struct ast_var_t *newvariable;
    
    	struct varshead *headp;
    	if (chan)
    		headp=&chan->varshead;
    
    	else
    		headp=&globals;
    
    Mark Spencer's avatar
    Mark Spencer committed
                    
    	AST_LIST_TRAVERSE (headp,newvariable,entries) {
    
    		if (strcasecmp(ast_var_name(newvariable),name)==0) {
    
    Mark Spencer's avatar
    Mark Spencer committed
    			/* 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);
    	}
    
    int pbx_builtin_setvar(struct ast_channel *chan, void *data)
    
    Mark Spencer's avatar
    Mark Spencer committed
    {
    	char *name;
    	char *value;
    
    Mark Spencer's avatar
    Mark Spencer committed
    	char *stringp=NULL;
    
    	if (!data || ast_strlen_zero(data)) {
    
    Mark Spencer's avatar
    Mark Spencer committed
    		ast_log(LOG_WARNING, "Ignoring, since there is no variable to set\n");
    		return 0;
    	}
    	
    
    Mark Spencer's avatar
    Mark Spencer committed
    	stringp=data;
    	name=strsep(&stringp,"=");
    	value=strsep(&stringp,"\0"); 
    
    Mark Spencer's avatar
    Mark Spencer committed
    	
    	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) 
    {
    
    	return condition ? atoi(condition) : 0;
    
    Mark Spencer's avatar
    Mark Spencer committed
    }
    
    static int pbx_builtin_gotoif(struct ast_channel *chan, void *data)
    {
    	char *condition,*branch1,*branch2,*branch;
    	char *s;
    	int rc;
    
    Mark Spencer's avatar
    Mark Spencer committed
    	char *stringp=NULL;
    
    	if (!data || ast_strlen_zero(data)) {
    
    		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);
    
    Mark Spencer's avatar
    Mark Spencer committed
    	stringp=s;
    	condition=strsep(&stringp,"?");
    	branch1=strsep(&stringp,":");
    	branch2=strsep(&stringp,"");
    
    	branch = pbx_checkcondition(condition) ? branch1 : branch2;
    
    	if ((branch==NULL) || ast_strlen_zero(branch)) {
    
    		ast_log(LOG_NOTICE, "Not taking any branch\n");
    
    Mark Spencer's avatar
    Mark Spencer committed
    		return(0);
    	}
    	
    	rc=pbx_builtin_goto(chan,branch);
    
    Mark Spencer's avatar
    Mark Spencer committed
    	return(rc);
    }           
    
    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;
    
    	
    
    	if (!data || ast_strlen_zero((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);
    
    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");
    	}
    
            AST_LIST_HEAD_INIT(&globals);
    
    Mark Spencer's avatar
    Mark Spencer committed
    	ast_cli_register(&show_applications_cli);
    	ast_cli_register(&show_application_cli);
    	ast_cli_register(&show_dialplan_cli);
    	ast_cli_register(&show_switches_cli);
    
    
    	/* Register builtin applications */
    	for (x=0; x<sizeof(builtins) / sizeof(struct pbx_builtin); x++) {
    
    Mark Spencer's avatar
    Mark Spencer committed
    		if (option_verbose)
    			ast_verbose( VERBOSE_PREFIX_1 "[%s]\n", builtins[x].name);
    
    Mark Spencer's avatar
    Mark Spencer committed
    		if (ast_register_application(builtins[x].name, builtins[x].execute, builtins[x].synopsis, builtins[x].description)) {
    
    Mark Spencer's avatar
    Mark Spencer committed
    			ast_log(LOG_ERROR, "Unable to register builtin application '%s'\n", builtins[x].name);
    			return -1;
    		}
    	}
    	return 0;
    }
    
    
    Mark Spencer's avatar
    Mark Spencer committed
    /*
     * Lock context list functions ...
     */
    int ast_lock_contexts()
    {
    
    Mark Spencer's avatar
    Mark Spencer committed
    }
    
    int ast_unlock_contexts()
    {
    
    Mark Spencer's avatar
    Mark Spencer committed
    }
    
    /*
     * Lock context ...
     */
    int ast_lock_context(struct ast_context *con)
    {
    
    Mark Spencer's avatar
    Mark Spencer committed
    }
    
    int ast_unlock_context(struct ast_context *con)
    {
    
    	return ast_mutex_unlock(&con->lock);
    
    Mark Spencer's avatar
    Mark Spencer committed
    }
    
    /*
     * 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;
    }