Skip to content
Snippets Groups Projects
pbx.c 153 KiB
Newer Older
  • Learn to ignore specific revisions
  • static int pbx_builtin_gotoiftime(struct ast_channel *chan, void *data)
    {
    	int res=0;
    	char *s, *ts;
    
    	struct ast_timing timing;
    
    
    	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 */
    
    	if (ast_build_timing(&timing, s) && ast_check_timing(&timing))
    
    		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;
    
    Mark Spencer's avatar
    Mark Spencer committed
    	int res;
    
    	/* Wait for "n" seconds */
    
    Mark Spencer's avatar
    Mark Spencer committed
    	if (data && atof((char *)data)) 
    
    		ms = atof((char *)data) * 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);
    
    Mark Spencer's avatar
    Mark Spencer committed
    			strncpy(chan->exten, "t", sizeof(chan->exten));
    			chan->priority = 0;
    		} else {
    			ast_log(LOG_WARNING, "Timeout but no rule 't' in context '%s'\n", chan->context);
    			res = -1;
    		}
    
    Mark Spencer's avatar
    Mark Spencer committed
    	return res;
    
    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;
    	int option_skip = 0;
    	int option_noanswer = 0;
    
    	char *filename = NULL;
    
    James Golovich's avatar
    James Golovich committed
    	char* stringp;
    	char* options;
    	char *lang = NULL;
    
    	char *front = NULL, *back = NULL;
    
    	if (!data || ast_strlen_zero(data) || !(filename = ast_strdupa(data))) {
    
    James Golovich's avatar
    James Golovich committed
    		ast_log(LOG_WARNING, "Background requires an argument(filename)\n");
    		return -1;
    	}
    
    	stringp = filename;
    	strsep(&stringp, "|");
    	options = strsep(&stringp, "|");
    	if (options)
    		lang = strsep(&stringp, "|");
    	if (!lang)
    		lang = chan->language;
    
    	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 */
    
    		front = filename;
    		while(!res && front) {
    			if((back = strchr(front, '&'))) {
    				*back = '\0';
    				back++;
    			}
    			res = ast_streamfile(chan, front, lang);
    			if (!res) {
    				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;
    
    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
    {
    
    	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;
    	struct varshead *headp;
    
    	int total = 0;
    
    	memset(buf,0,size);
    	if (chan) {
    		headp=&chan->varshead;
    		AST_LIST_TRAVERSE(headp,variables,entries) {
    
    			if(chan && variables && (var=ast_var_name(variables)) && (val=ast_var_value(variables)) && !ast_strlen_zero(var) && !ast_strlen_zero(val)) {
    
    				snprintf(buf + strlen(buf), size - strlen(buf), "%s=%s\n", var, val);
    				if(strlen(buf) >= size) {
    					ast_log(LOG_ERROR,"Data Buffer Size Exceeded!\n");
    					break;
    				}
    				total++;
    
    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;
    
    		headp = &chan->varshead;
    
    		if (!strncasecmp(name, "CDR(", 4)) { /* CDR VARS */
    			char *vtmp, *nt; 
    			int recur = 0;
    			if ((vtmp = ast_strdupa((char *) name + 4)) && (nt = strchr(vtmp, ')'))) {
    				*nt = '\0';
    				if(vtmp[0] == '-') {
    					vtmp++;
    					recur = 1;
    				}
    				ast_cdr_setvar(chan->cdr, vtmp, value, recur);
    			} else {
    				ast_log(LOG_WARNING, "Invalid CDR variable.\n");
    			}
    			return;
    		}
    	}
    
    		headp = &globals;
    
    	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, 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_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, *value, *mydata, *next, *fstr = NULL;
    	struct ast_flags flags = {0};
    
    	if (data && !ast_strlen_zero(data) && chan->cdr && (mydata = ast_strdupa(data))) {
    		next = mydata;
    		while(next) {
    			name = next;
    			if ((next = strchr(next, '|'))) {
    				*next = '\0';
    				next++;
    			}
    
    			if ((value = strchr(name, '='))) {
    				*value = '\0';
    				value++;
    				if( fstr && strchr(fstr, 'g') ) {
    					pbx_builtin_setvar_helper(NULL, name, value);
    				}
    				else {
    					pbx_builtin_setvar_helper(chan, name, value);
    					if (ast_test_flag(&flags, AST_CDR_FLAG_SETVAR)) {
    						ast_cdr_setvar(chan->cdr, name, value, ast_test_flag(&flags, AST_CDR_FLAG_RECUR));
    					}
    				}
    			} else if (!next) {
    				name++;
    				if (strchr(name, 'c') ) {
    					ast_set_flag(&flags, AST_CDR_FLAG_SETVAR);
    				} else if (strchr(name, 'r') ) {
    					ast_set_flag(&flags, AST_CDR_FLAG_RECUR | AST_CDR_FLAG_SETVAR);
    				}
    			} else
    				ast_log(LOG_WARNING, "Ignoring entry '%s' with no = (and not last 'options' entry)\n", name);
    		}
    	} else {
    
    Mark Spencer's avatar
    Mark Spencer committed
    		ast_log(LOG_WARNING, "Ignoring, since there is no variable to set\n");
    	}
    
    int pbx_builtin_importvar(struct ast_channel *chan, void *data)
    {
    	char *name;
    	char *value;
    	char *stringp=NULL;
    	char *channel;
    	struct ast_channel *chan2=NULL;
    	char tmp[4096]="";
    	char *s;
    
    	if (!data || ast_strlen_zero(data)) {
    		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) {
    		while((chan2 = ast_channel_walk_locked(chan2))) {
    			if (!strcmp(chan2->name, channel))
    				break;
    			ast_mutex_unlock(&chan2->lock);
    		}
    		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;
    
    	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_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_DEBUG, "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);
    
    	ast_cli_register(&show_hints_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 ...
     */
    
    const char *ast_get_context_name(struct ast_context *con)
    
    Mark Spencer's avatar
    Mark Spencer committed
    {
    	return con ? con->name : NULL;
    }
    
    
    const char *ast_get_extension_name(struct ast_exten *exten)
    
    Mark Spencer's avatar
    Mark Spencer committed
    {
    	return exten ? exten->exten : NULL;
    }
    
    
    const char *ast_get_extension_label(struct ast_exten *exten)
    {
    	return exten ? exten->label : NULL;
    }
    
    const char *ast_get_include_name(struct ast_include *inc)
    
    Mark Spencer's avatar
    Mark Spencer committed
    {
    	return inc ? inc->name : NULL;
    }
    
    
    const char *ast_get_ignorepat_name(struct ast_ignorepat *ip)
    
    Mark Spencer's avatar
    Mark Spencer committed
    {
    	return ip ? ip->pattern : NULL;
    }
    
    int ast_get_extension_priority(struct ast_exten *exten)
    {
    	return exten ? exten->priority : -1;
    }
    
    /*
     * Registrar info functions ...
     */
    
    const char *ast_get_context_registrar(struct ast_context *c)
    
    Mark Spencer's avatar
    Mark Spencer committed
    {
    	return c ? c->registrar : NULL;
    }
    
    
    const char *ast_get_extension_registrar(struct ast_exten *e)
    
    Mark Spencer's avatar
    Mark Spencer committed
    {
    	return e ? e->registrar : NULL;
    }
    
    
    const char *ast_get_include_registrar(struct ast_include *i)
    
    Mark Spencer's avatar
    Mark Spencer committed
    {
    	return i ? i->registrar : NULL;
    }
    
    
    const char *ast_get_ignorepat_registrar(struct ast_ignorepat *ip)
    
    Mark Spencer's avatar
    Mark Spencer committed
    {
    	return ip ? ip->registrar : NULL;
    }
    
    
    int ast_get_extension_matchcid(struct ast_exten *e)
    {
    	return e ? e->matchcid : 0;
    }
    
    
    const char *ast_get_extension_cidmatch(struct ast_exten *e)
    
    const char *ast_get_extension_app(struct ast_exten *e)
    
    Mark Spencer's avatar
    Mark Spencer committed
    {
    	return e ? e->app : NULL;
    }
    
    void *ast_get_extension_app_data(struct ast_exten *e)
    {
    	return e ? e->data : NULL;
    }
    
    
    const char *ast_get_switch_name(struct ast_sw *sw)
    
    Mark Spencer's avatar
    Mark Spencer committed
    {
    	return sw ? sw->name : NULL;
    }
    
    
    const char *ast_get_switch_data(struct ast_sw *sw)
    
    Mark Spencer's avatar
    Mark Spencer committed
    {
    	return sw ? sw->data : NULL;
    }
    
    
    const char *ast_get_switch_registrar(struct ast_sw *sw)
    
    Mark Spencer's avatar
    Mark Spencer committed
    {
    	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;
    }
    
    static int __ast_goto_if_exists(struct ast_channel *chan, char* context, char *exten, int priority, int async) 
    
    	int (*goto_func)(struct ast_channel *chan, const char *context, const char *exten, int priority) = NULL;
    
    
    		if (async) {
    			goto_func = ast_async_goto;
    		} else { 
    			goto_func = ast_explicit_goto;
    			priority--;
    			if(priority < 0)
    				priority = 0;
    		}
    
    		if (ast_exists_extension(chan, 
    								 context ? context : chan->context,
    								 exten ? exten : chan->exten,
    								 priority,
    								 chan->cid.cid_num)) {
    
    							 context ? context : chan->context,
    							 exten ? exten : chan->exten,
    							 priority);
    
    int ast_goto_if_exists(struct ast_channel *chan, char* context, char *exten, int priority) {
    	return __ast_goto_if_exists(chan, context, exten, priority, 0);
    }
    
    int ast_async_goto_if_exists(struct ast_channel *chan, char* context, char *exten, int priority) {
    	return __ast_goto_if_exists(chan, context, exten, priority, 1);
    }
    
    
    int ast_parseable_goto(struct ast_channel *chan, const char *goto_string) 
    {
    	char *s;
    	char *exten, *pri, *context;
    	char *stringp=NULL;
    	int ipri;
    	int mode = 0;
    
    	if (!goto_string || ast_strlen_zero(goto_string)) {
    		ast_log(LOG_WARNING, "Goto requires an argument (optional context|optional extension|priority)\n");
    		return -1;
    	}
    	s = ast_strdupa(goto_string);
    	stringp=s;
    	context = strsep(&stringp, "|");
    	exten = strsep(&stringp, "|");
    	if (!exten) {
    		/* Only a priority in this one */
    		pri = context;
    		exten = NULL;
    		context = NULL;
    	} else {
    		pri = strsep(&stringp, "|");
    		if (!pri) {
    			/* Only an extension and priority in this one */
    			pri = exten;
    			exten = context;
    			context = NULL;
    		}
    	}
    	if (*pri == '+') {
    		mode = 1;
    		pri++;
    	} else if (*pri == '-') {
    		mode = -1;
    		pri++;
    	}
    	if (sscanf(pri, "%i", &ipri) != 1) {
    		if ((ipri = ast_findlabel_extension(chan, context ? context : chan->context, (exten && strcasecmp(exten, "BYEXTENSION")) ? exten : chan->exten, 
    			pri, chan->cid.cid_num)) < 1) {
    			ast_log(LOG_WARNING, "Priority '%s' must be a number > 0, or valid label\n", pri);
    			return -1;
    		} else
    			mode = 0;
    	} 
    	/* At this point we have a priority and maybe an extension and a context */
    
    	if (exten && !strcasecmp(exten, "BYEXTENSION"))
    		exten = NULL;
    
    	if (mode) 
    		ipri = chan->priority + (ipri * mode);
    
    	/* This channel is currently in the PBX */
    
    	ast_explicit_goto(chan, context, exten, ipri - 1);