Skip to content
Snippets Groups Projects
pbx.c 164 KiB
Newer Older
/*!
 * \ingroup applications
 */
static int pbx_builtin_setamaflags(struct ast_channel *chan, void *data)
{
	/* Copy the AMA Flags as specified */
	ast_cdr_setamaflags(chan, data ? data : "");
/*!
 * \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
{
	if (!ast_strlen_zero(data)) {
		int cause;
		char *endptr;

		if ((cause = ast_str2cause(data)) > -1) {
			chan->hangupcause = cause;
			return -1;
		}
		
		cause = strtol((const char *) data, &endptr, 10);
		if (cause != 0 || (data != endptr)) {
			chan->hangupcause = cause;
			return -1;
		}
			
		ast_log(LOG_NOTICE, "Invalid cause given to Hangup(): \"%s\"\n", (char *) data);
	}

	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)
{
	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;
	}

	/* 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, ts);
	
/*!
 * \ingroup applications
 */
static int pbx_builtin_execiftime(struct ast_channel *chan, void *data)
{
	char *s, *appname;
	struct ast_timing timing;
	static const char *usage = "ExecIfTime requires an argument:\n  <time range>|<days of week>|<days of month>|<months>?<appname>[|<appargs>]";
Luigi Rizzo's avatar
Luigi Rizzo committed
		ast_log(LOG_WARNING, "%s\n", usage);
	s = strsep(&appname,"?");	/* Separate the timerange and application name/data */
	if (!appname) {	/* missing application */
		ast_log(LOG_WARNING, "%s\n", usage);
		return -1;
	}

	if (!ast_build_timing(&timing, s)) {
		ast_log(LOG_WARNING, "Invalid Time Spec: %s\nCorrect usage: %s\n", s, usage);
		return -1;
	if (!ast_check_timing(&timing))	/* outside the valid time window, just return */
		return 0;
	/* now split appname|appargs */
	if ((s = strchr(appname, '|')))
		*s++ = '\0';
	if ((app = pbx_findapp(appname))) {
		return pbx_exec(chan, app, S_OR(s, ""));
	} else {
		ast_log(LOG_WARNING, "Cannot locate application %s\n", appname);
		return -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 && (ms = atof(data)) > 0) {
		ms *= 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)
{
	char *parse;
	AST_DECLARE_APP_ARGS(args,
		AST_APP_ARG(timeout);
		AST_APP_ARG(options);
	);
		AST_STANDARD_APP_ARGS(args, parse);
	} else
		memset(&args, 0, sizeof(args));
	if (args.options)
		ast_app_parse_options(waitexten_opts, &flags, opts, args.options);
		ast_moh_start(chan, opts[0]);
	/* Wait for "n" seconds */
	if (args.timeout && (ms = atof(args.timeout)) > 0)
		 ms *= 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);
			set_ext_pri(chan, "t", 0); /* XXX is the 0 correct ? */
Mark Spencer's avatar
Mark Spencer committed
		} 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;
	AST_DECLARE_APP_ARGS(args,
		AST_APP_ARG(filename);
		AST_APP_ARG(options);
		AST_APP_ARG(lang);
		AST_APP_ARG(context);
	);
	if (ast_strlen_zero(data))
		ast_log(LOG_WARNING, "Background requires an argument (filename)\n");
	AST_STANDARD_APP_ARGS(args, parse);
Luigi Rizzo's avatar
Luigi Rizzo committed
		args.lang = (char *)chan->language;	/* XXX this is const */
	if (!args.context)
		args.context = chan->context;

	if (args.options) {
		if (!strcasecmp(args.options, "skip"))
		else if (!strcasecmp(args.options, "noanswer"))
			ast_app_parse_options(background_opts, &flags, NULL, args.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) {
Luigi Rizzo's avatar
Luigi Rizzo committed
		char *back = args.filename;
		char *front;
		ast_stopstream(chan);		/* Stop anything playing */
		/* Stream the list of files */
		while (!res && (front = strsep(&back, "&")) ) {
			if ( (res = ast_streamfile(chan, front, args.lang)) ) {
				ast_log(LOG_WARNING, "ast_streamfile failed on %s for %s\n", chan->name, (char*)data);
				res = 0;
				break;
			}
Luigi Rizzo's avatar
Luigi Rizzo committed
			if (ast_test_flag(&flags, BACKGROUND_PLAYBACK)) {
				res = ast_waitstream(chan, "");
			} else if (ast_test_flag(&flags, BACKGROUND_MATCHEXTEN)) {
				res = ast_waitstream_exten(chan, args.context);
			} else {
				res = ast_waitstream(chan, AST_DIGIT_ANY);
			}
			ast_stopstream(chan);
	if (args.context != chan->context && res) {
		snprintf(chan->exten, sizeof(chan->exten), "%c", res);
		ast_copy_string(chan->context, args.context, sizeof(chan->context));
Luigi Rizzo's avatar
Luigi Rizzo committed
		res = 0;
Luigi Rizzo's avatar
Luigi Rizzo committed
	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 = ast_parseable_goto(chan, 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
}
Luigi Rizzo's avatar
Luigi Rizzo 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");
Luigi Rizzo's avatar
Luigi Rizzo committed
		} else
Luigi Rizzo's avatar
Luigi Rizzo committed
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;
	int i;
	struct varshead *places[2] = { NULL, &globals };
		if (!places[i])
			continue;
		if (places[i] == &globals)
			ast_mutex_lock(&globalslock);
		AST_LIST_TRAVERSE(places[i], variables, entries) {
			if (!strcmp(name, ast_var_name(variables))) {
				ret = ast_var_value(variables);
				break;
		if (places[i] == &globals)
			ast_mutex_unlock(&globalslock);
		if (ret)
			break;
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] == ')') {
		char *function = ast_strdupa(name);

Kevin P. Fleming's avatar
Kevin P. Fleming committed
		ast_log(LOG_WARNING, "Cannot push a value onto a function\n");
		ast_func_write(chan, function, value);
		return;
Kevin P. Fleming's avatar
Kevin P. Fleming committed
	}

	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);
		if (headp == &globals)
			ast_mutex_lock(&globalslock);
Kevin P. Fleming's avatar
Kevin P. Fleming committed
		AST_LIST_INSERT_HEAD(headp, newvariable, entries);
		if (headp == &globals)
			ast_mutex_unlock(&globalslock);
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;
	/* XXX may need locking on the channel ? */
	if (name[strlen(name)-1] == ')') {
		char *function = ast_strdupa(name);
		ast_func_write(chan, function, value);
		return;
	}
	headp = (chan) ? &chan->varshead : &globals;
	/* For comparison purposes, we have to strip leading underscores */
	if (*nametail == '_') {
		nametail++;
Luigi Rizzo's avatar
Luigi Rizzo committed
		if (*nametail == '_')
	if (headp == &globals)
		ast_mutex_lock(&globalslock);
	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);
Luigi Rizzo's avatar
Luigi Rizzo committed
		newvariable = ast_var_assign(name, value);
		AST_LIST_INSERT_HEAD(headp, newvariable, entries);
	if (headp == &globals)
		ast_mutex_unlock(&globalslock);
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, '='))) {
			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 *channel;
	char tmp[VAR_BUF_SIZE]="";
		ast_log(LOG_WARNING, "Ignoring, since there is no variable to set\n");
		return 0;
	}

	value = ast_strdupa(data);
	name = strsep(&value,"=");
