예제 #1
0
/*!
 * \brief [lua_CFunction] Used to set the value of a variable or dialplan
 * function (for access from lua, don't call directly)
 * 
 * This function is the 'set()' function in the following example as would be
 * seen in extensions.lua.
 *
 * \code
 * channel.variable:set("value")
 * \endcode
 */
static int lua_set_variable_value(lua_State *L)
{
	const char *name, *value;
	struct ast_channel *chan;
	int autoservice;

	if (!lua_istable(L, 1)) {
		lua_pushstring(L, "User probably used '.' instead of ':' for setting a channel variable");
		return lua_error(L);
	}

	lua_getfield(L, 1, "name");
	name = ast_strdupa(lua_tostring(L, -1));
	lua_pop(L, 1);

	value = luaL_checkstring(L, 2);
	
	lua_getfield(L, LUA_REGISTRYINDEX, "channel");
	chan = lua_touserdata(L, -1);
	lua_pop(L, 1);

	lua_getfield(L, LUA_REGISTRYINDEX, "autoservice");
	autoservice = lua_toboolean(L, -1);
	lua_pop(L, 1);

	if (autoservice)
		ast_autoservice_stop(chan);

	pbx_builtin_setvar_helper(chan, name, value);
	
	if (autoservice)
		ast_autoservice_start(chan);

	return 0;
}
예제 #2
0
static int shell_helper(struct ast_channel *chan, const char *cmd, char *data,
		                         char *buf, size_t len)
{
	if (ast_strlen_zero(data)) {
		ast_log(LOG_WARNING, "Missing Argument!  Example:  Set(foo=${SHELL(echo \"bar\")})\n");
		return -1;
	}

	if (chan)
		ast_autoservice_start(chan);

	if (len >= 1) {
		FILE *ptr;
		char plbuff[4096];

		ptr = popen(data, "r");
		while (fgets(plbuff, sizeof(plbuff), ptr)) {
			strncat(buf, plbuff, len - strlen(buf) - 1);
		}
		pclose(ptr);
	}

	if (chan)
		ast_autoservice_stop(chan);

	return 0;
}
예제 #3
0
/*!
 * \brief [lua_CFunction] Set the value of a channel variable or dialplan
 * function (for access from lua, don't call directly)
 * 
 * This function is called to set a variable or dialplan function.  It would be
 * called in the following example as would be seen in extensions.lua.
 *
 * \code
 * channel.variable = "value"
 * \endcode
 */
static int lua_set_variable(lua_State *L)
{
	struct ast_channel *chan;
	int autoservice;
	const char *name = luaL_checkstring(L, 2);
	const char *value = luaL_checkstring(L, 3);

	lua_getfield(L, LUA_REGISTRYINDEX, "channel");
	chan = lua_touserdata(L, -1);
	lua_pop(L, 1);

	lua_getfield(L, LUA_REGISTRYINDEX, "autoservice");
	autoservice = lua_toboolean(L, -1);
	lua_pop(L, 1);

	if (autoservice)
		ast_autoservice_stop(chan);

	pbx_builtin_setvar_helper(chan, name, value);
	
	if (autoservice)
		ast_autoservice_start(chan);

	return 0;
}
예제 #4
0
파일: func_srv.c 프로젝트: cfhb/vlink-cti
static struct srv_context *srv_datastore_setup(const char *service, struct ast_channel *chan)
{
	struct srv_result_datastore *srds;
	struct ast_datastore *datastore;
	const char *host;
	unsigned short port;

	if (!(srds = ast_calloc(1, sizeof(*srds) + strlen(service)))) {
		return NULL;
	}

	ast_autoservice_start(chan);
	if (ast_srv_lookup(&srds->context, service, &host, &port) < 0) {
		ast_autoservice_stop(chan);
		ast_log(LOG_NOTICE, "Error performing lookup of service '%s'\n", service);
		ast_free(srds);
		return NULL;
	}
	ast_autoservice_stop(chan);

	strcpy(srds->id, service);

	if (!(datastore = ast_datastore_alloc(&srv_result_datastore_info, srds->id))) {
		ast_srv_cleanup(&srds->context);
		ast_free(srds);
		return NULL;
	}

	datastore->data = srds;
	ast_channel_lock(chan);
	ast_channel_datastore_add(chan, datastore);
	ast_channel_unlock(chan);
	return srds->context;
}
예제 #5
0
/*--- ast_get_txt: Get TXT record from DNS.
	Really has nothing to do with enum, but anyway...
 */
int ast_get_txt(struct ast_channel *chan, const char *number, char *dst, int dstlen, char *tech, int techlen, char *txt, int txtlen)
{
	struct enum_context context;
	char tmp[259 + 512];
	char naptrinput[512] = "+";
	int pos = strlen(number) - 1;
	int newpos = 0;
	int ret = -1;
	struct enum_search *s = NULL;
	int version = -1;

	strncat(naptrinput, number, sizeof(naptrinput) - 2);

	context.naptrinput = naptrinput;
	context.dst = dst;
	context.dstlen = dstlen;
	context.tech = tech;
	context.techlen = techlen;
	context.txt = txt;
	context.txtlen = txtlen;

	if (pos > 128)
		pos = 128;
	while (pos >= 0) {
		tmp[newpos++] = number[pos--];
		tmp[newpos++] = '.';
	}

	if (chan && ast_autoservice_start(chan) < 0)
		return -1;

	for (;;) {
		ast_mutex_lock(&enumlock);
		if (version != enumver) {
			/* Ooh, a reload... */
			s = toplevs;
			version = enumver;
		} else {
			s = s->next;
		}
		if (s) {
			strncpy(tmp + newpos, s->toplev, sizeof(tmp) - newpos - 1);
		}
		ast_mutex_unlock(&enumlock);
		if (!s)
			break;

		ret = ast_search_dns(&context, tmp, C_IN, T_TXT, txt_callback);
		if (ret > 0)
			break;
	}
	if (ret < 0) {
		ast_log(LOG_DEBUG, "No such number found: %s (%s)\n", tmp, strerror(errno));
		ret = 0;
	}
	if (chan)
		ret |= ast_autoservice_stop(chan);
	return ret;
}
예제 #6
0
/*!
 * \brief [lua_CFunction] Used to get the value of a variable or dialplan
 * function (for access from lua, don't call directly)
 *
 * The value of the variable or function is returned.  This function is the
 * 'get()' function in the following example as would be seen in
 * extensions.lua.
 *
 * \code
 * channel.variable:get()
 * \endcode
 */