Luigi Rizzo's avatar
Luigi Rizzo committed
	channel = strsep(&value,"|");
	if (channel && value && name) { /*! \todo XXX should do !ast_strlen_zero(..) of the args ? */
		struct ast_channel *chan2 = ast_get_channel_by_name_locked(channel);
		if (chan2) {
			char *s = alloca(strlen(value) + 4);
			if (s) {
				sprintf(s, "${%s}", value);
				pbx_substitute_variables_helper(chan2, s, tmp, sizeof(tmp) - 1);
			}
			ast_channel_unlock(chan2);
		}
		pbx_builtin_setvar_helper(chan, name, tmp);
	}

	return(0);
}

/*! \todo XXX overwrites data ? */
static int pbx_builtin_setglobalvar(struct ast_channel *chan, void *data)
{
	char *name;
		ast_log(LOG_WARNING, "Ignoring, since there is no variable to set\n");
		return 0;
	}

	name = strsep(&stringp, "=");

	if (!dep_warning) {
		dep_warning = 1;
		ast_log(LOG_WARNING, "SetGlobalVar is deprecated.  Please use Set(GLOBAL(%s)=%s) instead.\n", name, stringp);
	}

	/*! \todo XXX watch out, leading whitespace ? */
	pbx_builtin_setvar_helper(NULL, name, stringp);
static int pbx_builtin_noop(struct ast_channel *chan, void *data)
{
	return 0;
}

void pbx_builtin_clear_globals(void)
{
	struct ast_var_t *vardata;

	ast_mutex_lock(&globalslock);
	while ((vardata = AST_LIST_REMOVE_HEAD(&globals, entries)))
		ast_var_delete(vardata);
	ast_mutex_unlock(&globalslock);
Luigi Rizzo's avatar
Luigi Rizzo committed
int pbx_checkcondition(const char *condition)
	if (ast_strlen_zero(condition))	/* NULL or empty strings are false */
Mark Spencer's avatar
Mark Spencer committed
		return 0;
	else if (*condition >= '0' && *condition <= '9')	/* Numbers are evaluated for truth */
		return atoi(condition);
Russell Bryant's avatar
Russell Bryant committed
	else	/* Strings are true */
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
	int rc;
	char *stringp;
		ast_log(LOG_WARNING, "Ignoring, since there is no variable to check\n");
Mark Spencer's avatar
Mark Spencer committed
		return 0;
	}
	condition = strsep(&stringp,"?");
	branch1 = strsep(&stringp,":");
	branch2 = strsep(&stringp,"");
	branch = pbx_checkcondition(condition) ? branch1 : branch2;
		ast_log(LOG_DEBUG, "Not taking any branch\n");