static int lua_get_variable_value(lua_State *L)
{
	struct ast_channel *chan;
	char *value = NULL, *name;
	char *workspace = alloca(LUA_BUF_SIZE);
	int autoservice;

	workspace[0] = '\0';

	if (!lua_istable(L, 1)) {
		lua_pushstring(L, "User probably used '.' instead of ':' for retrieving a channel variable value");
		return lua_error(L);
	}
	
	lua_getfield(L, LUA_REGISTRYINDEX, "channel");
	chan = lua_touserdata(L, -1);
	lua_pop(L, 1);

	lua_getfield(L, 1, "name");
	name = ast_strdupa(lua_tostring(L, -1));
	lua_pop(L, 1);
	
	lua_getfield(L, LUA_REGISTRYINDEX, "autoservice");
	autoservice = lua_toboolean(L, -1);
	lua_pop(L, 1);

	if (autoservice)
		ast_autoservice_stop(chan);
	
	/* if this is a dialplan function then use ast_func_read(), otherwise
	 * use pbx_retrieve_variable() */
	if (!ast_strlen_zero(name) && name[strlen(name) - 1] == ')') {
		value = ast_func_read(chan, name, workspace, LUA_BUF_SIZE) ? NULL : workspace;
	} else {
		pbx_retrieve_variable(chan, name, &value, workspace, LUA_BUF_SIZE, ast_channel_varshead(chan));
	}
	
	if (autoservice)
		ast_autoservice_start(chan);

	if (value) {
		lua_pushstring(L, value);
	} else {
		lua_pushnil(L);
	}

	return 1;
}
예제 #7
0
파일: app_system.c 프로젝트: mtulio/mtulio
static int system_exec_helper(struct ast_channel *chan, const char *data, int failmode)
{
	int res = 0;
	struct ast_str *buf = ast_str_thread_get(&buf_buf, 16);
	char *cbuf;

	if (ast_strlen_zero(data)) {
		ast_log(LOG_WARNING, "System requires an argument(command)\n");
		pbx_builtin_setvar_helper(chan, chanvar, "FAILURE");
		return failmode;
	}

	ast_autoservice_start(chan);

	/* Do our thing here */
	ast_str_get_encoded_str(&buf, 0, (char *) data);
	cbuf = ast_str_buffer(buf);

	if (strchr("\"'", cbuf[0]) && cbuf[ast_str_strlen(buf) - 1] == cbuf[0]) {
		cbuf[ast_str_strlen(buf) - 1] = '\0';
		cbuf++;
		ast_log(LOG_NOTICE, "It is not necessary to quote the argument to the System application.\n");
	}

	res = ast_safe_system(cbuf);

	if ((res < 0) && (errno != ECHILD)) {
		ast_log(LOG_WARNING, "Unable to execute '%s'\n", (char *)data);
		pbx_builtin_setvar_helper(chan, chanvar, "FAILURE");
		res = failmode;
	} else if (res == 127) {
		ast_log(LOG_WARNING, "Unable to execute '%s'\n", (char *)data);
		pbx_builtin_setvar_helper(chan, chanvar, "FAILURE");
		res = failmode;
	} else {
		if (res < 0) 
			res = 0;
		if (res != 0)
			pbx_builtin_setvar_helper(chan, chanvar, "APPERROR");
		else
			pbx_builtin_setvar_helper(chan, chanvar, "SUCCESS");
		res = 0;
	} 

	ast_autoservice_stop(chan);

	return res;
}
예제 #8
0
int ast_dtmf_stream(struct ast_channel *chan,struct ast_channel *peer,char *digits,int between)
{
    char *ptr=NULL;
    int res=0;
    struct ast_frame f;
    if (!between)
        between = 100;

    if (peer)
        res = ast_autoservice_start(peer);

    if (!res) {
        res = ast_waitfor(chan,100);
        if (res > -1) {
            for (ptr=digits; *ptr; *ptr++) {
                if (*ptr == 'w') {
                    res = ast_safe_sleep(chan, 500);
                    if (res)
                        break;
                    continue;
                }
                memset(&f, 0, sizeof(f));
                f.frametype = AST_FRAME_DTMF;
                f.subclass = *ptr;
                f.src = "ast_dtmf_stream";
                if (strchr("0123456789*#abcdABCD",*ptr)==NULL) {
                    ast_log(LOG_WARNING, "Illegal DTMF character '%c' in string. (0-9*#aAbBcCdD allowed)\n",*ptr);
                } else {
                    res = ast_write(chan, &f);
                    if (res)
                        break;
                    /* pause between digits */
                    res = ast_safe_sleep(chan,between);
                    if (res)
                        break;
                }
            }
        }
        if (peer)
            res = ast_autoservice_stop(peer);
    }
    return res;
}
예제 #9
0
int ast_get_txt(struct ast_channel *chan, const char *number, char *txt, int txtlen, char *suffix)
{
	struct txt_context context;
	char tmp[259 + 512];
	int pos = strlen(number) - 1;
	int newpos = 0;
	int ret = -1;

	ast_debug(4, "ast_get_txt: Number = '%s', suffix = '%s'\n", number, suffix);

	if (chan && ast_autoservice_start(chan) < 0) {
		return -1;
	}

	if (pos > 128) {
		pos = 128;
	}

	while (pos >= 0) {
		if (isdigit(number[pos])) {
			tmp[newpos++] = number[pos];
			tmp[newpos++] = '.';
		}
		pos--;
	}

	ast_copy_string(&tmp[newpos], suffix, sizeof(tmp) - newpos);

	if (ret < 0) {
		ast_debug(2, "No such number found in ENUM: %s (%s)\n", tmp, strerror(errno));
		ret = 0;
	} else {
		ast_copy_string(txt, context.txt, txtlen);
	}
	if (chan) {
		ret |= ast_autoservice_stop(chan);
	}
	return ret;
}
예제 #10
0
static int system_exec_helper(struct ast_channel *chan, void *data, int failmode)
{
	int res = 0;
	struct ast_str *buf = ast_str_thread_get(&buf_buf, 16);
	
	if (ast_strlen_zero(data)) {
		ast_log(LOG_WARNING, "System requires an argument(command)\n");
		pbx_builtin_setvar_helper(chan, chanvar, "FAILURE");
		return failmode;
	}

	ast_autoservice_start(chan);

	/* Do our thing here */
	ast_str_get_encoded_str(&buf, 0, (char *) data);
	res = ast_safe_system(ast_str_buffer(buf));

	if ((res < 0) && (errno != ECHILD)) {
		ast_log(LOG_WARNING, "Unable to execute '%s'\n", (char *)data);
		pbx_builtin_setvar_helper(chan, chanvar, "FAILURE");
		res = failmode;
	} else if (res == 127) {
		ast_log(LOG_WARNING, "Unable to execute '%s'\n", (char *)data);
		pbx_builtin_setvar_helper(chan, chanvar, "FAILURE");
		res = failmode;
	} else {
		if (res < 0) 
			res = 0;
		if (res != 0)
			pbx_builtin_setvar_helper(chan, chanvar, "APPERROR");
		else
			pbx_builtin_setvar_helper(chan, chanvar, "SUCCESS");
		res = 0;
	} 

	ast_autoservice_stop(chan);

	return res;
}
예제 #11
0
/*!
 * \brief [lua_CFunction] Tell pbx_lua to maintain an autoservice on this
 * channel (for access from lua, don't call directly)
 *
 * \param L the lua_State to use
 *
 * This function will set a flag that will cause pbx_lua to maintain an
 * autoservice on this channel.  The autoservice will automatically be stopped
 * and restarted before calling applications and functions.
 */
static int lua_autoservice_start(lua_State *L)
{
	struct ast_channel *chan;

	lua_getfield(L, LUA_REGISTRYINDEX, "autoservice");
	if (lua_toboolean(L, -1)) {
		/* autservice already running */
		lua_pop(L, 1);
		return 0;
	}
	lua_pop(L, 1);

	lua_getfield(L, LUA_REGISTRYINDEX, "channel");
	chan = lua_touserdata(L, -1);
	lua_pop(L, 1);

	ast_autoservice_start(chan);

	lua_pushboolean(L, 1);
	lua_setfield(L, LUA_REGISTRYINDEX, "autoservice");
	return 0;
}
예제 #12
0
int ast_get_srv(struct ast_channel *chan, char *host, int hostlen, int *port, const char *service)
{
	struct srv_context context;
	int ret;

	context.host = host;
	context.hostlen = hostlen;
	context.port = port;

	if (chan && ast_autoservice_start(chan) < 0)
		return -1;

	ret = ast_search_dns(&context, service, C_IN, T_SRV, srv_callback);

	if (chan)
		ret |= ast_autoservice_stop(chan);

	if (ret <= 0) {
		host[0] = '\0';
		*port = -1;
		return ret;
	}
	return ret;
}
예제 #13
0
/*!
 * \brief [lua_CFunction] This function is part of the 'application' metatable
 * and is used to execute applications similar to pbx_exec() (for access from
 * lua, don't call directly)
 *
 * \param L the lua_State to use
 * \return nothing
 *
 * This funciton is executed as the '()' operator for apps accessed through the
 * 'app' table.
 *
 * \code
 * app.playback('demo-congrats')
 * \endcode
 */