Mark Spencer's avatar
Mark Spencer committed
	}
	rc = pbx_builtin_goto(chan, branch);
Mark Spencer's avatar
Mark Spencer committed

static int pbx_builtin_saynumber(struct ast_channel *chan, void *data)
{
	char *number = tmp;
	char *options;
		ast_log(LOG_WARNING, "SayNumber requires an argument (number)\n");
		return -1;
	}
	ast_copy_string(tmp, data, sizeof(tmp));
	strsep(&number, "|");
	options = strsep(&number, "|");
Luigi Rizzo's avatar
Luigi Rizzo committed
	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 ast_say_number(chan, atoi(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, 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;
		res = ast_say_character_str(chan, data, "", chan->language);
static int pbx_builtin_sayphonetic(struct ast_channel *chan, void *data)
{
	int res = 0;
		res = ast_say_phonetic_str(chan, data, "", chan->language);
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_cli_register_multiple(pbx_cli, sizeof(pbx_cli) / sizeof(pbx_cli[0]));

	/* 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;
}

struct ast_context *ast_get_extension_context(struct ast_exten *exten)
{
	return exten ? exten->parent : 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)
{
Russell Bryant's avatar
Russell Bryant committed
	return con ? con->next : contexts;
Mark Spencer's avatar
Mark Spencer committed
}

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 ? AST_LIST_FIRST(&con->alts) : NULL;
Mark Spencer's avatar
Mark Spencer committed
	else
		return AST_LIST_NEXT(sw, list);
Mark Spencer's avatar
Mark Spencer committed
}

struct ast_exten *ast_walk_extension_priorities(struct ast_exten *exten,
	struct ast_exten *priority)
{
Russell Bryant's avatar
Russell Bryant committed
	return priority ? priority->peer : exten;
Mark Spencer's avatar
Mark Spencer committed
}

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)
{
Russell Bryant's avatar
Russell Bryant committed
	struct ast_include *inc = NULL;
Russell Bryant's avatar
Russell Bryant committed
	while ( (inc = ast_walk_context_includes(con, inc)) )
		if (!ast_context_find(inc->rname)) {
			res = -1;
			ast_log(LOG_WARNING, "Context '%s' tries includes nonexistent context '%s'\n",
					ast_get_context_name(con), inc->rname);
		}
	return res;
}
Luigi Rizzo's avatar
Luigi Rizzo committed
static int __ast_goto_if_exists(struct ast_channel *chan, const char *context, const char *exten, int priority, int async)
	int (*goto_func)(struct ast_channel *chan, const char *context, const char *exten, int priority);
	if (context == NULL)
		context = chan->context;
	if (exten == NULL)
		exten = chan->exten;

	goto_func = (async) ? ast_async_goto : ast_explicit_goto;
	if (ast_exists_extension(chan, context, exten, priority, chan->cid.cid_num))
		return goto_func(chan, context, exten, priority);
Luigi Rizzo's avatar
Luigi Rizzo committed
	else
int ast_goto_if_exists(struct ast_channel *chan, const char* context, const char *exten, int priority)
{
	return __ast_goto_if_exists(chan, context, exten, priority, 0);
}

int ast_async_goto_if_exists(struct ast_channel *chan, const char * context, const char *exten, int priority)
{
	return __ast_goto_if_exists(chan, context, exten, priority, 1);
}

Luigi Rizzo's avatar
Luigi Rizzo committed
int ast_parseable_goto(struct ast_channel *chan, const char *goto_string)
{
	char *exten, *pri, *context;
	if (ast_strlen_zero(goto_string)) {
		ast_log(LOG_WARNING, "Goto requires an argument (optional context|optional extension|priority)\n");
		return -1;
	}
	stringp = ast_strdupa(goto_string);
	context = strsep(&stringp, "|");	/* guaranteed non-null */
	exten = strsep(&stringp, "|");
	pri = strsep(&stringp, "|");
	if (!exten) {	/* Only a priority in this one */
		pri = context;
		exten = NULL;
		context = NULL;
	} else if (!pri) {	/* Only an extension and priority in this one */
		pri = exten;
		exten = context;
		context = NULL;
	}
	if (*pri == '+') {
		mode = 1;
		pri++;
	} else if (*pri == '-') {
		mode = -1;
		pri++;
	}
Luigi Rizzo's avatar
Luigi Rizzo committed
		if ((ipri = ast_findlabel_extension(chan, context ? context : chan->context, exten ? 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 */

Luigi Rizzo's avatar
Luigi Rizzo committed
	if (mode)
		ipri = chan->priority + (ipri * mode);

	ast_explicit_goto(chan, context, exten, ipri);
	ast_cdr_update(chan);
	return 0;

}