static int lua_pbx_exec(lua_State *L)
{
	int res, nargs = lua_gettop(L);
	char data[LUA_EXT_DATA_SIZE] = "";
	char *data_next = data, *app_name;
	char *context, *exten;
	char tmp[80], tmp2[80], tmp3[LUA_EXT_DATA_SIZE];
	int priority, autoservice;
	size_t data_left = sizeof(data);
	struct ast_app *app;
	struct ast_channel *chan;
	
	lua_getfield(L, 1, "name");
	app_name = ast_strdupa(lua_tostring(L, -1));
	lua_pop(L, 1);
	
	if (!(app = pbx_findapp(app_name))) {
		lua_pushstring(L, "application '");
		lua_pushstring(L, app_name);
		lua_pushstring(L, "' not found");
		lua_concat(L, 3);
		return lua_error(L);
	}
	

	lua_getfield(L, LUA_REGISTRYINDEX, "channel");
	chan = lua_touserdata(L, -1);
	lua_pop(L, 1);
	
	
	lua_getfield(L, LUA_REGISTRYINDEX, "context");
	context = ast_strdupa(lua_tostring(L, -1));
	lua_pop(L, 1);
	
	lua_getfield(L, LUA_REGISTRYINDEX, "exten");
	exten = ast_strdupa(lua_tostring(L, -1));
	lua_pop(L, 1);
	
	lua_getfield(L, LUA_REGISTRYINDEX, "priority");
	priority = lua_tointeger(L, -1);
	lua_pop(L, 1);


	if (nargs > 1) {
		int i;

		if (!lua_isnil(L, 2))
			ast_build_string(&data_next, &data_left, "%s", luaL_checkstring(L, 2));

		for (i = 3; i <= nargs; i++) {
			if (lua_isnil(L, i))
				ast_build_string(&data_next, &data_left, ",");
			else
				ast_build_string(&data_next, &data_left, ",%s", luaL_checkstring(L, i));
		}
	}
	
	ast_verb(3, "Executing [%s@%s:%d] %s(\"%s\", \"%s\")\n",
			exten, context, priority,
			term_color(tmp, app_name, COLOR_BRCYAN, 0, sizeof(tmp)),
			term_color(tmp2, chan->name, COLOR_BRMAGENTA, 0, sizeof(tmp2)),
			term_color(tmp3, data, COLOR_BRMAGENTA, 0, sizeof(tmp3)));

	lua_getfield(L, LUA_REGISTRYINDEX, "autoservice");
	autoservice = lua_toboolean(L, -1);
	lua_pop(L, 1);

	if (autoservice)
		ast_autoservice_stop(chan);

	res = pbx_exec(chan, app, data);
	
	if (autoservice)
		ast_autoservice_start(chan);

	/* error executing an application, report it */
	if (res) {
		lua_pushinteger(L, res);
		return lua_error(L);
	}
	return 0;
}
예제 #14
0
/*--- ast_get_enum: ENUM lookup */
int ast_get_enum(struct ast_channel *chan, const char *number, char *dst, int dstlen, char *tech, int techlen, char* suffix, char* options)
{
	struct enum_context context;
	char tmp[259 + 512];
	char naptrinput[512];
	int pos = strlen(number) - 1;
	int newpos = 0;
	int ret = -1;
	struct enum_search *s = NULL;
	int version = -1;
	/* for ISN rewrite */
	char *p1 = NULL;
	char *p2 = NULL;
	int k = 0;
	int i = 0;
	int z = 0;

	if (number[0] == 'n') {
		strncpy(naptrinput, number+1, sizeof(naptrinput));
	} else {
		strncpy(naptrinput, number, sizeof(naptrinput));
	}

	context.naptrinput = naptrinput;	/* The number */
	context.dst = dst;			/* Return string */
	context.dstlen = dstlen;
	context.tech = tech;
	context.techlen = techlen;
	context.options = 0;
	context.position = 1;
	context.naptr_rrs = NULL;
	context.naptr_rrs_count = 0;

	if (options != NULL){
		if (*options == 'c'){
			context.options = ENUMLOOKUP_OPTIONS_COUNT;
			context.position = 0;
		} else {
			context.position = atoi(options);
			if (context.position < 1)
				context.position = 1;
		}
	}

	if (pos > 128)
		pos = 128;

	/* ISN rewrite */
	p1 = strchr(number, '*');

	if (number[0] == 'n') { /* do not perform ISN rewrite ('n' is testing flag) */
		p1 = NULL;
		k = 1; /* strip 'n' from number */
	}

	if (p1 != NULL) {
		p2 = p1+1;
		while (p1 > number){
			p1--;
			tmp[newpos++] = *p1;
			tmp[newpos++] = '.';
		}
		if (*p2) {
			while(*p2 && newpos < 128){
				tmp[newpos++] = *p2;
				p2++;
			}
			tmp[newpos++] = '.';
		}

	} else {
		while (pos >= k) {
			if (isdigit(number[pos])) {
				tmp[newpos++] = number[pos];
				tmp[newpos++] = '.';
			}
			pos--;
		}
	}

	if (chan && ast_autoservice_start(chan) < 0)
		return -1;

	for (;;) {
		ast_mutex_lock(&enumlock);
		if (version != enumver) {
			/* Ooh, a reload... */
			s = toplevs;
			version = enumver;
		} else {
			s = s->next;
		}
		if (suffix != NULL) {
			strncpy(tmp + newpos, suffix, sizeof(tmp) - newpos - 1);
		} else if (s) {
			strncpy(tmp + newpos, s->toplev, sizeof(tmp) - newpos - 1);
		}
		ast_mutex_unlock(&enumlock);
		if (!s)
			break;
		ret = ast_search_dns(&context, tmp, C_IN, T_NAPTR, enum_callback);
		if (ret > 0)
			break;
		if (suffix != NULL)
                       break;
	}
	if (ret < 0) {
		ast_log(LOG_DEBUG, "No such number found: %s (%s)\n", tmp, strerror(errno));
		ret = 0;
	}

	if (context.naptr_rrs_count >= context.position && ! (context.options & ENUMLOOKUP_OPTIONS_COUNT)) {
		/* sort array by NAPTR order/preference/tech */
		for (k = 0; k < context.naptr_rrs_count; k++) {
			for (i = 0; i < context.naptr_rrs_count; i++) {
				/* Compare by order first. */
				if ((ntohs(context.naptr_rrs[k].naptr.order) < ntohs(context.naptr_rrs[i].naptr.order)
						&& context.naptr_rrs[k].sort_pos > context.naptr_rrs[i].sort_pos)
					|| (ntohs(context.naptr_rrs[k].naptr.order) > ntohs(context.naptr_rrs[i].naptr.order)
						&& context.naptr_rrs[k].sort_pos < context.naptr_rrs[i].sort_pos)){
					z = context.naptr_rrs[k].sort_pos;
					context.naptr_rrs[k].sort_pos = context.naptr_rrs[i].sort_pos;
					context.naptr_rrs[i].sort_pos = z;
				} else if (ntohs(context.naptr_rrs[k].naptr.order) == ntohs(context.naptr_rrs[i].naptr.order)) {
					/* Order is the same, so sort by preference next */
					if (ntohs(context.naptr_rrs[k].naptr.pref) == ntohs(context.naptr_rrs[i].naptr.pref)) {
						/* Preference is the same, so sort by tech */
						if ((strcmp(context.naptr_rrs[k].tech, context.naptr_rrs[i].tech) < 0
								&& context.naptr_rrs[k].sort_pos > context.naptr_rrs[i].sort_pos)
							|| (strcmp(context.naptr_rrs[k].tech, context.naptr_rrs[i].tech) > 0
								&& context.naptr_rrs[k].sort_pos < context.naptr_rrs[i].sort_pos)) {
							z = context.naptr_rrs[k].sort_pos;
							context.naptr_rrs[k].sort_pos = context.naptr_rrs[i].sort_pos;
							context.naptr_rrs[i].sort_pos = z;
						}
					} else if ((ntohs(context.naptr_rrs[k].naptr.pref) < ntohs(context.naptr_rrs[i].naptr.pref)
							&& context.naptr_rrs[k].sort_pos > context.naptr_rrs[i].sort_pos)
						|| (ntohs(context.naptr_rrs[k].naptr.pref) > ntohs(context.naptr_rrs[i].naptr.pref)
							&& context.naptr_rrs[k].sort_pos < context.naptr_rrs[i].sort_pos)){
						z = context.naptr_rrs[k].sort_pos;
						context.naptr_rrs[k].sort_pos = context.naptr_rrs[i].sort_pos;
						context.naptr_rrs[i].sort_pos = z;
					}
				}
			}
		}
		for (k = 0; k < context.naptr_rrs_count; k++) {
			if (context.naptr_rrs[k].sort_pos == context.position - 1) {
				ast_copy_string(context.dst, context.naptr_rrs[k].result, dstlen);
				ast_copy_string(context.tech, context.naptr_rrs[k].tech, techlen);
				break;
			}
		}
	} else if (!(context.options & ENUMLOOKUP_OPTIONS_COUNT)) {
		context.dst[0] = 0;
	}

	if (chan)
		ret |= ast_autoservice_stop(chan);

	for (k=0; k<context.naptr_rrs_count; k++) {
		free(context.naptr_rrs[k].result);
		free(context.naptr_rrs[k].tech);
	}

	free(context.naptr_rrs);

	return ret;
}
예제 #15
0
/*!
 * \brief [lua_CFunction] This function is part of the 'application' metatable
 * and is used to execute applications similar to pbx_exec() (for access from
 * lua, don't call directly)
 *
 * \param L the lua_State to use
 * \return nothing
 *
 * This funciton is executed as the '()' operator for apps accessed through the
 * 'app' table.
 *
 * \code
 * app.playback('demo-congrats')
 * \endcode
 */
static int lua_pbx_exec(lua_State *L)
{
	int res, nargs = lua_gettop(L);
	const char *data = "";
	char *app_name, *context, *exten;
	char tmp[80], tmp2[80], tmp3[LUA_EXT_DATA_SIZE];
	int priority, autoservice;
	struct ast_app *app;
	struct ast_channel *chan;

	lua_getfield(L, 1, "name");
	app_name = ast_strdupa(lua_tostring(L, -1));
	lua_pop(L, 1);
	
	if (!(app = pbx_findapp(app_name))) {
		lua_pushstring(L, "application '");
		lua_pushstring(L, app_name);
		lua_pushstring(L, "' not found");
		lua_concat(L, 3);
		return lua_error(L);
	}
	

	lua_getfield(L, LUA_REGISTRYINDEX, "channel");
	chan = lua_touserdata(L, -1);
	lua_pop(L, 1);
	
	
	lua_getfield(L, LUA_REGISTRYINDEX, "context");
	context = ast_strdupa(lua_tostring(L, -1));
	lua_pop(L, 1);
	
	lua_getfield(L, LUA_REGISTRYINDEX, "exten");
	exten = ast_strdupa(lua_tostring(L, -1));
	lua_pop(L, 1);
	
	lua_getfield(L, LUA_REGISTRYINDEX, "priority");
	priority = lua_tointeger(L, -1);
	lua_pop(L, 1);

	lua_concat_args(L, 2, nargs);
	data = lua_tostring(L, -1);

	ast_verb(3, "Executing [%s@%s:%d] %s(\"%s\", \"%s\")\n",
			exten, context, priority,
			term_color(tmp, app_name, COLOR_BRCYAN, 0, sizeof(tmp)),
			term_color(tmp2, chan->name, COLOR_BRMAGENTA, 0, sizeof(tmp2)),
			term_color(tmp3, data, COLOR_BRMAGENTA, 0, sizeof(tmp3)));

	lua_getfield(L, LUA_REGISTRYINDEX, "autoservice");
	autoservice = lua_toboolean(L, -1);
	lua_pop(L, 1);

	if (autoservice)
		ast_autoservice_stop(chan);

	res = pbx_exec(chan, app, data);

	lua_pop(L, 1); /* pop data */
	data = "";

	if (autoservice)
		ast_autoservice_start(chan);

	/* error executing an application, report it */
	if (res) {
		lua_pushinteger(L, res);
		return lua_error(L);
	}

	lua_detect_goto(L);

	return 0;
}
예제 #16
0
/*!
 * \brief [lua_CFunction] This function is part of the 'application' metatable
 * and is used to execute applications similar to pbx_exec() (for access from
 * lua, don't call directly)
 *
 * \param L the lua_State to use
 * \return nothing
 *
 * This funciton is executed as the '()' operator for apps accessed through the
 * 'app' table.
 *
 * \code
 * app.playback('demo-congrats')
 * \endcode
 */
static int lua_pbx_exec(lua_State *L)
{
	int res, nargs = lua_gettop(L);
	const char *data = "";
	char *app_name, *context, *exten;
	char tmp[80], tmp2[80], tmp3[LUA_EXT_DATA_SIZE];
	int priority, autoservice;
	struct ast_app *app;
	struct ast_channel *chan;

	lua_getfield(L, 1, "name");
	app_name = ast_strdupa(lua_tostring(L, -1));
	lua_pop(L, 1);
	
	if (!(app = pbx_findapp(app_name))) {
		lua_pushstring(L, "application '");
		lua_pushstring(L, app_name);
		lua_pushstring(L, "' not found");
		lua_concat(L, 3);
		return lua_error(L);
	}
	

	lua_getfield(L, LUA_REGISTRYINDEX, "channel");
	chan = lua_touserdata(L, -1);
	lua_pop(L, 1);
	
	context = ast_strdupa(ast_channel_context(chan));
	exten = ast_strdupa(ast_channel_exten(chan));
	priority = ast_channel_priority(chan);
	
	lua_concat_args(L, 2, nargs);
	data = lua_tostring(L, -1);

	ast_verb(3, "Executing [%s@%s:%d] %s(\"%s\", \"%s\")\n",
			exten, context, priority,
			term_color(tmp, app_name, COLOR_BRCYAN, 0, sizeof(tmp)),
			term_color(tmp2, ast_channel_name(chan), COLOR_BRMAGENTA, 0, sizeof(tmp2)),
			term_color(tmp3, data, COLOR_BRMAGENTA, 0, sizeof(tmp3)));

	lua_getfield(L, LUA_REGISTRYINDEX, "autoservice");
	autoservice = lua_toboolean(L, -1);
	lua_pop(L, 1);

	if (autoservice)
		ast_autoservice_stop(chan);

	res = pbx_exec(chan, app, data);

	lua_pop(L, 1); /* pop data */
	data = "";

	if (autoservice)
		ast_autoservice_start(chan);

	/* error executing an application, report it */
	if (res) {
		lua_pushinteger(L, res);
		return lua_error(L);
	}

	if (strcmp(context, ast_channel_context(chan))) {
		lua_pushstring(L, context);
		lua_pushstring(L, ast_channel_context(chan));
		lua_pushliteral(L, "context");
	} else if (strcmp(exten, ast_channel_exten(chan))) {
		lua_pushstring(L, exten);
		lua_pushstring(L, ast_channel_exten(chan));
		lua_pushliteral(L, "exten");
	} else if (priority != ast_channel_priority(chan)) {
		lua_pushinteger(L, priority);
		lua_pushinteger(L, ast_channel_priority(chan));
		lua_pushliteral(L, "priority");
	} else {
		/* no goto - restore the original position back
		 * to lua state, in case this was a recursive dialplan
		 * call (a dialplan application re-entering dialplan) */
		lua_update_registry(L, context, exten, priority);
		return 0;
	}

	/* goto detected - construct error message */
	lua_insert(L, -3);
													
	lua_pushliteral(L, " changed from ");							    
	lua_insert(L, -3);									       
													 
	lua_pushliteral(L, " to ");								      
	lua_insert(L, -2);									       
													 
	lua_concat(L, 5);										
													 
	ast_debug(2, "Goto detected: %s\n", lua_tostring(L, -1));					
	lua_pop(L, 1);										   
													 
	/* let the lua engine know it needs to return control to the pbx */			      
	lua_pushinteger(L, LUA_GOTO_DETECTED);							   
	lua_error(L);

	return 0;
}
예제 #17
0
static int exec(struct ast_channel *chan, const char *context, const char *exten, int priority, const char *callerid, const char *data)
{
	int res, error_func;
	lua_State *L;
	struct ast_module_user *u = ast_module_user_add(chan);
	if (!u) {
		ast_log(LOG_ERROR, "Error adjusting use count, probably could not allocate memory\n");
		return -1;
	}
	
	L = lua_get_state(chan);
	if (!L) {
		ast_module_user_remove(u);
		return -1;
	}

	lua_pushcfunction(L, &lua_error_function);
	error_func = lua_gettop(L);

	/* push the extension function onto the stack */
	if (!lua_find_extension(L, context, exten, priority, &exists, 1)) {
		lua_pop(L, 1); /* pop the debug function */
		ast_log(LOG_ERROR, "Could not find extension %s in context %s\n", exten, context);
		if (!chan) lua_close(L);
		ast_module_user_remove(u);
		return -1;
	}

	lua_getfield(L, LUA_REGISTRYINDEX, "autoservice");
	if (lua_toboolean(L, -1)) {
		ast_autoservice_start(chan);
	}
	lua_pop(L, 1);

	lua_update_registry(L, context, exten, priority);
	
	lua_pushstring(L, context);
	lua_pushstring(L, exten);
	
	res = lua_pcall(L, 2, 0, error_func);
	if (res) {
		if (res == LUA_ERRRUN) {
			res = -1;
			if (lua_isnumber(L, -1)) {
				res = lua_tointeger(L, -1);

				if (res == LUA_GOTO_DETECTED) {
					res = 0;
				}
			} else if (lua_isstring(L, -1)) {
				const char *error = lua_tostring(L, -1);
				ast_log(LOG_ERROR, "Error executing lua extension: %s\n", error);
			}
		} else if (res == LUA_ERRERR) {
			res = -1;
			ast_log(LOG_ERROR, "Error in the lua error handler (this is probably a bug in pbx_lua)\n");
		} else if (res == LUA_ERRMEM) {
			res = -1;
			ast_log(LOG_ERROR, "Memory allocation error\n");
		}
		lua_pop(L, 1);
	}
	lua_remove(L, error_func);

	lua_getfield(L, LUA_REGISTRYINDEX, "autoservice");
	if (lua_toboolean(L, -1)) {
		ast_autoservice_stop(chan);
	}
	lua_pop(L, 1);

	if (!chan) lua_close(L);
	ast_module_user_remove(u);
	return res;
}
예제 #18
0
/* ENUM lookup */
int ast_get_enum(struct ast_channel *chan, const char *number, char *dst, int dstlen, char *tech, int techlen, char* suffix, char* options, unsigned int record, struct enum_context **argcontext)
{
	struct enum_context *context;
	char tmp[512];
	char domain[256];
	char left[128];
	char middle[128];
	char naptrinput[128];
	char apex[128] = "";
	int ret = -1;
	/* for ISN rewrite */
	char *p1 = NULL;
	char *p2 = NULL;
	char *p3 = NULL;
	int k = 0;
	int i = 0;
	int z = 0;
	int spaceleft = 0;
	struct timeval time_start, time_end;

	if (ast_strlen_zero(suffix)) {
		ast_log(LOG_WARNING, "ast_get_enum need a suffix parameter now.\n");
		return -1;
	}

	ast_debug(2, "num='%s', tech='%s', suffix='%s', options='%s', record=%u\n", number, tech, suffix, options, record);

/*
  We don't need that any more, that "n" preceding the number has been replaced by a flag
  in the options paramter.
	ast_copy_string(naptrinput, number, sizeof(naptrinput));
*/
/*
 * The "number" parameter includes a leading '+' if it's a full E.164 number (and not ISN)
 * We need to preserve that as the regex inside NAPTRs expect the +.
 *
 * But for the domain generation, the '+' is a nuissance, so we get rid of it.
*/
	ast_copy_string(naptrinput, number[0] == 'n' ? number + 1 : number, sizeof(naptrinput));
	if (number[0] == '+') {
		number++;
	}

	if (!(context = ast_calloc(1, sizeof(*context)))) {
		return -1;
	}

	if ((p3 = strchr(naptrinput, '*'))) {
		*p3='\0';
	}

	context->naptrinput = naptrinput;	/* The number */
	context->dst = dst;			/* Return string */
	context->dstlen = dstlen;
	context->tech = tech;
	context->techlen = techlen;
	context->options = 0;
	context->position = record > 0 ? record : 1;
	context->count = 0;
	context->naptr_rrs = NULL;
	context->naptr_rrs_count = 0;

	/*
	 * Process options:
	 *
	 *	c	Return count, not URI
	 *	i	Use infrastructure ENUM
	 *	s	Do ISN transformation
	 *	d	Direct DNS query: no reversing.
	 *
	 */
	if (options != NULL) {
		if (strchr(options,'s')) {
			context->options |= ENUMLOOKUP_OPTIONS_ISN;
		} else if (strchr(options,'i')) {
			context->options |= ENUMLOOKUP_OPTIONS_IENUM;
		} else if (strchr(options,'d')) {
			context->options |= ENUMLOOKUP_OPTIONS_DIRECT;
		}
		if (strchr(options,'c')) {
			context->options |= ENUMLOOKUP_OPTIONS_COUNT;
		}
		if (strchr(number,'*')) {
			context->options |= ENUMLOOKUP_OPTIONS_ISN;
		}
	}
	ast_debug(2, "ENUM options(%s): pos=%d, options='%d'\n", options, context->position, context->options);
	ast_debug(1, "n='%s', tech='%s', suffix='%s', options='%d', record='%d'\n",
			number, tech, suffix, context->options, context->position);

	/*
	 * This code does more than simple RFC3261 ENUM. All these rewriting
	 * schemes have in common that they build the FQDN for the NAPTR lookup
	 * by concatenating
	 *    - a number which needs be flipped and "."-seperated 	(left)
	 *    - some fixed string					(middle)
	 *    - an Apex.						(apex)
	 *
	 * The RFC3261 ENUM is: left=full number, middle="", apex=from args.
	 * ISN:  number = "middle*left", apex=from args
	 * I-ENUM: EBL parameters build the split, can change apex
	 * Direct: left="", middle=argument, apex=from args
	 *
	 */

	/* default: the whole number will be flipped, no middle domain component */
	ast_copy_string(left, number, sizeof(left));
	middle[0] = '\0';
	/*
	 * I-ENUM can change the apex, thus we copy it
	 */
	ast_copy_string(apex, suffix, sizeof(apex));
	/* ISN rewrite */
	if ((context->options & ENUMLOOKUP_OPTIONS_ISN) && (p1 = strchr(number, '*'))) {
		*p1++ = '\0';
		ast_copy_string(left, number, sizeof(left));
		ast_copy_string(middle, p1, sizeof(middle) - 1);
		strcat(middle, ".");
		ast_debug(2, "ISN ENUM: left=%s, middle='%s'\n", left, middle);
	/* Direct DNS lookup rewrite */
	} else if (context->options & ENUMLOOKUP_OPTIONS_DIRECT) {
		left[0] = 0; /* nothing to flip around */
		ast_copy_string(middle, number, sizeof(middle) - 1);
		strcat(middle, ".");
		ast_debug(2, "DIRECT ENUM:  middle='%s'\n", middle);
	/* Infrastructure ENUM rewrite */
	} else if (context->options & ENUMLOOKUP_OPTIONS_IENUM) {
		int sdl = 0;
		char cc[8];
		char sep[256], n_apex[256];
		int cc_len = cclen(number);
		sdl = cc_len;
		ast_mutex_lock(&enumlock);
		ast_copy_string(sep, ienum_branchlabel, sizeof(sep)); /* default */
		ast_mutex_unlock(&enumlock);

		switch (ebl_alg) {
		case ENUMLOOKUP_BLR_EBL:
			ast_copy_string(cc, number, cc_len); /* cclen() never returns more than 3 */
			sdl = blr_ebl(cc, suffix, sep, sizeof(sep) - 1, n_apex, sizeof(n_apex) - 1);

			if (sdl >= 0) {
				ast_copy_string(apex, n_apex, sizeof(apex));
				ast_debug(2, "EBL ENUM: sep=%s, apex='%s'\n", sep, n_apex);
			} else {
				sdl = cc_len;
			}
			break;
		case ENUMLOOKUP_BLR_TXT:
			ast_copy_string(cc, number, cc_len); /* cclen() never returns more than 3 */
			sdl = blr_txt(cc, suffix);

			if (sdl < 0) {
				sdl = cc_len;
			}
			break;

		case ENUMLOOKUP_BLR_CC:	/* BLR is at the country-code level */
		default:
			sdl = cc_len;
			break;
		}

		if (sdl > strlen(number)) {	/* Number too short for this sdl? */
			ast_log(LOG_WARNING, "I-ENUM: subdomain location %d behind number %s\n", sdl, number);
			ast_free(context);
			return 0;
		}
		ast_copy_string(left, number + sdl, sizeof(left));

		ast_mutex_lock(&enumlock);
		ast_copy_string(middle, sep, sizeof(middle) - 1);
		strcat(middle, ".");
		ast_mutex_unlock(&enumlock);

		/* check the space we need for middle */
		if ((sdl * 2 + strlen(middle) + 2) > sizeof(middle)) {
			ast_log(LOG_WARNING, "ast_get_enum: not enough space for I-ENUM rewrite.\n");
			ast_free(context);
			return -1;
		}

		p1 = middle + strlen(middle);
		for (p2 = (char *) number + sdl - 1; p2 >= number; p2--) {
			if (isdigit(*p2)) {
				*p1++ = *p2;
				*p1++ = '.';
			}
		}
		*p1 = '\0';

		ast_debug(2, "I-ENUM: cclen=%d, left=%s, middle='%s', apex='%s'\n", cc_len, left, middle, apex);
	}

	if (strlen(left) * 2 + 2 > sizeof(domain)) {
		ast_log(LOG_WARNING, "string to long in ast_get_enum\n");
		ast_free(context);
		return -1;
	}

	/* flip left into domain */
	p1 = domain;
	for (p2 = left + strlen(left); p2 >= left; p2--) {
		if (isdigit(*p2)) {
			*p1++ = *p2;
			*p1++ = '.';
		}
	}
	*p1 = '\0';

	if (chan && ast_autoservice_start(chan) < 0) {
		ast_free(context);
		return -1;
	}

	spaceleft = sizeof(tmp) - 2;
	ast_copy_string(tmp, domain, spaceleft);
	spaceleft -= strlen(domain);

	if (*middle) {
		strncat(tmp, middle, spaceleft);
		spaceleft -= strlen(middle);
	}

	strncat(tmp,apex,spaceleft);
	time_start = ast_tvnow();
	ret = ast_search_dns(context, tmp, C_IN, T_NAPTR, enum_callback);
	time_end = ast_tvnow();

	ast_debug(2, "profiling: %s, %s, %" PRIi64 " ms\n",
			(ret == 0) ? "OK" : "FAIL", tmp, ast_tvdiff_ms(time_end, time_start));

	if (ret < 0) {
		ast_debug(1, "No such number found: %s (%s)\n", tmp, strerror(errno));
		context->naptr_rrs_count = -1;
		strcpy(dst, "0");
		ret = 0;
	}

	if (context->naptr_rrs_count >= context->position && ! (context->options & ENUMLOOKUP_OPTIONS_COUNT)) {
		/* sort array by NAPTR order/preference */
		for (k = 0; k < context->naptr_rrs_count; k++) {
			for (i = 0; i < context->naptr_rrs_count; i++) {
				/* use order first and then preference to compare */
				if ((ntohs(context->naptr_rrs[k].naptr.order) < ntohs(context->naptr_rrs[i].naptr.order)
				     && context->naptr_rrs[k].sort_pos > context->naptr_rrs[i].sort_pos)
				     || (ntohs(context->naptr_rrs[k].naptr.order) > ntohs(context->naptr_rrs[i].naptr.order)
				     && context->naptr_rrs[k].sort_pos < context->naptr_rrs[i].sort_pos)) {
					z = context->naptr_rrs[k].sort_pos;
					context->naptr_rrs[k].sort_pos = context->naptr_rrs[i].sort_pos;
					context->naptr_rrs[i].sort_pos = z;
					continue;
				}
				if (ntohs(context->naptr_rrs[k].naptr.order) == ntohs(context->naptr_rrs[i].naptr.order)) {
					if ((ntohs(context->naptr_rrs[k].naptr.pref) < ntohs(context->naptr_rrs[i].naptr.pref)
					     && context->naptr_rrs[k].sort_pos > context->naptr_rrs[i].sort_pos)
					     || (ntohs(context->naptr_rrs[k].naptr.pref) > ntohs(context->naptr_rrs[i].naptr.pref)
					     && context->naptr_rrs[k].sort_pos < context->naptr_rrs[i].sort_pos)) {
						z = context->naptr_rrs[k].sort_pos;
						context->naptr_rrs[k].sort_pos = context->naptr_rrs[i].sort_pos;
						context->naptr_rrs[i].sort_pos = z;
					}
				}
			}
		}
		for (k = 0; k < context->naptr_rrs_count; k++) {
			if (context->naptr_rrs[k].sort_pos == context->position - 1) {
				ast_copy_string(context->dst, context->naptr_rrs[k].result, dstlen);
				ast_copy_string(context->tech, context->naptr_rrs[k].tech, techlen);
				break;
			}
		}
	} else if (!(context->options & ENUMLOOKUP_OPTIONS_COUNT)) {
		context->dst[0] = 0;
	} else if ((context->options & ENUMLOOKUP_OPTIONS_COUNT)) {
		snprintf(context->dst, context->dstlen, "%d", context->naptr_rrs_count + context->count);
	}

	if (chan) {
		ret |= ast_autoservice_stop(chan);
	}

	if (!argcontext) {
		for (k = 0; k < context->naptr_rrs_count; k++) {
			ast_free(context->naptr_rrs[k].result);
			ast_free(context->naptr_rrs[k].tech);
		}
		ast_free(context->naptr_rrs);
		ast_free(context);
	} else {
		*argcontext = context;
	}

	return ret;
}
예제 #19
0
static int _macro_exec(struct ast_channel *chan, const char *data, int exclusive)
{
	const char *s;
	char *tmp;
	char *cur, *rest;
	char *macro;
	char fullmacro[80];
	char varname[80];
	char runningapp[80], runningdata[1024];
	char *oldargs[MAX_ARGS + 1] = { NULL, };
	int argc, x;
	int res=0;
	char oldexten[256]="";
	int oldpriority, gosub_level = 0;
	char pc[80], depthc[12];
	char oldcontext[AST_MAX_CONTEXT] = "";
	const char *inhangupc;
	int offset, depth = 0, maxdepth = 7;
	int setmacrocontext=0;
	int autoloopflag, inhangup = 0;
	struct ast_str *tmp_subst = NULL;
  
	char *save_macro_exten;
	char *save_macro_context;
	char *save_macro_priority;
	char *save_macro_offset;
	struct ast_datastore *macro_store = ast_channel_datastore_find(chan, &macro_ds_info, NULL);

	if (ast_strlen_zero(data)) {
		ast_log(LOG_WARNING, "Macro() requires arguments. See \"core show application macro\" for help.\n");
		return -1;
	}

	do {
		if (macro_store) {
			break;
		}
		if (!(macro_store = ast_datastore_alloc(&macro_ds_info, NULL))) {
			ast_log(LOG_WARNING, "Unable to allocate new datastore.\n");
			break;
		}
		/* Just the existence of this datastore is enough. */
		macro_store->inheritance = DATASTORE_INHERIT_FOREVER;
		ast_channel_datastore_add(chan, macro_store);
	} while (0);

	/* does the user want a deeper rabbit hole? */
	ast_channel_lock(chan);
	if ((s = pbx_builtin_getvar_helper(chan, "MACRO_RECURSION"))) {
		sscanf(s, "%30d", &maxdepth);
	}
	
	/* Count how many levels deep the rabbit hole goes */
	if ((s = pbx_builtin_getvar_helper(chan, "MACRO_DEPTH"))) {
		sscanf(s, "%30d", &depth);
	}
	
	/* Used for detecting whether to return when a Macro is called from another Macro after hangup */
	if (strcmp(ast_channel_exten(chan), "h") == 0)
		pbx_builtin_setvar_helper(chan, "MACRO_IN_HANGUP", "1");
	
	if ((inhangupc = pbx_builtin_getvar_helper(chan, "MACRO_IN_HANGUP"))) {
		sscanf(inhangupc, "%30d", &inhangup);
	}
	ast_channel_unlock(chan);

	if (depth >= maxdepth) {
		ast_log(LOG_ERROR, "Macro():  possible infinite loop detected.  Returning early.\n");
		return 0;
	}
	snprintf(depthc, sizeof(depthc), "%d", depth + 1);

	tmp = ast_strdupa(data);
	rest = tmp;
	macro = strsep(&rest, ",");
	if (ast_strlen_zero(macro)) {
		ast_log(LOG_WARNING, "Invalid macro name specified\n");
		return 0;
	}

	snprintf(fullmacro, sizeof(fullmacro), "macro-%s", macro);
	if (!ast_exists_extension(chan, fullmacro, "s", 1,
		S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL))) {
		if (!ast_context_find(fullmacro)) 
			ast_log(LOG_WARNING, "No such context '%s' for macro '%s'. Was called by %s@%s\n", fullmacro, macro, ast_channel_exten(chan), ast_channel_context(chan));
		else
			ast_log(LOG_WARNING, "Context '%s' for macro '%s' lacks 's' extension, priority 1\n", fullmacro, macro);
		return 0;
	}

	/* If we are to run the macro exclusively, take the mutex */
	if (exclusive) {
		ast_debug(1, "Locking macrolock for '%s'\n", fullmacro);
		ast_autoservice_start(chan);
		if (ast_context_lockmacro(fullmacro)) {
			ast_log(LOG_WARNING, "Failed to lock macro '%s' as in-use\n", fullmacro);
			ast_autoservice_stop(chan);
			return 0;
		}
		ast_autoservice_stop(chan);
	}

	if (!(tmp_subst = ast_str_create(16))) {
		return -1;
	}

	/* Save old info */
	oldpriority = ast_channel_priority(chan);
	ast_copy_string(oldexten, ast_channel_exten(chan), sizeof(oldexten));
	ast_copy_string(oldcontext, ast_channel_context(chan), sizeof(oldcontext));
	if (ast_strlen_zero(ast_channel_macrocontext(chan))) {
		ast_channel_macrocontext_set(chan, ast_channel_context(chan));
		ast_channel_macroexten_set(chan, ast_channel_exten(chan));
		ast_channel_macropriority_set(chan, ast_channel_priority(chan));
		setmacrocontext=1;
	}
	argc = 1;
	/* Save old macro variables */
	save_macro_exten = ast_strdup(pbx_builtin_getvar_helper(chan, "MACRO_EXTEN"));
	pbx_builtin_setvar_helper(chan, "MACRO_EXTEN", oldexten);

	save_macro_context = ast_strdup(pbx_builtin_getvar_helper(chan, "MACRO_CONTEXT"));
	pbx_builtin_setvar_helper(chan, "MACRO_CONTEXT", oldcontext);

	save_macro_priority = ast_strdup(pbx_builtin_getvar_helper(chan, "MACRO_PRIORITY"));
	snprintf(pc, sizeof(pc), "%d", oldpriority);
	pbx_builtin_setvar_helper(chan, "MACRO_PRIORITY", pc);
  
	save_macro_offset = ast_strdup(pbx_builtin_getvar_helper(chan, "MACRO_OFFSET"));
	pbx_builtin_setvar_helper(chan, "MACRO_OFFSET", NULL);

	pbx_builtin_setvar_helper(chan, "MACRO_DEPTH", depthc);

	/* Setup environment for new run */
	ast_channel_exten_set(chan, "s");
	ast_channel_context_set(chan, fullmacro);
	ast_channel_priority_set(chan, 1);

	ast_channel_lock(chan);
	while((cur = strsep(&rest, ",")) && (argc < MAX_ARGS)) {
		const char *argp;
  		/* Save copy of old arguments if we're overwriting some, otherwise
	   	let them pass through to the other macro */
  		snprintf(varname, sizeof(varname), "ARG%d", argc);
		if ((argp = pbx_builtin_getvar_helper(chan, varname))) {
			oldargs[argc] = ast_strdup(argp);
		}
		pbx_builtin_setvar_helper(chan, varname, cur);
		argc++;
	}
	ast_channel_unlock(chan);
	autoloopflag = ast_test_flag(ast_channel_flags(chan), AST_FLAG_IN_AUTOLOOP);
	ast_set_flag(ast_channel_flags(chan), AST_FLAG_IN_AUTOLOOP);
	while (ast_exists_extension(chan, ast_channel_context(chan), ast_channel_exten(chan), ast_channel_priority(chan),
		S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL))) {
		struct ast_context *c;
		struct ast_exten *e;
		int foundx;
		runningapp[0] = '\0';
		runningdata[0] = '\0';

		/* What application will execute? */
		if (ast_rdlock_contexts()) {
			ast_log(LOG_WARNING, "Failed to lock contexts list\n");
		} else {
			for (c = ast_walk_contexts(NULL), e = NULL; c; c = ast_walk_contexts(c)) {
				if (!strcmp(ast_get_context_name(c), ast_channel_context(chan))) {
					if (ast_rdlock_context(c)) {
						ast_log(LOG_WARNING, "Unable to lock context?\n");
					} else {
						e = find_matching_priority(c, ast_channel_exten(chan), ast_channel_priority(chan),
							S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL));
						if (e) { /* This will only be undefined for pbx_realtime, which is majorly broken. */
							ast_copy_string(runningapp, ast_get_extension_app(e), sizeof(runningapp));
							ast_copy_string(runningdata, ast_get_extension_app_data(e), sizeof(runningdata));
						}
						ast_unlock_context(c);
					}
					break;
				}
			}
		}
		ast_unlock_contexts();

		/* Reset the macro depth, if it was changed in the last iteration */
		pbx_builtin_setvar_helper(chan, "MACRO_DEPTH", depthc);

		res = ast_spawn_extension(chan, ast_channel_context(chan), ast_channel_exten(chan), ast_channel_priority(chan),
			S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL),
			&foundx, 1);
		if (res) {
			/* Something bad happened, or a hangup has been requested. */
			if (((res >= '0') && (res <= '9')) || ((res >= 'A') && (res <= 'F')) ||
		    	(res == '*') || (res == '#')) {
				/* Just return result as to the previous application as if it had been dialed */
				ast_debug(1, "Oooh, got something to jump out with ('%c')!\n", res);
				break;
			}
			switch(res) {
			case MACRO_EXIT_RESULT:
				res = 0;
				goto out;
			default:
				ast_debug(2, "Spawn extension (%s,%s,%d) exited non-zero on '%s' in macro '%s'\n", ast_channel_context(chan), ast_channel_exten(chan), ast_channel_priority(chan), ast_channel_name(chan), macro);
				ast_verb(2, "Spawn extension (%s, %s, %d) exited non-zero on '%s' in macro '%s'\n", ast_channel_context(chan), ast_channel_exten(chan), ast_channel_priority(chan), ast_channel_name(chan), macro);
				goto out;
			}
		}

		ast_debug(1, "Executed application: %s\n", runningapp);

		if (!strcasecmp(runningapp, "GOSUB")) {
			gosub_level++;
			ast_debug(1, "Incrementing gosub_level\n");
		} else if (!strcasecmp(runningapp, "GOSUBIF")) {
			char *cond, *app_arg;
			char *app2;
			ast_str_substitute_variables(&tmp_subst, 0, chan, runningdata);
			app2 = ast_str_buffer(tmp_subst);
			cond = strsep(&app2, "?");
			app_arg = strsep(&app2, ":");
			if (pbx_checkcondition(cond)) {
				if (!ast_strlen_zero(app_arg)) {
					gosub_level++;
					ast_debug(1, "Incrementing gosub_level\n");
				}
			} else {
				if (!ast_strlen_zero(app2)) {
					gosub_level++;
					ast_debug(1, "Incrementing gosub_level\n");
				}
			}
		} else if (!strcasecmp(runningapp, "RETURN")) {
			gosub_level--;
			ast_debug(1, "Decrementing gosub_level\n");
		} else if (!strcasecmp(runningapp, "STACKPOP")) {
			gosub_level--;
			ast_debug(1, "Decrementing gosub_level\n");
		} else if (!strncasecmp(runningapp, "EXEC", 4)) {
			/* Must evaluate args to find actual app */
			char *tmp2, *tmp3 = NULL;
			ast_str_substitute_variables(&tmp_subst, 0, chan, runningdata);
			tmp2 = ast_str_buffer(tmp_subst);
			if (!strcasecmp(runningapp, "EXECIF")) {
				if ((tmp3 = strchr(tmp2, '|'))) {
					*tmp3++ = '\0';
				}
				if (!pbx_checkcondition(tmp2)) {
					tmp3 = NULL;
				}
			} else {
				tmp3 = tmp2;
			}

			if (tmp3) {
				ast_debug(1, "Last app: %s\n", tmp3);
			}

			if (tmp3 && !strncasecmp(tmp3, "GOSUB", 5)) {
				gosub_level++;
				ast_debug(1, "Incrementing gosub_level\n");
			} else if (tmp3 && !strncasecmp(tmp3, "RETURN", 6)) {
				gosub_level--;
				ast_debug(1, "Decrementing gosub_level\n");
			} else if (tmp3 && !strncasecmp(tmp3, "STACKPOP", 8)) {
				gosub_level--;
				ast_debug(1, "Decrementing gosub_level\n");
			}
		}

		if (gosub_level == 0 && strcasecmp(ast_channel_context(chan), fullmacro)) {
			ast_verb(2, "Channel '%s' jumping out of macro '%s'\n", ast_channel_name(chan), macro);
			break;
		}

		/* don't stop executing extensions when we're in "h" */
		if (ast_check_hangup(chan) && !inhangup) {
			ast_debug(1, "Extension %s, macroexten %s, priority %d returned normally even though call was hung up\n", ast_channel_exten(chan), ast_channel_macroexten(chan), ast_channel_priority(chan));
			goto out;
		}
		ast_channel_priority_set(chan, ast_channel_priority(chan) + 1);
  	}
	out:

	/* Don't let the channel change now. */
	ast_channel_lock(chan);

	/* Reset the depth back to what it was when the routine was entered (like if we called Macro recursively) */
	snprintf(depthc, sizeof(depthc), "%d", depth);
	pbx_builtin_setvar_helper(chan, "MACRO_DEPTH", depthc);
	ast_set2_flag(ast_channel_flags(chan), autoloopflag, AST_FLAG_IN_AUTOLOOP);

  	for (x = 1; x < argc; x++) {
  		/* Restore old arguments and delete ours */
		snprintf(varname, sizeof(varname), "ARG%d", x);
  		if (oldargs[x]) {
			pbx_builtin_setvar_helper(chan, varname, oldargs[x]);
			ast_free(oldargs[x]);
		} else {
			pbx_builtin_setvar_helper(chan, varname, NULL);
		}
  	}

	/* Restore macro variables */
	pbx_builtin_setvar_helper(chan, "MACRO_EXTEN", save_macro_exten);
	pbx_builtin_setvar_helper(chan, "MACRO_CONTEXT", save_macro_context);
	pbx_builtin_setvar_helper(chan, "MACRO_PRIORITY", save_macro_priority);
	if (save_macro_exten)
		ast_free(save_macro_exten);
	if (save_macro_context)
		ast_free(save_macro_context);
	if (save_macro_priority)
		ast_free(save_macro_priority);

	if (setmacrocontext) {
		ast_channel_macrocontext_set(chan, "");
		ast_channel_macroexten_set(chan, "");
		ast_channel_macropriority_set(chan, 0);
	}

	if (!strcasecmp(ast_channel_context(chan), fullmacro)) {
		const char *offsets;

  		/* If we're leaving the macro normally, restore original information */
		ast_channel_priority_set(chan, oldpriority);
		ast_channel_context_set(chan, oldcontext);
		ast_channel_exten_set(chan, oldexten);
		if ((offsets = pbx_builtin_getvar_helper(chan, "MACRO_OFFSET"))) {
			/* Handle macro offset if it's set by checking the availability of step n + offset + 1, otherwise continue
			normally if there is any problem */
			if (sscanf(offsets, "%30d", &offset) == 1) {
				if (ast_exists_extension(chan, ast_channel_context(chan), ast_channel_exten(chan),
					ast_channel_priority(chan) + offset + 1,
					S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL))) {
					ast_channel_priority_set(chan, ast_channel_priority(chan) + offset);
				}
			}
		}
	}

	pbx_builtin_setvar_helper(chan, "MACRO_OFFSET", save_macro_offset);
	if (save_macro_offset)
		ast_free(save_macro_offset);

	/* Unlock the macro */
	if (exclusive) {
		ast_debug(1, "Unlocking macrolock for '%s'\n", fullmacro);
		if (ast_context_unlockmacro(fullmacro)) {
			ast_log(LOG_ERROR, "Failed to unlock macro '%s' - that isn't good\n", fullmacro);
			res = 0;
		}
	}
	ast_channel_unlock(chan);
	ast_free(tmp_subst);

	return res;
}
예제 #20
0
/* ENUM lookup */
int ast_get_enum(struct ast_channel *chan, const char *number, char *dst, int dstlen, char *tech, int techlen, char* suffix, char* options, unsigned int record, struct enum_context **argcontext)
{
	struct enum_context *context;
	char tmp[259 + 512];
	char naptrinput[512];
	int pos = strlen(number) - 1;
	int newpos = 0;
	int ret = -1;
	struct enum_search *s = NULL;
	int version = -1;
	/* for ISN rewrite */
	char *p1 = NULL;
	char *p2 = NULL;
	int k = 0;
	int i = 0;
	int z = 0;

	if (!(context = ast_calloc(1, sizeof(*context))))
		return -1;

	ast_copy_string(naptrinput, number[0] == 'n' ? number + 1 : number, sizeof(naptrinput));

	context->naptrinput = naptrinput;	/* The number */
	context->dst = dst;			/* Return string */
	context->dstlen = dstlen;
	context->tech = tech;
	context->techlen = techlen;
	context->options = 0;
	context->position = record;
	context->naptr_rrs = NULL;
	context->naptr_rrs_count = 0;

	if (options != NULL) {
		if (*options == 'c') {
			context->options = ENUMLOOKUP_OPTIONS_COUNT;
			context->position = 0;
		}
	}

	ast_debug(1, "ast_get_enum(): n='%s', tech='%s', suffix='%s', options='%d', record='%d'\n",
			number, tech, suffix, context->options, context->position);

	if (pos > 128)
		pos = 128;

	/* ISN rewrite */
	p1 = strchr(number, '*');

	if (number[0] == 'n') { /* do not perform ISN rewrite ('n' is testing flag) */
		p1 = NULL;
		k = 1; /* strip 'n' from number */
	}

	if (p1 != NULL) {
		p2 = p1 + 1;
		while (p1 > number){
			p1--;
			tmp[newpos++] = *p1;
			tmp[newpos++] = '.';
		}
		if (*p2) {
			while (*p2 && newpos < 128){
				tmp[newpos++] = *p2;
				p2++;
			}
			tmp[newpos++] = '.';
		}

	} else {
		while (pos >= k) {
			if (isdigit(number[pos])) {
				tmp[newpos++] = number[pos];
				tmp[newpos++] = '.';
			}
			pos--;
		}
	}

	if (chan && ast_autoservice_start(chan) < 0) {
		ast_free(context);
		return -1;
	}

	if (suffix) {
		ast_copy_string(tmp + newpos, suffix, sizeof(tmp) - newpos);
		ret = ast_search_dns(context, tmp, C_IN, T_NAPTR, enum_callback);
		ast_debug(1, "ast_get_enum: ast_search_dns(%s) returned %d\n", tmp, ret);
	} else {
		ret = -1;		/* this is actually dead code since the demise of app_enum.c */
		for (;;) {
			ast_mutex_lock(&enumlock);
			if (version != enumver) {
				/* Ooh, a reload... */
				s = toplevs;
				version = enumver;
			} else {
				s = s->next;
			}
			ast_mutex_unlock(&enumlock);

			if (!s)
				break;
	
			ast_copy_string(tmp + newpos, s->toplev, sizeof(tmp) - newpos);
			ret = ast_search_dns(&context, tmp, C_IN, T_NAPTR, enum_callback);
			ast_debug(1, "ast_get_enum: ast_search_dns(%s) returned %d\n", tmp, ret);
			if (ret > 0)
				break;
		}
	}

	if (ret < 0) {
		ast_debug(1, "No such number found: %s (%s)\n", tmp, strerror(errno));
		strcpy(dst, "0");
		ret = 0;
	}

	if (context->naptr_rrs_count >= context->position && ! (context->options & ENUMLOOKUP_OPTIONS_COUNT)) {
		/* sort array by NAPTR order/preference */
		for (k = 0; k < context->naptr_rrs_count; k++) {
			for (i = 0; i < context->naptr_rrs_count; i++) {
				/* use order first and then preference to compare */
				if ((ntohs(context->naptr_rrs[k].naptr.order) < ntohs(context->naptr_rrs[i].naptr.order)
						&& context->naptr_rrs[k].sort_pos > context->naptr_rrs[i].sort_pos)
					|| (ntohs(context->naptr_rrs[k].naptr.order) > ntohs(context->naptr_rrs[i].naptr.order)
						&& context->naptr_rrs[k].sort_pos < context->naptr_rrs[i].sort_pos)){
					z = context->naptr_rrs[k].sort_pos;
					context->naptr_rrs[k].sort_pos = context->naptr_rrs[i].sort_pos;
					context->naptr_rrs[i].sort_pos = z;
					continue;
				}
				if (ntohs(context->naptr_rrs[k].naptr.order) == ntohs(context->naptr_rrs[i].naptr.order)) {
					if ((ntohs(context->naptr_rrs[k].naptr.pref) < ntohs(context->naptr_rrs[i].naptr.pref)
							&& context->naptr_rrs[k].sort_pos > context->naptr_rrs[i].sort_pos)
						|| (ntohs(context->naptr_rrs[k].naptr.pref) > ntohs(context->naptr_rrs[i].naptr.pref)
							&& context->naptr_rrs[k].sort_pos < context->naptr_rrs[i].sort_pos)){
						z = context->naptr_rrs[k].sort_pos;
						context->naptr_rrs[k].sort_pos = context->naptr_rrs[i].sort_pos;
						context->naptr_rrs[i].sort_pos = z;
					}
				}
			}
		}
		for (k = 0; k < context->naptr_rrs_count; k++) {
			if (context->naptr_rrs[k].sort_pos == context->position - 1) {
				ast_copy_string(context->dst, context->naptr_rrs[k].result, dstlen);
				ast_copy_string(context->tech, context->naptr_rrs[k].tech, techlen);
				break;
			}
		}
	} else if (!(context->options & ENUMLOOKUP_OPTIONS_COUNT)) {
		context->dst[0] = 0;
	}
	if (chan)
		ret |= ast_autoservice_stop(chan);

	if (!argcontext) {
		for (k = 0; k < context->naptr_rrs_count; k++) {
			ast_free(context->naptr_rrs[k].result);
			ast_free(context->naptr_rrs[k].tech);
		}
		ast_free(context->naptr_rrs);
		ast_free(context);
	} else
		*argcontext = context;

	return ret;
}