| 
									
										
										
										
											2007-11-02 15:36:34 +00:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  * Asterisk -- An open source telephony toolkit. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Copyright (C) 1999 - 2007, Digium, Inc. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Matthew Nicholson <mnicholson@digium.com> | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * See http://www.asterisk.org for more information about
 | 
					
						
							|  |  |  |  * the Asterisk project. Please do not directly contact | 
					
						
							|  |  |  |  * any of the maintainers of this project for assistance; | 
					
						
							|  |  |  |  * the project provides a web site, mailing lists and IRC | 
					
						
							|  |  |  |  * channels for your use. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * This program is free software, distributed under the terms of | 
					
						
							|  |  |  |  * the GNU General Public License Version 2. See the LICENSE file | 
					
						
							|  |  |  |  * at the top of the source tree. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-12-22 09:23:22 -05:00
										 |  |  | /*!
 | 
					
						
							| 
									
										
										
										
											2007-11-02 15:36:34 +00:00
										 |  |  |  * \file | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * \author Matthew Nicholson <mnicholson@digium.com> | 
					
						
							|  |  |  |  * \brief Lua PBX Switch | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*** MODULEINFO
 | 
					
						
							|  |  |  | 	<depend>lua</depend> | 
					
						
							| 
									
										
										
										
											2011-07-14 20:28:54 +00:00
										 |  |  | 	<support_level>extended</support_level> | 
					
						
							| 
									
										
										
										
											2007-11-02 15:36:34 +00:00
										 |  |  |  ***/ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "asterisk.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "asterisk/logger.h"
 | 
					
						
							|  |  |  | #include "asterisk/channel.h"
 | 
					
						
							|  |  |  | #include "asterisk/pbx.h"
 | 
					
						
							|  |  |  | #include "asterisk/module.h"
 | 
					
						
							|  |  |  | #include "asterisk/cli.h"
 | 
					
						
							|  |  |  | #include "asterisk/utils.h"
 | 
					
						
							|  |  |  | #include "asterisk/term.h"
 | 
					
						
							| 
									
										
										
										
											2007-11-20 23:29:33 +00:00
										 |  |  | #include "asterisk/paths.h"
 | 
					
						
							| 
									
										
										
										
											2008-09-25 21:18:12 +00:00
										 |  |  | #include "asterisk/hashtab.h"
 | 
					
						
							| 
									
										
										
										
											2007-11-02 15:36:34 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-08-30 06:43:04 +00:00
										 |  |  | #include <lua.h>
 | 
					
						
							|  |  |  | #include <lauxlib.h>
 | 
					
						
							|  |  |  | #include <lualib.h>
 | 
					
						
							| 
									
										
										
										
											2007-11-02 15:36:34 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-06-24 14:09:43 +03:00
										 |  |  | static const char *config = "extensions.lua"; | 
					
						
							|  |  |  | static const char *registrar = "pbx_lua"; | 
					
						
							| 
									
										
										
										
											2007-11-02 15:36:34 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-10-21 16:22:23 +00:00
										 |  |  | #ifdef LOW_MEMORY
 | 
					
						
							| 
									
										
										
										
											2007-11-02 15:36:34 +00:00
										 |  |  | #define LUA_EXT_DATA_SIZE 256
 | 
					
						
							| 
									
										
										
										
											2011-10-21 16:22:23 +00:00
										 |  |  | #else
 | 
					
						
							|  |  |  | #define LUA_EXT_DATA_SIZE 8192
 | 
					
						
							|  |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2007-11-02 15:36:34 +00:00
										 |  |  | #define LUA_BUF_SIZE 4096
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-05-06 18:04:23 +00:00
										 |  |  | /* This value is used by the lua engine to signal that a Goto or dialplan jump
 | 
					
						
							|  |  |  |  * was detected. Ensure this value does not conflict with any values dialplan | 
					
						
							|  |  |  |  * applications might return */ | 
					
						
							|  |  |  | #define LUA_GOTO_DETECTED 5
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-06-24 14:09:43 +03:00
										 |  |  | static char *lua_read_extensions_file(lua_State *L, size_t *size, int *file_not_openable); | 
					
						
							| 
									
										
										
										
											2007-11-02 15:36:34 +00:00
										 |  |  | static int lua_load_extensions(lua_State *L, struct ast_channel *chan); | 
					
						
							|  |  |  | static int lua_reload_extensions(lua_State *L); | 
					
						
							|  |  |  | static void lua_free_extensions(void); | 
					
						
							|  |  |  | static int lua_sort_extensions(lua_State *L); | 
					
						
							| 
									
										
										
										
											2008-09-25 21:18:12 +00:00
										 |  |  | static int lua_register_switches(lua_State *L); | 
					
						
							| 
									
										
										
										
											2011-03-04 17:44:44 +00:00
										 |  |  | static int lua_register_hints(lua_State *L); | 
					
						
							| 
									
										
										
										
											2007-11-02 15:36:34 +00:00
										 |  |  | static int lua_extension_cmp(lua_State *L); | 
					
						
							|  |  |  | static int lua_find_extension(lua_State *L, const char *context, const char *exten, int priority, ast_switch_f *func, int push_func); | 
					
						
							|  |  |  | static int lua_pbx_findapp(lua_State *L); | 
					
						
							|  |  |  | static int lua_pbx_exec(lua_State *L); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int lua_get_variable_value(lua_State *L); | 
					
						
							|  |  |  | static int lua_set_variable_value(lua_State *L); | 
					
						
							|  |  |  | static int lua_get_variable(lua_State *L); | 
					
						
							|  |  |  | static int lua_set_variable(lua_State *L); | 
					
						
							|  |  |  | static int lua_func_read(lua_State *L); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int lua_autoservice_start(lua_State *L); | 
					
						
							|  |  |  | static int lua_autoservice_stop(lua_State *L); | 
					
						
							|  |  |  | static int lua_autoservice_status(lua_State *L); | 
					
						
							| 
									
										
										
										
											2007-11-08 23:38:30 +00:00
										 |  |  | static int lua_check_hangup(lua_State *L); | 
					
						
							| 
									
										
										
										
											2008-09-26 18:02:06 +00:00
										 |  |  | static int lua_error_function(lua_State *L); | 
					
						
							| 
									
										
										
										
											2007-11-02 15:36:34 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | static void lua_update_registry(lua_State *L, const char *context, const char *exten, int priority); | 
					
						
							| 
									
										
										
										
											2011-10-21 16:22:23 +00:00
										 |  |  | static void lua_push_variable_table(lua_State *L); | 
					
						
							| 
									
										
										
										
											2007-11-02 15:36:34 +00:00
										 |  |  | static void lua_create_app_table(lua_State *L); | 
					
						
							|  |  |  | static void lua_create_channel_table(lua_State *L); | 
					
						
							|  |  |  | static void lua_create_variable_metatable(lua_State *L); | 
					
						
							|  |  |  | static void lua_create_application_metatable(lua_State *L); | 
					
						
							|  |  |  | static void lua_create_autoservice_functions(lua_State *L); | 
					
						
							| 
									
										
										
										
											2007-11-08 23:38:30 +00:00
										 |  |  | static void lua_create_hangup_function(lua_State *L); | 
					
						
							| 
									
										
										
										
											2011-10-21 16:22:23 +00:00
										 |  |  | static void lua_concat_args(lua_State *L, int start, int nargs); | 
					
						
							| 
									
										
										
										
											2007-11-02 15:36:34 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-07-20 19:35:02 +00:00
										 |  |  | static void lua_state_destroy(void *data); | 
					
						
							| 
									
										
										
										
											2011-05-05 22:49:36 +00:00
										 |  |  | static void lua_datastore_fixup(void *data, struct ast_channel *old_chan, struct ast_channel *new_chan); | 
					
						
							| 
									
										
										
										
											2007-11-02 15:36:34 +00:00
										 |  |  | static lua_State *lua_get_state(struct ast_channel *chan); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int exists(struct ast_channel *chan, const char *context, const char *exten, int priority, const char *callerid, const char *data); | 
					
						
							|  |  |  | static int canmatch(struct ast_channel *chan, const char *context, const char *exten, int priority, const char *callerid, const char *data); | 
					
						
							|  |  |  | static int matchmore(struct ast_channel *chan, const char *context, const char *exten, int priority, const char *callerid, const char *data); | 
					
						
							|  |  |  | static int exec(struct ast_channel *chan, const char *context, const char *exten, int priority, const char *callerid, const char *data); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | AST_MUTEX_DEFINE_STATIC(config_file_lock); | 
					
						
							| 
									
										
										
										
											2009-06-15 17:34:30 +00:00
										 |  |  | static char *config_file_data = NULL; | 
					
						
							| 
									
										
										
										
											2022-06-24 14:09:43 +03:00
										 |  |  | static size_t config_file_size = 0; | 
					
						
							| 
									
										
										
										
											2007-11-02 15:36:34 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-09-25 21:18:12 +00:00
										 |  |  | static struct ast_context *local_contexts = NULL; | 
					
						
							|  |  |  | static struct ast_hashtab *local_table = NULL; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-11-02 15:36:34 +00:00
										 |  |  | static const struct ast_datastore_info lua_datastore = { | 
					
						
							|  |  |  | 	.type = "lua", | 
					
						
							|  |  |  | 	.destroy = lua_state_destroy, | 
					
						
							| 
									
										
										
										
											2011-05-05 22:49:36 +00:00
										 |  |  | 	.chan_fixup = lua_datastore_fixup, | 
					
						
							| 
									
										
										
										
											2007-11-02 15:36:34 +00:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*!
 | 
					
						
							|  |  |  |  * \brief The destructor for lua_datastore | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2010-07-20 19:35:02 +00:00
										 |  |  | static void lua_state_destroy(void *data) | 
					
						
							| 
									
										
										
										
											2007-11-02 15:36:34 +00:00
										 |  |  | { | 
					
						
							|  |  |  | 	if (data) | 
					
						
							|  |  |  | 		lua_close(data); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-05-05 22:49:36 +00:00
										 |  |  | /*!
 | 
					
						
							|  |  |  |  * \brief The fixup function for the lua_datastore. | 
					
						
							|  |  |  |  * \param data the datastore data, in this case it will be a lua_State | 
					
						
							|  |  |  |  * \param old_chan the channel we are moving from | 
					
						
							|  |  |  |  * \param new_chan the channel we are moving to | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * This function updates our internal channel pointer. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | static void lua_datastore_fixup(void *data, struct ast_channel *old_chan, struct ast_channel *new_chan) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	lua_State *L = data; | 
					
						
							|  |  |  | 	lua_pushlightuserdata(L, new_chan); | 
					
						
							|  |  |  | 	lua_setfield(L, LUA_REGISTRYINDEX, "channel"); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-11-02 15:36:34 +00:00
										 |  |  | /*!
 | 
					
						
							|  |  |  |  * \brief [lua_CFunction] Find an app and return it in a lua table (for access from lua, don't | 
					
						
							|  |  |  |  * call directly) | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * This function would be called in the following example as it would be found | 
					
						
							|  |  |  |  * in extensions.lua. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * \code | 
					
						
							|  |  |  |  * app.dial | 
					
						
							|  |  |  |  * \endcode | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | static int lua_pbx_findapp(lua_State *L) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	const char *app_name = luaL_checkstring(L, 2); | 
					
						
							| 
									
										
										
										
											2017-12-22 09:23:22 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-11-02 15:36:34 +00:00
										 |  |  | 	lua_newtable(L); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	lua_pushstring(L, "name"); | 
					
						
							|  |  |  | 	lua_pushstring(L, app_name); | 
					
						
							|  |  |  | 	lua_settable(L, -3); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	luaL_getmetatable(L, "application"); | 
					
						
							|  |  |  | 	lua_setmetatable(L, -2); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return 1; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*!
 | 
					
						
							|  |  |  |  * \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 | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * This funciton is executed as the '()' operator for apps accessed through the | 
					
						
							|  |  |  |  * 'app' table. | 
					
						
							|  |  |  |  * | 
					
						
							| 
									
										
										
										
											2021-11-28 11:29:53 +01:00
										 |  |  |  * \return LUA error | 
					
						
							|  |  |  |  * | 
					
						
							| 
									
										
										
										
											2007-11-02 15:36:34 +00:00
										 |  |  |  * \code | 
					
						
							|  |  |  |  * app.playback('demo-congrats') | 
					
						
							|  |  |  |  * \endcode | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | static int lua_pbx_exec(lua_State *L) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2007-11-02 17:34:33 +00:00
										 |  |  | 	int res, nargs = lua_gettop(L); | 
					
						
							| 
									
										
										
										
											2011-10-21 16:22:23 +00:00
										 |  |  | 	const char *data = ""; | 
					
						
							|  |  |  | 	char *app_name, *context, *exten; | 
					
						
							| 
									
										
										
										
											2007-11-02 17:34:33 +00:00
										 |  |  | 	char tmp[80], tmp2[80], tmp3[LUA_EXT_DATA_SIZE]; | 
					
						
							|  |  |  | 	int priority, autoservice; | 
					
						
							|  |  |  | 	struct ast_app *app; | 
					
						
							|  |  |  | 	struct ast_channel *chan; | 
					
						
							| 
									
										
										
										
											2011-10-21 16:22:23 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-11-02 15:36:34 +00:00
										 |  |  | 	lua_getfield(L, 1, "name"); | 
					
						
							| 
									
										
										
										
											2007-11-02 17:34:33 +00:00
										 |  |  | 	app_name = ast_strdupa(lua_tostring(L, -1)); | 
					
						
							| 
									
										
										
										
											2007-11-02 15:36:34 +00:00
										 |  |  | 	lua_pop(L, 1); | 
					
						
							| 
									
										
										
										
											2017-12-22 09:23:22 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-11-02 17:34:33 +00:00
										 |  |  | 	if (!(app = pbx_findapp(app_name))) { | 
					
						
							| 
									
										
										
										
											2007-11-02 15:36:34 +00:00
										 |  |  | 		lua_pushstring(L, "application '"); | 
					
						
							|  |  |  | 		lua_pushstring(L, app_name); | 
					
						
							|  |  |  | 		lua_pushstring(L, "' not found"); | 
					
						
							|  |  |  | 		lua_concat(L, 3); | 
					
						
							|  |  |  | 		return lua_error(L); | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-12-22 09:23:22 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-11-02 15:36:34 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	lua_getfield(L, LUA_REGISTRYINDEX, "channel"); | 
					
						
							| 
									
										
										
										
											2007-11-02 17:34:33 +00:00
										 |  |  | 	chan = lua_touserdata(L, -1); | 
					
						
							| 
									
										
										
										
											2007-11-02 15:36:34 +00:00
										 |  |  | 	lua_pop(L, 1); | 
					
						
							| 
									
										
										
										
											2017-12-22 09:23:22 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-02-13 17:27:06 +00:00
										 |  |  | 	context = ast_strdupa(ast_channel_context(chan)); | 
					
						
							|  |  |  | 	exten = ast_strdupa(ast_channel_exten(chan)); | 
					
						
							| 
									
										
										
										
											2012-02-20 23:43:27 +00:00
										 |  |  | 	priority = ast_channel_priority(chan); | 
					
						
							| 
									
										
										
										
											2017-12-22 09:23:22 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-10-21 16:22:23 +00:00
										 |  |  | 	lua_concat_args(L, 2, nargs); | 
					
						
							|  |  |  | 	data = lua_tostring(L, -1); | 
					
						
							| 
									
										
										
										
											2007-11-02 15:36:34 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	ast_verb(3, "Executing [%s@%s:%d] %s(\"%s\", \"%s\")\n", | 
					
						
							|  |  |  | 			exten, context, priority, | 
					
						
							|  |  |  | 			term_color(tmp, app_name, COLOR_BRCYAN, 0, sizeof(tmp)), | 
					
						
							| 
									
										
										
										
											2012-01-09 22:15:50 +00:00
										 |  |  | 			term_color(tmp2, ast_channel_name(chan), COLOR_BRMAGENTA, 0, sizeof(tmp2)), | 
					
						
							| 
									
										
										
										
											2007-11-02 15:36:34 +00:00
										 |  |  | 			term_color(tmp3, data, COLOR_BRMAGENTA, 0, sizeof(tmp3))); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	lua_getfield(L, LUA_REGISTRYINDEX, "autoservice"); | 
					
						
							| 
									
										
										
										
											2007-11-02 17:34:33 +00:00
										 |  |  | 	autoservice = lua_toboolean(L, -1); | 
					
						
							| 
									
										
										
										
											2007-11-02 15:36:34 +00:00
										 |  |  | 	lua_pop(L, 1); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (autoservice) | 
					
						
							|  |  |  | 		ast_autoservice_stop(chan); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	res = pbx_exec(chan, app, data); | 
					
						
							| 
									
										
										
										
											2011-10-21 16:22:23 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	lua_pop(L, 1); /* pop data */ | 
					
						
							|  |  |  | 	data = ""; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-11-02 15:36:34 +00:00
										 |  |  | 	if (autoservice) | 
					
						
							|  |  |  | 		ast_autoservice_start(chan); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* error executing an application, report it */ | 
					
						
							|  |  |  | 	if (res) { | 
					
						
							|  |  |  | 		lua_pushinteger(L, res); | 
					
						
							|  |  |  | 		return lua_error(L); | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2011-05-06 18:04:23 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-02-13 17:27:06 +00:00
										 |  |  | 	if (strcmp(context, ast_channel_context(chan))) { | 
					
						
							| 
									
										
										
										
											2012-01-06 21:26:16 +00:00
										 |  |  | 		lua_pushstring(L, context); | 
					
						
							| 
									
										
										
										
											2012-02-13 17:27:06 +00:00
										 |  |  | 		lua_pushstring(L, ast_channel_context(chan)); | 
					
						
							| 
									
										
										
										
											2011-05-06 18:04:23 +00:00
										 |  |  | 		lua_pushliteral(L, "context"); | 
					
						
							| 
									
										
										
										
											2012-02-13 17:27:06 +00:00
										 |  |  | 	} else if (strcmp(exten, ast_channel_exten(chan))) { | 
					
						
							| 
									
										
										
										
											2012-01-06 21:26:16 +00:00
										 |  |  | 		lua_pushstring(L, exten); | 
					
						
							| 
									
										
										
										
											2012-02-13 17:27:06 +00:00
										 |  |  | 		lua_pushstring(L, ast_channel_exten(chan)); | 
					
						
							| 
									
										
										
										
											2011-05-06 18:04:23 +00:00
										 |  |  | 		lua_pushliteral(L, "exten"); | 
					
						
							| 
									
										
										
										
											2012-02-20 23:43:27 +00:00
										 |  |  | 	} else if (priority != ast_channel_priority(chan)) { | 
					
						
							| 
									
										
										
										
											2012-01-06 21:26:16 +00:00
										 |  |  | 		lua_pushinteger(L, priority); | 
					
						
							| 
									
										
										
										
											2012-02-20 23:43:27 +00:00
										 |  |  | 		lua_pushinteger(L, ast_channel_priority(chan)); | 
					
						
							| 
									
										
										
										
											2011-05-06 18:04:23 +00:00
										 |  |  | 		lua_pushliteral(L, "priority"); | 
					
						
							| 
									
										
										
										
											2012-01-06 21:26:16 +00:00
										 |  |  | 	} 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; | 
					
						
							| 
									
										
										
										
											2011-05-06 18:04:23 +00:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-01-06 21:26:16 +00:00
										 |  |  | 	/* goto detected - construct error message */ | 
					
						
							| 
									
										
										
										
											2011-05-06 18:04:23 +00:00
										 |  |  | 	lua_insert(L, -3); | 
					
						
							| 
									
										
										
										
											2017-12-22 09:23:22 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	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); | 
					
						
							| 
									
										
										
										
											2011-05-06 18:04:23 +00:00
										 |  |  | 	lua_error(L); | 
					
						
							| 
									
										
										
										
											2012-01-06 21:26:16 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	return 0; | 
					
						
							| 
									
										
										
										
											2011-05-06 18:04:23 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-11-02 15:36:34 +00:00
										 |  |  | /*!
 | 
					
						
							|  |  |  |  * \brief [lua_CFunction] Used to get the value of a variable or dialplan | 
					
						
							|  |  |  |  * function (for access from lua, don't call directly) | 
					
						
							| 
									
										
										
										
											2012-01-06 21:26:16 +00:00
										 |  |  |  * | 
					
						
							| 
									
										
										
										
											2007-11-02 15:36:34 +00:00
										 |  |  |  * 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. | 
					
						
							|  |  |  |  * | 
					
						
							| 
									
										
										
										
											2021-11-28 11:29:53 +01:00
										 |  |  |  * \return LUA error | 
					
						
							|  |  |  |  * | 
					
						
							| 
									
										
										
										
											2007-11-02 15:36:34 +00:00
										 |  |  |  * \code | 
					
						
							|  |  |  |  * channel.variable:get() | 
					
						
							|  |  |  |  * \endcode | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | static int lua_get_variable_value(lua_State *L) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2007-11-02 17:34:33 +00:00
										 |  |  | 	struct ast_channel *chan; | 
					
						
							|  |  |  | 	char *value = NULL, *name; | 
					
						
							| 
									
										
										
										
											2012-07-31 20:21:43 +00:00
										 |  |  | 	char *workspace = ast_alloca(LUA_BUF_SIZE); | 
					
						
							| 
									
										
										
										
											2007-11-02 17:34:33 +00:00
										 |  |  | 	int autoservice; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-11-02 15:36:34 +00:00
										 |  |  | 	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); | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-12-22 09:23:22 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-11-02 15:36:34 +00:00
										 |  |  | 	lua_getfield(L, LUA_REGISTRYINDEX, "channel"); | 
					
						
							| 
									
										
										
										
											2007-11-02 17:34:33 +00:00
										 |  |  | 	chan = lua_touserdata(L, -1); | 
					
						
							| 
									
										
										
										
											2007-11-02 15:36:34 +00:00
										 |  |  | 	lua_pop(L, 1); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	lua_getfield(L, 1, "name"); | 
					
						
							| 
									
										
										
										
											2007-11-02 17:34:33 +00:00
										 |  |  | 	name = ast_strdupa(lua_tostring(L, -1)); | 
					
						
							| 
									
										
										
										
											2007-11-02 15:36:34 +00:00
										 |  |  | 	lua_pop(L, 1); | 
					
						
							| 
									
										
										
										
											2017-12-22 09:23:22 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-11-02 15:36:34 +00:00
										 |  |  | 	lua_getfield(L, LUA_REGISTRYINDEX, "autoservice"); | 
					
						
							| 
									
										
										
										
											2007-11-02 17:34:33 +00:00
										 |  |  | 	autoservice = lua_toboolean(L, -1); | 
					
						
							| 
									
										
										
										
											2007-11-02 15:36:34 +00:00
										 |  |  | 	lua_pop(L, 1); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (autoservice) | 
					
						
							|  |  |  | 		ast_autoservice_stop(chan); | 
					
						
							| 
									
										
										
										
											2017-12-22 09:23:22 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-11-02 15:36:34 +00:00
										 |  |  | 	/* 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 { | 
					
						
							| 
									
										
										
										
											2012-02-29 16:52:47 +00:00
										 |  |  | 		pbx_retrieve_variable(chan, name, &value, workspace, LUA_BUF_SIZE, ast_channel_varshead(chan)); | 
					
						
							| 
									
										
										
										
											2007-11-02 15:36:34 +00:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-12-22 09:23:22 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-11-02 15:36:34 +00:00
										 |  |  | 	if (autoservice) | 
					
						
							|  |  |  | 		ast_autoservice_start(chan); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (value) { | 
					
						
							|  |  |  | 		lua_pushstring(L, value); | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		lua_pushnil(L); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return 1; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*!
 | 
					
						
							|  |  |  |  * \brief [lua_CFunction] Used to set the value of a variable or dialplan | 
					
						
							|  |  |  |  * function (for access from lua, don't call directly) | 
					
						
							| 
									
										
										
										
											2017-12-22 09:23:22 -05:00
										 |  |  |  * | 
					
						
							| 
									
										
										
										
											2007-11-02 15:36:34 +00:00
										 |  |  |  * This function is the 'set()' function in the following example as would be | 
					
						
							|  |  |  |  * seen in extensions.lua. | 
					
						
							|  |  |  |  * | 
					
						
							| 
									
										
										
										
											2021-11-28 11:29:53 +01:00
										 |  |  |  * \return LUA error | 
					
						
							|  |  |  |  * | 
					
						
							| 
									
										
										
										
											2007-11-02 15:36:34 +00:00
										 |  |  |  * \code | 
					
						
							| 
									
										
										
										
											2007-12-07 21:28:49 +00:00
										 |  |  |  * channel.variable:set("value") | 
					
						
							| 
									
										
										
										
											2007-11-02 15:36:34 +00:00
										 |  |  |  * \endcode | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | static int lua_set_variable_value(lua_State *L) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2007-11-02 17:34:33 +00:00
										 |  |  | 	const char *name, *value; | 
					
						
							|  |  |  | 	struct ast_channel *chan; | 
					
						
							|  |  |  | 	int autoservice; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-11-02 15:36:34 +00:00
										 |  |  | 	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"); | 
					
						
							| 
									
										
										
										
											2007-11-02 17:34:33 +00:00
										 |  |  | 	name = ast_strdupa(lua_tostring(L, -1)); | 
					
						
							| 
									
										
										
										
											2007-11-02 15:36:34 +00:00
										 |  |  | 	lua_pop(L, 1); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-11-02 17:34:33 +00:00
										 |  |  | 	value = luaL_checkstring(L, 2); | 
					
						
							| 
									
										
										
										
											2017-12-22 09:23:22 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-11-02 15:36:34 +00:00
										 |  |  | 	lua_getfield(L, LUA_REGISTRYINDEX, "channel"); | 
					
						
							| 
									
										
										
										
											2007-11-02 17:34:33 +00:00
										 |  |  | 	chan = lua_touserdata(L, -1); | 
					
						
							| 
									
										
										
										
											2007-11-02 15:36:34 +00:00
										 |  |  | 	lua_pop(L, 1); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	lua_getfield(L, LUA_REGISTRYINDEX, "autoservice"); | 
					
						
							| 
									
										
										
										
											2007-11-02 17:34:33 +00:00
										 |  |  | 	autoservice = lua_toboolean(L, -1); | 
					
						
							| 
									
										
										
										
											2007-11-02 15:36:34 +00:00
										 |  |  | 	lua_pop(L, 1); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (autoservice) | 
					
						
							|  |  |  | 		ast_autoservice_stop(chan); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	pbx_builtin_setvar_helper(chan, name, value); | 
					
						
							| 
									
										
										
										
											2017-12-22 09:23:22 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-11-02 15:36:34 +00:00
										 |  |  | 	if (autoservice) | 
					
						
							|  |  |  | 		ast_autoservice_start(chan); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*!
 | 
					
						
							|  |  |  |  * \brief Update the lua registry with the given context, exten, and priority. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * \param L the lua_State to use | 
					
						
							|  |  |  |  * \param context the new context | 
					
						
							|  |  |  |  * \param exten the new exten | 
					
						
							|  |  |  |  * \param priority the new priority | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | static void lua_update_registry(lua_State *L, const char *context, const char *exten, int priority) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	lua_pushstring(L, context); | 
					
						
							|  |  |  | 	lua_setfield(L, LUA_REGISTRYINDEX, "context"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	lua_pushstring(L, exten); | 
					
						
							|  |  |  | 	lua_setfield(L, LUA_REGISTRYINDEX, "exten"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	lua_pushinteger(L, priority); | 
					
						
							|  |  |  | 	lua_setfield(L, LUA_REGISTRYINDEX, "priority"); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*!
 | 
					
						
							|  |  |  |  * \brief Push a 'variable' table on the stack for access the channel variable | 
					
						
							|  |  |  |  * with the given name. | 
					
						
							|  |  |  |  * | 
					
						
							| 
									
										
										
										
											2011-10-21 16:22:23 +00:00
										 |  |  |  * The value on the top of the stack is popped and used as the name. | 
					
						
							|  |  |  |  * | 
					
						
							| 
									
										
										
										
											2007-11-02 15:36:34 +00:00
										 |  |  |  * \param L the lua_State to use | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2011-10-21 16:22:23 +00:00
										 |  |  | static void lua_push_variable_table(lua_State *L) | 
					
						
							| 
									
										
										
										
											2007-11-02 15:36:34 +00:00
										 |  |  | { | 
					
						
							|  |  |  | 	lua_newtable(L); | 
					
						
							|  |  |  | 	luaL_getmetatable(L, "variable"); | 
					
						
							|  |  |  | 	lua_setmetatable(L, -2); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-10-21 16:22:23 +00:00
										 |  |  | 	lua_insert(L, -2); /* move the table after the name */ | 
					
						
							| 
									
										
										
										
											2007-11-02 15:36:34 +00:00
										 |  |  | 	lua_setfield(L, -2, "name"); | 
					
						
							| 
									
										
										
										
											2017-12-22 09:23:22 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-11-02 15:36:34 +00:00
										 |  |  | 	lua_pushcfunction(L, &lua_get_variable_value); | 
					
						
							|  |  |  | 	lua_setfield(L, -2, "get"); | 
					
						
							| 
									
										
										
										
											2017-12-22 09:23:22 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-11-02 15:36:34 +00:00
										 |  |  | 	lua_pushcfunction(L, &lua_set_variable_value); | 
					
						
							|  |  |  | 	lua_setfield(L, -2, "set"); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*!
 | 
					
						
							|  |  |  |  * \brief Create the global 'app' table for executing applications | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * \param L the lua_State to use | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | static void lua_create_app_table(lua_State *L) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	lua_newtable(L); | 
					
						
							|  |  |  | 	luaL_newmetatable(L, "app"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	lua_pushstring(L, "__index"); | 
					
						
							|  |  |  | 	lua_pushcfunction(L, &lua_pbx_findapp); | 
					
						
							|  |  |  | 	lua_settable(L, -3); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	lua_setmetatable(L, -2); | 
					
						
							|  |  |  | 	lua_setglobal(L, "app"); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*!
 | 
					
						
							| 
									
										
										
										
											2021-10-30 21:04:39 -04:00
										 |  |  |  * \brief Create the global 'channel' table for accessing channel variables | 
					
						
							| 
									
										
										
										
											2007-11-02 15:36:34 +00:00
										 |  |  |  * | 
					
						
							|  |  |  |  * \param L the lua_State to use | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | static void lua_create_channel_table(lua_State *L) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	lua_newtable(L); | 
					
						
							|  |  |  | 	luaL_newmetatable(L, "channel_data"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	lua_pushstring(L, "__index"); | 
					
						
							|  |  |  | 	lua_pushcfunction(L, &lua_get_variable); | 
					
						
							|  |  |  | 	lua_settable(L, -3); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	lua_pushstring(L, "__newindex"); | 
					
						
							|  |  |  | 	lua_pushcfunction(L, &lua_set_variable); | 
					
						
							|  |  |  | 	lua_settable(L, -3); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	lua_setmetatable(L, -2); | 
					
						
							|  |  |  | 	lua_setglobal(L, "channel"); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*!
 | 
					
						
							|  |  |  |  * \brief Create the 'variable' metatable, used to retrieve channel variables | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * \param L the lua_State to use | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | static void lua_create_variable_metatable(lua_State *L) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	luaL_newmetatable(L, "variable"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	lua_pushstring(L, "__call"); | 
					
						
							|  |  |  | 	lua_pushcfunction(L, &lua_func_read); | 
					
						
							|  |  |  | 	lua_settable(L, -3); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	lua_pop(L, 1); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*!
 | 
					
						
							|  |  |  |  * \brief Create the 'application' metatable, used to execute asterisk | 
					
						
							| 
									
										
										
										
											2017-12-22 09:23:22 -05:00
										 |  |  |  * applications from lua | 
					
						
							| 
									
										
										
										
											2007-11-02 15:36:34 +00:00
										 |  |  |  * | 
					
						
							|  |  |  |  * \param L the lua_State to use | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | static void lua_create_application_metatable(lua_State *L) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	luaL_newmetatable(L, "application"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	lua_pushstring(L, "__call"); | 
					
						
							|  |  |  | 	lua_pushcfunction(L, &lua_pbx_exec); | 
					
						
							|  |  |  | 	lua_settable(L, -3); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	lua_pop(L, 1); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*!
 | 
					
						
							|  |  |  |  * \brief Create the autoservice functions | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * \param L the lua_State to use | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | static void lua_create_autoservice_functions(lua_State *L) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	lua_pushcfunction(L, &lua_autoservice_start); | 
					
						
							|  |  |  | 	lua_setglobal(L, "autoservice_start"); | 
					
						
							| 
									
										
										
										
											2017-12-22 09:23:22 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-11-02 15:36:34 +00:00
										 |  |  | 	lua_pushcfunction(L, &lua_autoservice_stop); | 
					
						
							|  |  |  | 	lua_setglobal(L, "autoservice_stop"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	lua_pushcfunction(L, &lua_autoservice_status); | 
					
						
							|  |  |  | 	lua_setglobal(L, "autoservice_status"); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-05-06 19:14:39 +00:00
										 |  |  | 	lua_pushboolean(L, 1); | 
					
						
							| 
									
										
										
										
											2007-11-02 15:36:34 +00:00
										 |  |  | 	lua_setfield(L, LUA_REGISTRYINDEX, "autoservice"); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-11-08 23:38:30 +00:00
										 |  |  | /*!
 | 
					
						
							|  |  |  |  * \brief Create the hangup check function | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * \param L the lua_State to use | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | static void lua_create_hangup_function(lua_State *L) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	lua_pushcfunction(L, &lua_check_hangup); | 
					
						
							|  |  |  | 	lua_setglobal(L, "check_hangup"); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-11-02 15:36:34 +00:00
										 |  |  | /*!
 | 
					
						
							|  |  |  |  * \brief [lua_CFunction] Return a lua 'variable' object (for access from lua, don't call | 
					
						
							|  |  |  |  * directly) | 
					
						
							| 
									
										
										
										
											2017-12-22 09:23:22 -05:00
										 |  |  |  * | 
					
						
							| 
									
										
										
										
											2007-11-02 15:36:34 +00:00
										 |  |  |  * This function is called to lookup a variable construct a 'variable' object. | 
					
						
							|  |  |  |  * It would be called in the following example as would be seen in | 
					
						
							|  |  |  |  * extensions.lua. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * \code | 
					
						
							|  |  |  |  * channel.variable | 
					
						
							|  |  |  |  * \endcode | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | static int lua_get_variable(lua_State *L) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2007-11-02 17:34:33 +00:00
										 |  |  | 	struct ast_channel *chan; | 
					
						
							| 
									
										
										
										
											2011-10-21 16:22:23 +00:00
										 |  |  | 	const char *name = luaL_checkstring(L, 2); | 
					
						
							| 
									
										
										
										
											2007-11-02 15:36:34 +00:00
										 |  |  | 	char *value = NULL; | 
					
						
							| 
									
										
										
										
											2012-07-31 20:21:43 +00:00
										 |  |  | 	char *workspace = ast_alloca(LUA_BUF_SIZE); | 
					
						
							| 
									
										
										
										
											2007-11-02 15:36:34 +00:00
										 |  |  | 	workspace[0] = '\0'; | 
					
						
							| 
									
										
										
										
											2017-12-22 09:23:22 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-11-02 15:36:34 +00:00
										 |  |  | 	lua_getfield(L, LUA_REGISTRYINDEX, "channel"); | 
					
						
							| 
									
										
										
										
											2007-11-02 17:34:33 +00:00
										 |  |  | 	chan = lua_touserdata(L, -1); | 
					
						
							| 
									
										
										
										
											2007-11-02 15:36:34 +00:00
										 |  |  | 	lua_pop(L, 1); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-10-21 16:22:23 +00:00
										 |  |  | 	lua_pushvalue(L, 2); | 
					
						
							|  |  |  | 	lua_push_variable_table(L); | 
					
						
							| 
									
										
										
										
											2017-12-22 09:23:22 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-11-02 15:36:34 +00:00
										 |  |  | 	/* if this is not a request for a dialplan funciton attempt to retrieve
 | 
					
						
							|  |  |  | 	 * the value of the variable */ | 
					
						
							|  |  |  | 	if (!ast_strlen_zero(name) && name[strlen(name) - 1] != ')') { | 
					
						
							| 
									
										
										
										
											2012-02-29 16:52:47 +00:00
										 |  |  | 		pbx_retrieve_variable(chan, name, &value, workspace, LUA_BUF_SIZE, ast_channel_varshead(chan)); | 
					
						
							| 
									
										
										
										
											2007-11-02 15:36:34 +00:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (value) { | 
					
						
							|  |  |  | 		lua_pushstring(L, value); | 
					
						
							|  |  |  | 		lua_setfield(L, -2, "value"); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-12-22 09:23:22 -05:00
										 |  |  | 	return 1; | 
					
						
							| 
									
										
										
										
											2007-11-02 15:36:34 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*!
 | 
					
						
							|  |  |  |  * \brief [lua_CFunction] Set the value of a channel variable or dialplan | 
					
						
							|  |  |  |  * function (for access from lua, don't call directly) | 
					
						
							| 
									
										
										
										
											2017-12-22 09:23:22 -05:00
										 |  |  |  * | 
					
						
							| 
									
										
										
										
											2007-11-02 15:36:34 +00:00
										 |  |  |  * 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) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2007-11-02 17:34:33 +00:00
										 |  |  | 	struct ast_channel *chan; | 
					
						
							|  |  |  | 	int autoservice; | 
					
						
							| 
									
										
										
										
											2007-11-02 15:36:34 +00:00
										 |  |  | 	const char *name = luaL_checkstring(L, 2); | 
					
						
							|  |  |  | 	const char *value = luaL_checkstring(L, 3); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	lua_getfield(L, LUA_REGISTRYINDEX, "channel"); | 
					
						
							| 
									
										
										
										
											2007-11-02 17:34:33 +00:00
										 |  |  | 	chan = lua_touserdata(L, -1); | 
					
						
							| 
									
										
										
										
											2007-11-02 15:36:34 +00:00
										 |  |  | 	lua_pop(L, 1); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	lua_getfield(L, LUA_REGISTRYINDEX, "autoservice"); | 
					
						
							| 
									
										
										
										
											2007-11-02 17:34:33 +00:00
										 |  |  | 	autoservice = lua_toboolean(L, -1); | 
					
						
							| 
									
										
										
										
											2007-11-02 15:36:34 +00:00
										 |  |  | 	lua_pop(L, 1); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (autoservice) | 
					
						
							|  |  |  | 		ast_autoservice_stop(chan); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	pbx_builtin_setvar_helper(chan, name, value); | 
					
						
							| 
									
										
										
										
											2017-12-22 09:23:22 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-11-02 15:36:34 +00:00
										 |  |  | 	if (autoservice) | 
					
						
							|  |  |  | 		ast_autoservice_start(chan); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-10-21 16:22:23 +00:00
										 |  |  | /*!
 | 
					
						
							|  |  |  |  * \brief Concatenate a list of lua function arguments into a comma separated | 
					
						
							|  |  |  |  * string. | 
					
						
							|  |  |  |  * \param L the lua_State to use | 
					
						
							|  |  |  |  * \param start the index of the first argument | 
					
						
							|  |  |  |  * \param nargs the number of args | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * The resulting string will be left on the top of the stack. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | static void lua_concat_args(lua_State *L, int start, int nargs) { | 
					
						
							|  |  |  | 	int concat = 0; | 
					
						
							|  |  |  | 	int i = start + 1; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-10-21 16:42:56 +00:00
										 |  |  | 	if (start <= nargs && !lua_isnil(L, start)) { | 
					
						
							| 
									
										
										
										
											2011-10-21 16:22:23 +00:00
										 |  |  | 		lua_pushvalue(L, start); | 
					
						
							|  |  |  | 		concat += 1; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for (; i <= nargs; i++) { | 
					
						
							|  |  |  | 		if (lua_isnil(L, i)) { | 
					
						
							|  |  |  | 			lua_pushliteral(L, ","); | 
					
						
							|  |  |  | 			concat += 1; | 
					
						
							|  |  |  | 		} else { | 
					
						
							|  |  |  | 			lua_pushliteral(L, ","); | 
					
						
							|  |  |  | 			lua_pushvalue(L, i); | 
					
						
							|  |  |  | 			concat += 2; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	lua_concat(L, concat); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-11-02 15:36:34 +00:00
										 |  |  | /*!
 | 
					
						
							|  |  |  |  * \brief [lua_CFunction] Create a 'variable' object for accessing a dialplan | 
					
						
							|  |  |  |  * function (for access from lua, don't call directly) | 
					
						
							| 
									
										
										
										
											2017-12-22 09:23:22 -05:00
										 |  |  |  * | 
					
						
							| 
									
										
										
										
											2007-11-02 15:36:34 +00:00
										 |  |  |  * This function is called to create a 'variable' object to access a dialplan | 
					
						
							|  |  |  |  * function.  It would be called in the following example as would be seen in | 
					
						
							|  |  |  |  * extensions.lua. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * \code | 
					
						
							|  |  |  |  * channel.func("arg1", "arg2", "arg3") | 
					
						
							|  |  |  |  * \endcode | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * To actually do anything with the resulting value you must use the 'get()' | 
					
						
							|  |  |  |  * and 'set()' methods (the reason is the resulting value is not a value, but | 
					
						
							|  |  |  |  * an object in the form of a lua table). | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | static int lua_func_read(lua_State *L) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	int nargs = lua_gettop(L); | 
					
						
							| 
									
										
										
										
											2007-11-02 17:34:33 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-10-21 16:22:23 +00:00
										 |  |  | 	/* build a string in the form of "func_name(arg1,arg2,arg3)" */ | 
					
						
							|  |  |  | 	lua_getfield(L, 1, "name"); | 
					
						
							|  |  |  | 	lua_pushliteral(L, "("); | 
					
						
							|  |  |  | 	lua_concat_args(L, 2, nargs); | 
					
						
							|  |  |  | 	lua_pushliteral(L, ")"); | 
					
						
							|  |  |  | 	lua_concat(L, 4); | 
					
						
							| 
									
										
										
										
											2007-11-02 15:36:34 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-10-21 16:22:23 +00:00
										 |  |  | 	lua_push_variable_table(L); | 
					
						
							| 
									
										
										
										
											2007-11-02 15:36:34 +00:00
										 |  |  | 	return 1; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*!
 | 
					
						
							|  |  |  |  * \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) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2007-11-02 17:34:33 +00:00
										 |  |  | 	struct ast_channel *chan; | 
					
						
							| 
									
										
										
										
											2011-05-06 19:01:57 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	lua_getfield(L, LUA_REGISTRYINDEX, "autoservice"); | 
					
						
							|  |  |  | 	if (lua_toboolean(L, -1)) { | 
					
						
							|  |  |  | 		/* autservice already running */ | 
					
						
							|  |  |  | 		lua_pop(L, 1); | 
					
						
							|  |  |  | 		return 0; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	lua_pop(L, 1); | 
					
						
							| 
									
										
										
										
											2007-11-02 17:34:33 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-11-02 15:36:34 +00:00
										 |  |  | 	lua_getfield(L, LUA_REGISTRYINDEX, "channel"); | 
					
						
							| 
									
										
										
										
											2007-11-02 17:34:33 +00:00
										 |  |  | 	chan = lua_touserdata(L, -1); | 
					
						
							| 
									
										
										
										
											2007-11-02 15:36:34 +00:00
										 |  |  | 	lua_pop(L, 1); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-05-06 19:01:57 +00:00
										 |  |  | 	ast_autoservice_start(chan); | 
					
						
							| 
									
										
										
										
											2007-11-02 15:36:34 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-05-06 19:01:57 +00:00
										 |  |  | 	lua_pushboolean(L, 1); | 
					
						
							| 
									
										
										
										
											2007-11-02 15:36:34 +00:00
										 |  |  | 	lua_setfield(L, LUA_REGISTRYINDEX, "autoservice"); | 
					
						
							| 
									
										
										
										
											2011-05-06 19:01:57 +00:00
										 |  |  | 	return 0; | 
					
						
							| 
									
										
										
										
											2007-11-02 15:36:34 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*!
 | 
					
						
							| 
									
										
										
										
											2021-10-30 21:04:39 -04:00
										 |  |  |  * \brief [lua_CFunction] Tell pbx_lua to stop maintaining an autoservice on | 
					
						
							| 
									
										
										
										
											2007-11-02 15:36:34 +00:00
										 |  |  |  * this channel (for access from lua, don't call directly) | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * \param L the lua_State to use | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * This function will stop any autoservice running and turn off the autoservice | 
					
						
							|  |  |  |  * flag.  If this function returns false, it's probably because no autoservice | 
					
						
							|  |  |  |  * was running to begin with. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | static int lua_autoservice_stop(lua_State *L) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2007-11-02 17:34:33 +00:00
										 |  |  | 	struct ast_channel *chan; | 
					
						
							| 
									
										
										
										
											2011-05-06 19:01:57 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	lua_getfield(L, LUA_REGISTRYINDEX, "autoservice"); | 
					
						
							|  |  |  | 	if (!lua_toboolean(L, -1)) { | 
					
						
							|  |  |  | 		/* no autservice running */ | 
					
						
							|  |  |  | 		lua_pop(L, 1); | 
					
						
							|  |  |  | 		return 0; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	lua_pop(L, 1); | 
					
						
							| 
									
										
										
										
											2007-11-02 17:34:33 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-11-02 15:36:34 +00:00
										 |  |  | 	lua_getfield(L, LUA_REGISTRYINDEX, "channel"); | 
					
						
							| 
									
										
										
										
											2007-11-02 17:34:33 +00:00
										 |  |  | 	chan = lua_touserdata(L, -1); | 
					
						
							| 
									
										
										
										
											2007-11-02 15:36:34 +00:00
										 |  |  | 	lua_pop(L, 1); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-05-06 19:01:57 +00:00
										 |  |  | 	ast_autoservice_stop(chan); | 
					
						
							| 
									
										
										
										
											2007-11-02 15:36:34 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	lua_pushboolean(L, 0); | 
					
						
							|  |  |  | 	lua_setfield(L, LUA_REGISTRYINDEX, "autoservice"); | 
					
						
							| 
									
										
										
										
											2011-05-06 19:01:57 +00:00
										 |  |  | 	return 0; | 
					
						
							| 
									
										
										
										
											2007-11-02 15:36:34 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*!
 | 
					
						
							|  |  |  |  * \brief [lua_CFunction] Get the status of the autoservice flag (for access | 
					
						
							|  |  |  |  * from lua, don't call directly) | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * \param L the lua_State to use | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * \return This function returns the status of the autoservice flag as a | 
					
						
							|  |  |  |  * boolean to its lua caller. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | static int lua_autoservice_status(lua_State *L) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	lua_getfield(L, LUA_REGISTRYINDEX, "autoservice"); | 
					
						
							|  |  |  | 	return 1; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-11-08 23:38:30 +00:00
										 |  |  | /*!
 | 
					
						
							|  |  |  |  * \brief [lua_CFunction] Check if this channel has been hungup or not (for | 
					
						
							|  |  |  |  * access from lua, don't call directly) | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * \param L the lua_State to use | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * \return This function returns true if the channel was hungup | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | static int lua_check_hangup(lua_State *L) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct ast_channel *chan; | 
					
						
							|  |  |  | 	lua_getfield(L, LUA_REGISTRYINDEX, "channel"); | 
					
						
							|  |  |  | 	chan = lua_touserdata(L, -1); | 
					
						
							|  |  |  | 	lua_pop(L, 1); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	lua_pushboolean(L, ast_check_hangup(chan)); | 
					
						
							|  |  |  | 	return 1; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-09-26 18:02:06 +00:00
										 |  |  | /*!
 | 
					
						
							|  |  |  |  * \brief [lua_CFunction] Handle lua errors (for access from lua, don't call | 
					
						
							|  |  |  |  * directly) | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * \param L the lua_State to use | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | static int lua_error_function(lua_State *L) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	int message_index; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* pass number arguments right through back to asterisk*/ | 
					
						
							|  |  |  | 	if (lua_isnumber(L, -1)) { | 
					
						
							|  |  |  | 		return 1; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* if we are here then we have a string error message, let's attach a
 | 
					
						
							|  |  |  | 	 * backtrace to it */ | 
					
						
							|  |  |  | 	message_index = lua_gettop(L); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-03-04 19:02:31 +00:00
										 |  |  | 	/* prepare to prepend a new line to the traceback */ | 
					
						
							|  |  |  | 	lua_pushliteral(L, "\n"); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-09-26 18:02:06 +00:00
										 |  |  | 	lua_getglobal(L, "debug"); | 
					
						
							| 
									
										
										
										
											2018-04-25 08:57:39 +02:00
										 |  |  | 	if (!lua_istable(L, -1)) { | 
					
						
							|  |  |  | 		/* Have no 'debug' table for whatever reason */ | 
					
						
							|  |  |  | 		lua_pop(L, 2); | 
					
						
							|  |  |  | 		/*  Original err message is on stack top now */ | 
					
						
							|  |  |  | 		return 1; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2008-09-26 18:02:06 +00:00
										 |  |  | 	lua_getfield(L, -1, "traceback"); | 
					
						
							| 
									
										
										
										
											2018-04-25 08:57:39 +02:00
										 |  |  | 	if (!lua_isfunction(L, -1)) { | 
					
						
							|  |  |  | 		/* Same here for traceback function */ | 
					
						
							|  |  |  | 		lua_pop(L, 3); | 
					
						
							|  |  |  | 		/*  Original err message is on stack top now */ | 
					
						
							|  |  |  | 		return 1; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2008-09-26 18:02:06 +00:00
										 |  |  | 	lua_remove(L, -2); /* remove the 'debug' table */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	lua_pushvalue(L, message_index); | 
					
						
							|  |  |  | 	lua_remove(L, message_index); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	lua_pushnumber(L, 2); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	lua_call(L, 2, 1); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-03-04 19:02:31 +00:00
										 |  |  | 	/* prepend the new line we prepared above */ | 
					
						
							|  |  |  | 	lua_concat(L, 2); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-09-26 18:02:06 +00:00
										 |  |  | 	return 1; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-11-02 15:36:34 +00:00
										 |  |  | /*!
 | 
					
						
							|  |  |  |  * \brief Store the sort order of each context | 
					
						
							| 
									
										
										
										
											2017-12-22 09:23:22 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-11-02 15:36:34 +00:00
										 |  |  |  * In the event of an error, an error string will be pushed onto the lua stack. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * \retval 0 success | 
					
						
							|  |  |  |  * \retval 1 failure | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | static int lua_sort_extensions(lua_State *L) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2007-11-02 17:34:33 +00:00
										 |  |  | 	int extensions, extensions_order; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-11-02 15:36:34 +00:00
										 |  |  | 	/* create the extensions_order table */ | 
					
						
							|  |  |  | 	lua_newtable(L); | 
					
						
							|  |  |  | 	lua_setfield(L, LUA_REGISTRYINDEX, "extensions_order"); | 
					
						
							|  |  |  | 	lua_getfield(L, LUA_REGISTRYINDEX, "extensions_order"); | 
					
						
							| 
									
										
										
										
											2007-11-02 17:34:33 +00:00
										 |  |  | 	extensions_order = lua_gettop(L); | 
					
						
							| 
									
										
										
										
											2007-11-02 15:36:34 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	/* sort each context in the extensions table */ | 
					
						
							|  |  |  | 	/* load the 'extensions' table */ | 
					
						
							|  |  |  | 	lua_getglobal(L, "extensions"); | 
					
						
							| 
									
										
										
										
											2007-11-02 17:34:33 +00:00
										 |  |  | 	extensions = lua_gettop(L); | 
					
						
							| 
									
										
										
										
											2007-11-02 15:36:34 +00:00
										 |  |  | 	if (lua_isnil(L, -1)) { | 
					
						
							|  |  |  | 		lua_pop(L, 1); | 
					
						
							|  |  |  | 		lua_pushstring(L, "Unable to find 'extensions' table in extensions.lua\n"); | 
					
						
							|  |  |  | 		return 1; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* iterate through the extensions table and create a
 | 
					
						
							|  |  |  | 	 * matching table (holding the sort order) in the | 
					
						
							|  |  |  | 	 * extensions_order table for each context that is found | 
					
						
							|  |  |  | 	 */ | 
					
						
							|  |  |  | 	for (lua_pushnil(L); lua_next(L, extensions); lua_pop(L, 1)) { | 
					
						
							|  |  |  | 		int context = lua_gettop(L); | 
					
						
							|  |  |  | 		int context_name = context - 1; | 
					
						
							| 
									
										
										
										
											2007-11-02 17:34:33 +00:00
										 |  |  | 		int context_order; | 
					
						
							| 
									
										
										
										
											2007-11-02 15:36:34 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-03-04 19:38:59 +00:00
										 |  |  | 		/* copy the context_name to be used as the key for the
 | 
					
						
							|  |  |  | 		 * context_order table in the extensions_order table later */ | 
					
						
							|  |  |  | 		lua_pushvalue(L, context_name); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-03-04 18:11:43 +00:00
										 |  |  | 		/* create the context_order table */ | 
					
						
							| 
									
										
										
										
											2007-11-02 15:36:34 +00:00
										 |  |  | 		lua_newtable(L); | 
					
						
							| 
									
										
										
										
											2007-11-02 17:34:33 +00:00
										 |  |  | 		context_order = lua_gettop(L); | 
					
						
							| 
									
										
										
										
											2007-11-02 15:36:34 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-10-30 21:04:39 -04:00
										 |  |  | 		/* iterate through this context an populate the corrisponding
 | 
					
						
							| 
									
										
										
										
											2007-11-02 15:36:34 +00:00
										 |  |  | 		 * table in the extensions_order table */ | 
					
						
							|  |  |  | 		for (lua_pushnil(L); lua_next(L, context); lua_pop(L, 1)) { | 
					
						
							|  |  |  | 			int exten = lua_gettop(L) - 1; | 
					
						
							| 
									
										
										
										
											2014-01-08 16:34:24 +00:00
										 |  |  | #if LUA_VERSION_NUM < 502
 | 
					
						
							| 
									
										
										
										
											2007-11-02 15:36:34 +00:00
										 |  |  | 			lua_pushinteger(L, lua_objlen(L, context_order) + 1); | 
					
						
							| 
									
										
										
										
											2014-01-08 16:34:24 +00:00
										 |  |  | #else
 | 
					
						
							|  |  |  | 			lua_pushinteger(L, lua_rawlen(L, context_order) + 1); | 
					
						
							|  |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2007-11-02 15:36:34 +00:00
										 |  |  | 			lua_pushvalue(L, exten); | 
					
						
							|  |  |  | 			lua_settable(L, context_order); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		lua_settable(L, extensions_order); /* put the context_order table in the extensions_order table */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		/* now sort the new table */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		/* push the table.sort function */ | 
					
						
							|  |  |  | 		lua_getglobal(L, "table"); | 
					
						
							|  |  |  | 		lua_getfield(L, -1, "sort"); | 
					
						
							|  |  |  | 		lua_remove(L, -2); /* remove the 'table' table */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		/* push the context_order table */ | 
					
						
							|  |  |  | 		lua_pushvalue(L, context_name); | 
					
						
							|  |  |  | 		lua_gettable(L, extensions_order); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		/* push the comp function */ | 
					
						
							|  |  |  | 		lua_pushcfunction(L, &lua_extension_cmp); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if (lua_pcall(L, 2, 0, 0)) { | 
					
						
							|  |  |  | 			lua_insert(L, -5); | 
					
						
							|  |  |  | 			lua_pop(L, 4); | 
					
						
							|  |  |  | 			return 1; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-12-22 09:23:22 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-11-02 15:36:34 +00:00
										 |  |  | 	/* remove the extensions table and the extensions_order table */ | 
					
						
							|  |  |  | 	lua_pop(L, 2); | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-09-25 21:18:12 +00:00
										 |  |  | /*!
 | 
					
						
							| 
									
										
										
										
											2021-10-30 21:04:39 -04:00
										 |  |  |  * \brief Register dialplan switches for our pbx_lua contexts. | 
					
						
							| 
									
										
										
										
											2008-09-25 21:18:12 +00:00
										 |  |  |  * | 
					
						
							|  |  |  |  * In the event of an error, an error string will be pushed onto the lua stack. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * \retval 0 success | 
					
						
							|  |  |  |  * \retval 1 failure | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | static int lua_register_switches(lua_State *L) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	int extensions; | 
					
						
							|  |  |  | 	struct ast_context *con = NULL; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* create the hash table for our contexts */ | 
					
						
							|  |  |  | 	/* XXX do we ever need to destroy this? pbx_config does not */ | 
					
						
							|  |  |  | 	if (!local_table) | 
					
						
							|  |  |  | 		local_table = ast_hashtab_create(17, ast_hashtab_compare_contexts, ast_hashtab_resize_java, ast_hashtab_newsize_java, ast_hashtab_hash_contexts, 0); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* load the 'extensions' table */ | 
					
						
							|  |  |  | 	lua_getglobal(L, "extensions"); | 
					
						
							|  |  |  | 	extensions = lua_gettop(L); | 
					
						
							|  |  |  | 	if (lua_isnil(L, -1)) { | 
					
						
							|  |  |  | 		lua_pop(L, 1); | 
					
						
							|  |  |  | 		lua_pushstring(L, "Unable to find 'extensions' table in extensions.lua\n"); | 
					
						
							|  |  |  | 		return 1; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* iterate through the extensions table and register a context and
 | 
					
						
							|  |  |  | 	 * dialplan switch for each lua context | 
					
						
							|  |  |  | 	 */ | 
					
						
							|  |  |  | 	for (lua_pushnil(L); lua_next(L, extensions); lua_pop(L, 1)) { | 
					
						
							|  |  |  | 		int context = lua_gettop(L); | 
					
						
							|  |  |  | 		int context_name = context - 1; | 
					
						
							|  |  |  | 		const char *context_str = lua_tostring(L, context_name); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		/* find or create this context */ | 
					
						
							|  |  |  | 		con = ast_context_find_or_create(&local_contexts, local_table, context_str, registrar); | 
					
						
							|  |  |  | 		if (!con) { | 
					
						
							|  |  |  | 			/* remove extensions table and context key and value */ | 
					
						
							|  |  |  | 			lua_pop(L, 3); | 
					
						
							|  |  |  | 			lua_pushstring(L, "Failed to find or create context\n"); | 
					
						
							|  |  |  | 			return 1; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		/* register the switch */ | 
					
						
							|  |  |  | 		if (ast_context_add_switch2(con, "Lua", "", 0, registrar)) { | 
					
						
							|  |  |  | 			/* remove extensions table and context key and value */ | 
					
						
							|  |  |  | 			lua_pop(L, 3); | 
					
						
							|  |  |  | 			lua_pushstring(L, "Unable to create switch for context\n"); | 
					
						
							|  |  |  | 			return 1; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-12-22 09:23:22 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-09-25 21:18:12 +00:00
										 |  |  | 	/* remove the extensions table */ | 
					
						
							|  |  |  | 	lua_pop(L, 1); | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-03-04 17:44:44 +00:00
										 |  |  | /*!
 | 
					
						
							| 
									
										
										
										
											2021-10-30 21:04:39 -04:00
										 |  |  |  * \brief Register dialplan hints for our pbx_lua contexts. | 
					
						
							| 
									
										
										
										
											2011-03-04 17:44:44 +00:00
										 |  |  |  * | 
					
						
							|  |  |  |  * In the event of an error, an error string will be pushed onto the lua stack. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * \retval 0 success | 
					
						
							|  |  |  |  * \retval 1 failure | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | static int lua_register_hints(lua_State *L) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	int hints; | 
					
						
							|  |  |  | 	struct ast_context *con = NULL; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* create the hash table for our contexts */ | 
					
						
							|  |  |  | 	/* XXX do we ever need to destroy this? pbx_config does not */ | 
					
						
							|  |  |  | 	if (!local_table) | 
					
						
							|  |  |  | 		local_table = ast_hashtab_create(17, ast_hashtab_compare_contexts, ast_hashtab_resize_java, ast_hashtab_newsize_java, ast_hashtab_hash_contexts, 0); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* load the 'hints' table */ | 
					
						
							|  |  |  | 	lua_getglobal(L, "hints"); | 
					
						
							|  |  |  | 	hints = lua_gettop(L); | 
					
						
							|  |  |  | 	if (lua_isnil(L, -1)) { | 
					
						
							|  |  |  | 		/* hints table not found, move along */ | 
					
						
							|  |  |  | 		lua_pop(L, 1); | 
					
						
							|  |  |  | 		return 0; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* iterate through the hints table and register each context and
 | 
					
						
							|  |  |  | 	 * the hints that go along with it | 
					
						
							|  |  |  | 	 */ | 
					
						
							|  |  |  | 	for (lua_pushnil(L); lua_next(L, hints); lua_pop(L, 1)) { | 
					
						
							|  |  |  | 		int context = lua_gettop(L); | 
					
						
							|  |  |  | 		int context_name = context - 1; | 
					
						
							|  |  |  | 		const char *context_str = lua_tostring(L, context_name); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		/* find or create this context */ | 
					
						
							|  |  |  | 		con = ast_context_find_or_create(&local_contexts, local_table, context_str, registrar); | 
					
						
							|  |  |  | 		if (!con) { | 
					
						
							|  |  |  | 			/* remove hints table and context key and value */ | 
					
						
							|  |  |  | 			lua_pop(L, 3); | 
					
						
							|  |  |  | 			lua_pushstring(L, "Failed to find or create context\n"); | 
					
						
							|  |  |  | 			return 1; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		/* register each hint */ | 
					
						
							|  |  |  | 		for (lua_pushnil(L); lua_next(L, context); lua_pop(L, 1)) { | 
					
						
							|  |  |  | 			const char *hint_value = lua_tostring(L, -1); | 
					
						
							|  |  |  | 			const char *hint_name; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			/* the hint value is not a string, ignore it */ | 
					
						
							|  |  |  | 			if (!hint_value) { | 
					
						
							|  |  |  | 				continue; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			/* copy the name then convert it to a string */ | 
					
						
							|  |  |  | 			lua_pushvalue(L, -2); | 
					
						
							|  |  |  | 			if (!(hint_name = lua_tostring(L, -1))) { | 
					
						
							|  |  |  | 				/* ignore non-string value */ | 
					
						
							|  |  |  | 				lua_pop(L, 1); | 
					
						
							|  |  |  | 				continue; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-12-19 15:03:52 -06:00
										 |  |  | 			if (ast_add_extension2(con, 0, hint_name, PRIORITY_HINT, NULL, NULL, hint_value, NULL, NULL, registrar, NULL, 0)) { | 
					
						
							| 
									
										
										
										
											2011-03-04 17:44:44 +00:00
										 |  |  | 				/* remove hints table, hint name, hint value,
 | 
					
						
							|  |  |  | 				 * key copy, context name, and contex table */ | 
					
						
							|  |  |  | 				lua_pop(L, 6); | 
					
						
							|  |  |  | 				lua_pushstring(L, "Error creating hint\n"); | 
					
						
							|  |  |  | 				return 1; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			/* pop the name copy */ | 
					
						
							|  |  |  | 			lua_pop(L, 1); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* remove the hints table */ | 
					
						
							|  |  |  | 	lua_pop(L, 1); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2008-09-25 21:18:12 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-11-02 15:36:34 +00:00
										 |  |  | /*!
 | 
					
						
							|  |  |  |  * \brief [lua_CFunction] Compare two extensions (for access from lua, don't | 
					
						
							|  |  |  |  * call directly) | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * This function returns true if the first extension passed should match after | 
					
						
							|  |  |  |  * the second.  It behaves like the '<' operator. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | static int lua_extension_cmp(lua_State *L) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	const char *a = luaL_checkstring(L, -2); | 
					
						
							|  |  |  | 	const char *b = luaL_checkstring(L, -1); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (ast_extension_cmp(a, b) == -1) | 
					
						
							|  |  |  | 		lua_pushboolean(L, 1); | 
					
						
							|  |  |  | 	else | 
					
						
							|  |  |  | 		lua_pushboolean(L, 0); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return 1; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*!
 | 
					
						
							|  |  |  |  * \brief Load the extensions.lua file in to a buffer and execute the file | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * \param L the lua_State to use | 
					
						
							|  |  |  |  * \param size a pointer to store the size of the buffer | 
					
						
							| 
									
										
										
										
											2016-11-23 21:52:29 +01:00
										 |  |  |  * \param file_not_openable a pointer to store if config file could be opened | 
					
						
							| 
									
										
										
										
											2007-11-02 15:36:34 +00:00
										 |  |  |  * | 
					
						
							|  |  |  |  * \note The caller is expected to free the buffer at some point. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * \return a pointer to the buffer | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2022-06-24 14:09:43 +03:00
										 |  |  | static char *lua_read_extensions_file(lua_State *L, size_t *size, int *file_not_openable) | 
					
						
							| 
									
										
										
										
											2007-11-02 15:36:34 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2007-11-02 17:34:33 +00:00
										 |  |  | 	FILE *f; | 
					
						
							| 
									
										
										
										
											2011-03-04 19:02:31 +00:00
										 |  |  | 	int error_func; | 
					
						
							| 
									
										
										
										
											2007-11-02 17:34:33 +00:00
										 |  |  | 	char *data; | 
					
						
							| 
									
										
										
										
											2012-07-31 20:21:43 +00:00
										 |  |  | 	char *path = ast_alloca(strlen(config) + strlen(ast_config_AST_CONFIG_DIR) + 2); | 
					
						
							| 
									
										
										
										
											2007-11-02 15:36:34 +00:00
										 |  |  | 	sprintf(path, "%s/%s", ast_config_AST_CONFIG_DIR, config); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-11-02 17:34:33 +00:00
										 |  |  | 	if (!(f = fopen(path, "r"))) { | 
					
						
							| 
									
										
										
										
											2007-11-02 15:36:34 +00:00
										 |  |  | 		lua_pushstring(L, "cannot open '"); | 
					
						
							|  |  |  | 		lua_pushstring(L, path); | 
					
						
							|  |  |  | 		lua_pushstring(L, "' for reading: "); | 
					
						
							|  |  |  | 		lua_pushstring(L, strerror(errno)); | 
					
						
							|  |  |  | 		lua_concat(L, 4); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-23 21:52:29 +01:00
										 |  |  | 		*file_not_openable = 1; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-11-02 15:36:34 +00:00
										 |  |  | 		return NULL; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-03-04 19:02:31 +00:00
										 |  |  | 	if (fseek(f, 0l, SEEK_END)) { | 
					
						
							|  |  |  | 		fclose(f); | 
					
						
							|  |  |  | 		lua_pushliteral(L, "error determining the size of the config file"); | 
					
						
							|  |  |  | 		return NULL; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-11-02 15:36:34 +00:00
										 |  |  | 	*size = ftell(f); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-03-04 19:02:31 +00:00
										 |  |  | 	if (fseek(f, 0l, SEEK_SET)) { | 
					
						
							|  |  |  | 		*size = 0; | 
					
						
							|  |  |  | 		fclose(f); | 
					
						
							|  |  |  | 		lua_pushliteral(L, "error reading config file"); | 
					
						
							|  |  |  | 		return NULL; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2007-11-02 15:36:34 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-11-02 17:34:33 +00:00
										 |  |  | 	if (!(data = ast_malloc(*size))) { | 
					
						
							| 
									
										
										
										
											2007-11-02 15:36:34 +00:00
										 |  |  | 		*size = 0; | 
					
						
							|  |  |  | 		fclose(f); | 
					
						
							|  |  |  | 		lua_pushstring(L, "not enough memory"); | 
					
						
							|  |  |  | 		return NULL; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-11-02 18:52:13 +00:00
										 |  |  | 	if (fread(data, sizeof(char), *size, f) != *size) { | 
					
						
							| 
									
										
										
										
											2011-03-04 19:02:31 +00:00
										 |  |  | 		*size = 0; | 
					
						
							|  |  |  | 		fclose(f); | 
					
						
							|  |  |  | 		lua_pushliteral(L, "problem reading configuration file"); | 
					
						
							|  |  |  | 		return NULL; | 
					
						
							| 
									
										
										
										
											2008-11-02 18:52:13 +00:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2007-11-02 15:36:34 +00:00
										 |  |  | 	fclose(f); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-03-04 19:02:31 +00:00
										 |  |  | 	lua_pushcfunction(L, &lua_error_function); | 
					
						
							|  |  |  | 	error_func = lua_gettop(L); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-11-02 15:36:34 +00:00
										 |  |  | 	if (luaL_loadbuffer(L, data, *size, "extensions.lua") | 
					
						
							| 
									
										
										
										
											2011-03-04 19:02:31 +00:00
										 |  |  | 			|| lua_pcall(L, 0, LUA_MULTRET, error_func) | 
					
						
							| 
									
										
										
										
											2008-09-25 21:18:12 +00:00
										 |  |  | 			|| lua_sort_extensions(L) | 
					
						
							| 
									
										
										
										
											2011-03-04 17:44:44 +00:00
										 |  |  | 			|| lua_register_switches(L) | 
					
						
							|  |  |  | 			|| lua_register_hints(L)) { | 
					
						
							| 
									
										
										
										
											2007-11-02 15:36:34 +00:00
										 |  |  | 		ast_free(data); | 
					
						
							|  |  |  | 		data = NULL; | 
					
						
							|  |  |  | 		*size = 0; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2011-03-04 19:02:31 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	lua_remove(L, error_func); | 
					
						
							| 
									
										
										
										
											2007-11-02 15:36:34 +00:00
										 |  |  | 	return data; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*!
 | 
					
						
							|  |  |  |  * \brief Load the extensions.lua file from the internal buffer | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * \param L the lua_State to use | 
					
						
							| 
									
										
										
										
											2007-11-12 23:44:20 +00:00
										 |  |  |  * \param chan channel to work on | 
					
						
							| 
									
										
										
										
											2007-11-02 15:36:34 +00:00
										 |  |  |  * | 
					
						
							|  |  |  |  * This function also sets up some constructs used by the extensions.lua file. | 
					
						
							|  |  |  |  * In the event of an error, an error string will be pushed onto the lua stack. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * \retval 0 success | 
					
						
							|  |  |  |  * \retval 1 failure | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | static int lua_load_extensions(lua_State *L, struct ast_channel *chan) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2017-12-22 09:23:22 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-11-02 15:36:34 +00:00
										 |  |  | 	/* store a pointer to this channel */ | 
					
						
							|  |  |  | 	lua_pushlightuserdata(L, chan); | 
					
						
							|  |  |  | 	lua_setfield(L, LUA_REGISTRYINDEX, "channel"); | 
					
						
							| 
									
										
										
										
											2017-12-22 09:23:22 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-11-02 15:36:34 +00:00
										 |  |  | 	luaL_openlibs(L); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* load and sort extensions */ | 
					
						
							|  |  |  | 	ast_mutex_lock(&config_file_lock); | 
					
						
							|  |  |  | 	if (luaL_loadbuffer(L, config_file_data, config_file_size, "extensions.lua") | 
					
						
							|  |  |  | 			|| lua_pcall(L, 0, LUA_MULTRET, 0) | 
					
						
							|  |  |  | 			|| lua_sort_extensions(L)) { | 
					
						
							|  |  |  | 		ast_mutex_unlock(&config_file_lock); | 
					
						
							|  |  |  | 		return 1; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	ast_mutex_unlock(&config_file_lock); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* now we setup special tables and functions */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	lua_create_app_table(L); | 
					
						
							|  |  |  | 	lua_create_channel_table(L); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	lua_create_variable_metatable(L); | 
					
						
							|  |  |  | 	lua_create_application_metatable(L); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	lua_create_autoservice_functions(L); | 
					
						
							| 
									
										
										
										
											2007-11-08 23:38:30 +00:00
										 |  |  | 	lua_create_hangup_function(L); | 
					
						
							| 
									
										
										
										
											2007-11-02 15:36:34 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*!
 | 
					
						
							|  |  |  |  * \brief Reload the extensions file and update the internal buffers if it | 
					
						
							|  |  |  |  * loads correctly. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * \warning This function should not be called on a lua_State returned from | 
					
						
							|  |  |  |  * lua_get_state(). | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * \param L the lua_State to use (must be freshly allocated with | 
					
						
							|  |  |  |  * luaL_newstate(), don't use lua_get_state()) | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | static int lua_reload_extensions(lua_State *L) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2022-06-24 14:09:43 +03:00
										 |  |  | 	size_t size = 0; | 
					
						
							| 
									
										
										
										
											2007-11-02 15:36:34 +00:00
										 |  |  | 	char *data = NULL; | 
					
						
							| 
									
										
										
										
											2016-11-23 21:52:29 +01:00
										 |  |  | 	int file_not_openable = 0; | 
					
						
							| 
									
										
										
										
											2007-11-02 15:36:34 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	luaL_openlibs(L); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-23 21:52:29 +01:00
										 |  |  | 	if (!(data = lua_read_extensions_file(L, &size, &file_not_openable))) { | 
					
						
							|  |  |  | 		if (file_not_openable) { | 
					
						
							|  |  |  | 			return -1; | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2007-11-02 15:36:34 +00:00
										 |  |  | 		return 1; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ast_mutex_lock(&config_file_lock); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (config_file_data) | 
					
						
							|  |  |  | 		ast_free(config_file_data); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	config_file_data = data; | 
					
						
							|  |  |  | 	config_file_size = size; | 
					
						
							| 
									
										
										
										
											2017-12-22 09:23:22 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-09-25 21:18:12 +00:00
										 |  |  | 	/* merge our new contexts */ | 
					
						
							|  |  |  | 	ast_merge_contexts_and_delete(&local_contexts, local_table, registrar); | 
					
						
							| 
									
										
										
										
											2017-12-22 09:23:22 -05:00
										 |  |  | 	/* merge_contexts_and_delete will actually, at the correct moment,
 | 
					
						
							| 
									
										
										
										
											2008-09-25 21:18:12 +00:00
										 |  |  | 	   set the global dialplan pointers to your local_contexts and local_table. | 
					
						
							|  |  |  | 	   It then will free up the old tables itself. Just be sure not to | 
					
						
							|  |  |  | 	   hang onto the pointers. */ | 
					
						
							|  |  |  | 	local_table = NULL; | 
					
						
							|  |  |  | 	local_contexts = NULL; | 
					
						
							| 
									
										
										
										
											2007-11-02 15:36:34 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	ast_mutex_unlock(&config_file_lock); | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*!
 | 
					
						
							|  |  |  |  * \brief Free the internal extensions buffer. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | static void lua_free_extensions() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	ast_mutex_lock(&config_file_lock); | 
					
						
							|  |  |  | 	config_file_size = 0; | 
					
						
							|  |  |  | 	ast_free(config_file_data); | 
					
						
							|  |  |  | 	ast_mutex_unlock(&config_file_lock); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*!
 | 
					
						
							|  |  |  |  * \brief Get the lua_State for this channel | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * If no channel is passed then a new state is allocated.  States with no | 
					
						
							|  |  |  |  * channel assocatied with them should only be used for matching extensions. | 
					
						
							|  |  |  |  * If the channel does not yet have a lua state associated with it, one will be | 
					
						
							|  |  |  |  * created. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * \note If no channel was passed then the caller is expected to free the state | 
					
						
							|  |  |  |  * using lua_close(). | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * \return a lua_State | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | static lua_State *lua_get_state(struct ast_channel *chan) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct ast_datastore *datastore = NULL; | 
					
						
							| 
									
										
										
										
											2007-11-02 17:34:33 +00:00
										 |  |  | 	lua_State *L; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-11-02 15:36:34 +00:00
										 |  |  | 	if (!chan) { | 
					
						
							| 
									
										
										
										
											2012-03-08 17:02:52 +00:00
										 |  |  | 		L = luaL_newstate(); | 
					
						
							| 
									
										
										
										
											2007-11-02 15:36:34 +00:00
										 |  |  | 		if (!L) { | 
					
						
							|  |  |  | 			ast_log(LOG_ERROR, "Error allocating lua_State, no memory\n"); | 
					
						
							|  |  |  | 			return NULL; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if (lua_load_extensions(L, NULL)) { | 
					
						
							|  |  |  | 			const char *error = lua_tostring(L, -1); | 
					
						
							|  |  |  | 			ast_log(LOG_ERROR, "Error loading extensions.lua: %s\n", error); | 
					
						
							|  |  |  | 			lua_close(L); | 
					
						
							|  |  |  | 			return NULL; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		return L; | 
					
						
							|  |  |  | 	} else { | 
					
						
							| 
									
										
										
										
											2008-04-25 22:04:46 +00:00
										 |  |  | 		ast_channel_lock(chan); | 
					
						
							| 
									
										
										
										
											2007-11-02 15:36:34 +00:00
										 |  |  | 		datastore = ast_channel_datastore_find(chan, &lua_datastore, NULL); | 
					
						
							| 
									
										
										
										
											2008-04-25 22:04:46 +00:00
										 |  |  | 		ast_channel_unlock(chan); | 
					
						
							| 
									
										
										
										
											2007-11-02 15:36:34 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		if (!datastore) { | 
					
						
							|  |  |  | 			/* nothing found, allocate a new lua state */ | 
					
						
							| 
									
										
										
										
											2008-08-05 16:56:11 +00:00
										 |  |  | 			datastore = ast_datastore_alloc(&lua_datastore, NULL); | 
					
						
							| 
									
										
										
										
											2007-11-02 15:36:34 +00:00
										 |  |  | 			if (!datastore) { | 
					
						
							|  |  |  | 				ast_log(LOG_ERROR, "Error allocation channel datastore for lua_State\n"); | 
					
						
							|  |  |  | 				return NULL; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			datastore->data = luaL_newstate(); | 
					
						
							|  |  |  | 			if (!datastore->data) { | 
					
						
							| 
									
										
										
										
											2008-08-05 16:56:11 +00:00
										 |  |  | 				ast_datastore_free(datastore); | 
					
						
							| 
									
										
										
										
											2007-11-02 15:36:34 +00:00
										 |  |  | 				ast_log(LOG_ERROR, "Error allocating lua_State, no memory\n"); | 
					
						
							|  |  |  | 				return NULL; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			ast_channel_lock(chan); | 
					
						
							|  |  |  | 			ast_channel_datastore_add(chan, datastore); | 
					
						
							|  |  |  | 			ast_channel_unlock(chan); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-11-02 17:34:33 +00:00
										 |  |  | 			L = datastore->data; | 
					
						
							| 
									
										
										
										
											2007-11-02 15:36:34 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 			if (lua_load_extensions(L, chan)) { | 
					
						
							|  |  |  | 				const char *error = lua_tostring(L, -1); | 
					
						
							| 
									
										
										
										
											2012-01-09 22:15:50 +00:00
										 |  |  | 				ast_log(LOG_ERROR, "Error loading extensions.lua for %s: %s\n", ast_channel_name(chan), error); | 
					
						
							| 
									
										
										
										
											2007-11-02 15:36:34 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 				ast_channel_lock(chan); | 
					
						
							|  |  |  | 				ast_channel_datastore_remove(chan, datastore); | 
					
						
							|  |  |  | 				ast_channel_unlock(chan); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-08-05 16:56:11 +00:00
										 |  |  | 				ast_datastore_free(datastore); | 
					
						
							| 
									
										
										
										
											2007-11-02 15:36:34 +00:00
										 |  |  | 				return NULL; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		return datastore->data; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int exists(struct ast_channel *chan, const char *context, const char *exten, int priority, const char *callerid, const char *data) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2007-11-02 17:34:33 +00:00
										 |  |  | 	int res; | 
					
						
							|  |  |  | 	lua_State *L; | 
					
						
							| 
									
										
										
										
											2007-11-02 15:36:34 +00:00
										 |  |  | 	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 0; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-11-02 17:34:33 +00:00
										 |  |  | 	L = lua_get_state(chan); | 
					
						
							| 
									
										
										
										
											2007-11-02 15:36:34 +00:00
										 |  |  | 	if (!L) { | 
					
						
							|  |  |  | 		ast_module_user_remove(u); | 
					
						
							|  |  |  | 		return 0; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-11-02 17:34:33 +00:00
										 |  |  | 	res = lua_find_extension(L, context, exten, priority, &exists, 0); | 
					
						
							| 
									
										
										
										
											2007-11-02 15:36:34 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	if (!chan) lua_close(L); | 
					
						
							|  |  |  | 	ast_module_user_remove(u); | 
					
						
							|  |  |  | 	return res; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int canmatch(struct ast_channel *chan, const char *context, const char *exten, int priority, const char *callerid, const char *data) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2007-11-02 17:34:33 +00:00
										 |  |  | 	int res; | 
					
						
							|  |  |  | 	lua_State *L; | 
					
						
							| 
									
										
										
										
											2007-11-02 15:36:34 +00:00
										 |  |  | 	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 0; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-11-02 17:34:33 +00:00
										 |  |  | 	L = lua_get_state(chan); | 
					
						
							| 
									
										
										
										
											2007-11-02 15:36:34 +00:00
										 |  |  | 	if (!L) { | 
					
						
							|  |  |  | 		ast_module_user_remove(u); | 
					
						
							|  |  |  | 		return 0; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-11-02 17:34:33 +00:00
										 |  |  | 	res = lua_find_extension(L, context, exten, priority, &canmatch, 0); | 
					
						
							| 
									
										
										
										
											2007-11-02 15:36:34 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	if (!chan) lua_close(L); | 
					
						
							|  |  |  | 	ast_module_user_remove(u); | 
					
						
							|  |  |  | 	return res; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int matchmore(struct ast_channel *chan, const char *context, const char *exten, int priority, const char *callerid, const char *data) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2007-11-02 17:34:33 +00:00
										 |  |  | 	int res; | 
					
						
							|  |  |  | 	lua_State *L; | 
					
						
							| 
									
										
										
										
											2007-11-02 15:36:34 +00:00
										 |  |  | 	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 0; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-11-02 17:34:33 +00:00
										 |  |  | 	L = lua_get_state(chan); | 
					
						
							| 
									
										
										
										
											2007-11-02 15:36:34 +00:00
										 |  |  | 	if (!L) { | 
					
						
							|  |  |  | 		ast_module_user_remove(u); | 
					
						
							|  |  |  | 		return 0; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-12-22 09:23:22 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-11-02 17:34:33 +00:00
										 |  |  | 	res = lua_find_extension(L, context, exten, priority, &matchmore, 0); | 
					
						
							| 
									
										
										
										
											2007-11-02 15:36:34 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	if (!chan) lua_close(L); | 
					
						
							|  |  |  | 	ast_module_user_remove(u); | 
					
						
							|  |  |  | 	return res; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int exec(struct ast_channel *chan, const char *context, const char *exten, int priority, const char *callerid, const char *data) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2008-09-26 18:02:06 +00:00
										 |  |  | 	int res, error_func; | 
					
						
							| 
									
										
										
										
											2007-11-02 17:34:33 +00:00
										 |  |  | 	lua_State *L; | 
					
						
							| 
									
										
										
										
											2007-11-02 15:36:34 +00:00
										 |  |  | 	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; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-12-22 09:23:22 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-11-02 17:34:33 +00:00
										 |  |  | 	L = lua_get_state(chan); | 
					
						
							| 
									
										
										
										
											2007-11-02 15:36:34 +00:00
										 |  |  | 	if (!L) { | 
					
						
							|  |  |  | 		ast_module_user_remove(u); | 
					
						
							|  |  |  | 		return -1; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-09-26 18:02:06 +00:00
										 |  |  | 	lua_pushcfunction(L, &lua_error_function); | 
					
						
							|  |  |  | 	error_func = lua_gettop(L); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-11-02 15:36:34 +00:00
										 |  |  | 	/* push the extension function onto the stack */ | 
					
						
							|  |  |  | 	if (!lua_find_extension(L, context, exten, priority, &exists, 1)) { | 
					
						
							| 
									
										
										
										
											2008-09-26 18:02:06 +00:00
										 |  |  | 		lua_pop(L, 1); /* pop the debug function */ | 
					
						
							| 
									
										
										
										
											2007-11-02 15:36:34 +00:00
										 |  |  | 		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; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2011-05-06 19:01:57 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	lua_getfield(L, LUA_REGISTRYINDEX, "autoservice"); | 
					
						
							|  |  |  | 	if (lua_toboolean(L, -1)) { | 
					
						
							|  |  |  | 		ast_autoservice_start(chan); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	lua_pop(L, 1); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-11-02 15:36:34 +00:00
										 |  |  | 	lua_update_registry(L, context, exten, priority); | 
					
						
							| 
									
										
										
										
											2017-12-22 09:23:22 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-11-02 15:36:34 +00:00
										 |  |  | 	lua_pushstring(L, context); | 
					
						
							|  |  |  | 	lua_pushstring(L, exten); | 
					
						
							| 
									
										
										
										
											2017-12-22 09:23:22 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-09-26 18:02:06 +00:00
										 |  |  | 	res = lua_pcall(L, 2, 0, error_func); | 
					
						
							| 
									
										
										
										
											2007-11-02 15:36:34 +00:00
										 |  |  | 	if (res) { | 
					
						
							|  |  |  | 		if (res == LUA_ERRRUN) { | 
					
						
							| 
									
										
										
										
											2008-09-26 18:02:06 +00:00
										 |  |  | 			res = -1; | 
					
						
							| 
									
										
										
										
											2007-11-02 15:36:34 +00:00
										 |  |  | 			if (lua_isnumber(L, -1)) { | 
					
						
							|  |  |  | 				res = lua_tointeger(L, -1); | 
					
						
							| 
									
										
										
										
											2011-05-06 18:04:23 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 				if (res == LUA_GOTO_DETECTED) { | 
					
						
							|  |  |  | 					res = 0; | 
					
						
							|  |  |  | 				} | 
					
						
							| 
									
										
										
										
											2007-11-02 15:36:34 +00:00
										 |  |  | 			} else if (lua_isstring(L, -1)) { | 
					
						
							|  |  |  | 				const char *error = lua_tostring(L, -1); | 
					
						
							|  |  |  | 				ast_log(LOG_ERROR, "Error executing lua extension: %s\n", error); | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2008-09-26 18:02:06 +00:00
										 |  |  | 		} else if (res == LUA_ERRERR) { | 
					
						
							| 
									
										
										
										
											2007-11-02 15:36:34 +00:00
										 |  |  | 			res = -1; | 
					
						
							| 
									
										
										
										
											2008-09-26 18:02:06 +00:00
										 |  |  | 			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"); | 
					
						
							| 
									
										
										
										
											2007-11-02 15:36:34 +00:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2008-09-26 18:02:06 +00:00
										 |  |  | 		lua_pop(L, 1); | 
					
						
							| 
									
										
										
										
											2007-11-02 15:36:34 +00:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2008-09-26 18:02:06 +00:00
										 |  |  | 	lua_remove(L, error_func); | 
					
						
							| 
									
										
										
										
											2011-05-06 19:01:57 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	lua_getfield(L, LUA_REGISTRYINDEX, "autoservice"); | 
					
						
							|  |  |  | 	if (lua_toboolean(L, -1)) { | 
					
						
							|  |  |  | 		ast_autoservice_stop(chan); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	lua_pop(L, 1); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-11-02 15:36:34 +00:00
										 |  |  | 	if (!chan) lua_close(L); | 
					
						
							|  |  |  | 	ast_module_user_remove(u); | 
					
						
							|  |  |  | 	return res; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*!
 | 
					
						
							|  |  |  |  * \brief Locate an extensions and optionally push the matching function on the | 
					
						
							|  |  |  |  * stack | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * \param L the lua_State to use | 
					
						
							|  |  |  |  * \param context the context to look in | 
					
						
							|  |  |  |  * \param exten the extension to look up | 
					
						
							|  |  |  |  * \param priority the priority to check, '1' is the only valid priority | 
					
						
							|  |  |  |  * \param func the calling func, used to adjust matching behavior between, | 
					
						
							|  |  |  |  * match, canmatch, and matchmore | 
					
						
							|  |  |  |  * \param push_func whether or not to push the lua function for the given | 
					
						
							|  |  |  |  * extension onto the stack | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | static int lua_find_extension(lua_State *L, const char *context, const char *exten, int priority, ast_switch_f *func, int push_func) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2022-06-24 14:09:43 +03:00
										 |  |  | 	int context_table, context_order_table; | 
					
						
							|  |  |  | 	size_t i; | 
					
						
							| 
									
										
										
										
											2007-11-02 17:34:33 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-11-02 15:36:34 +00:00
										 |  |  | 	ast_debug(2, "Looking up %s@%s:%i\n", exten, context, priority); | 
					
						
							|  |  |  | 	if (priority != 1) | 
					
						
							|  |  |  | 		return 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* load the 'extensions' table */ | 
					
						
							|  |  |  | 	lua_getglobal(L, "extensions"); | 
					
						
							|  |  |  | 	if (lua_isnil(L, -1)) { | 
					
						
							|  |  |  | 		ast_log(LOG_ERROR, "Unable to find 'extensions' table in extensions.lua\n"); | 
					
						
							|  |  |  | 		lua_pop(L, 1); | 
					
						
							|  |  |  | 		return 0; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* load the given context */ | 
					
						
							|  |  |  | 	lua_getfield(L, -1, context); | 
					
						
							|  |  |  | 	if (lua_isnil(L, -1)) { | 
					
						
							|  |  |  | 		lua_pop(L, 2); | 
					
						
							|  |  |  | 		return 0; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* remove the extensions table */ | 
					
						
							|  |  |  | 	lua_remove(L, -2); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-11-02 17:34:33 +00:00
										 |  |  | 	context_table = lua_gettop(L); | 
					
						
							| 
									
										
										
										
											2007-11-02 15:36:34 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	/* load the extensions order table for this context */ | 
					
						
							|  |  |  | 	lua_getfield(L, LUA_REGISTRYINDEX, "extensions_order"); | 
					
						
							|  |  |  | 	lua_getfield(L, -1, context); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	lua_remove(L, -2);  /* remove the extensions order table */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-11-02 17:34:33 +00:00
										 |  |  | 	context_order_table = lua_gettop(L); | 
					
						
							| 
									
										
										
										
											2014-01-08 16:34:24 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-11-02 15:36:34 +00:00
										 |  |  | 	/* step through the extensions looking for a match */ | 
					
						
							| 
									
										
										
										
											2014-01-08 16:34:24 +00:00
										 |  |  | #if LUA_VERSION_NUM < 502
 | 
					
						
							| 
									
										
										
										
											2007-11-02 15:36:34 +00:00
										 |  |  | 	for (i = 1; i < lua_objlen(L, context_order_table) + 1; i++) { | 
					
						
							| 
									
										
										
										
											2014-01-08 16:34:24 +00:00
										 |  |  | #else
 | 
					
						
							|  |  |  | 	for (i = 1; i < lua_rawlen(L, context_order_table) + 1; i++) { | 
					
						
							|  |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2011-05-05 22:44:52 +00:00
										 |  |  | 		int e_index_copy, match = 0; | 
					
						
							| 
									
										
										
										
											2007-11-02 17:34:33 +00:00
										 |  |  | 		const char *e; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-11-02 15:36:34 +00:00
										 |  |  | 		lua_pushinteger(L, i); | 
					
						
							|  |  |  | 		lua_gettable(L, context_order_table); | 
					
						
							| 
									
										
										
										
											2011-05-05 22:44:52 +00:00
										 |  |  | 		lua_gettop(L); | 
					
						
							| 
									
										
										
										
											2007-11-02 15:36:34 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-09-25 17:51:11 +00:00
										 |  |  | 		/* copy the key at the top of the stack for use later */ | 
					
						
							|  |  |  | 		lua_pushvalue(L, -1); | 
					
						
							|  |  |  | 		e_index_copy = lua_gettop(L); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if (!(e = lua_tostring(L, e_index_copy))) { | 
					
						
							|  |  |  | 			lua_pop(L, 2); | 
					
						
							| 
									
										
										
										
											2007-11-02 15:36:34 +00:00
										 |  |  | 			continue; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		/* make sure this is not the 'include' extension */ | 
					
						
							| 
									
										
										
										
											2007-11-02 17:34:33 +00:00
										 |  |  | 		if (!strcasecmp(e, "include")) { | 
					
						
							| 
									
										
										
										
											2008-09-25 17:51:11 +00:00
										 |  |  | 			lua_pop(L, 2); | 
					
						
							| 
									
										
										
										
											2007-11-02 15:36:34 +00:00
										 |  |  | 			continue; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if (func == &matchmore) | 
					
						
							|  |  |  | 			match = ast_extension_close(e, exten, E_MATCHMORE); | 
					
						
							|  |  |  | 		else if (func == &canmatch) | 
					
						
							|  |  |  | 			match = ast_extension_close(e, exten, E_CANMATCH); | 
					
						
							|  |  |  | 		else | 
					
						
							|  |  |  | 			match = ast_extension_match(e, exten); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		/* the extension matching functions return 0 on fail, 1 on
 | 
					
						
							|  |  |  | 		 * match, 2 on earlymatch */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if (!match) { | 
					
						
							| 
									
										
										
										
											2008-09-25 17:51:11 +00:00
										 |  |  | 			/* pop the copy and the extension */ | 
					
						
							|  |  |  | 			lua_pop(L, 2); | 
					
						
							| 
									
										
										
										
											2007-11-02 15:36:34 +00:00
										 |  |  | 			continue;	/* keep trying */ | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if (func == &matchmore && match == 2) { | 
					
						
							|  |  |  | 			/* We match an extension ending in '!'. The decision in
 | 
					
						
							|  |  |  | 			 * this case is final and counts as no match. */ | 
					
						
							| 
									
										
										
										
											2008-09-25 17:51:11 +00:00
										 |  |  | 			lua_pop(L, 4); | 
					
						
							| 
									
										
										
										
											2007-11-02 15:36:34 +00:00
										 |  |  | 			return 0; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-09-25 17:51:11 +00:00
										 |  |  | 		/* remove the context table, the context order table, the
 | 
					
						
							|  |  |  | 		 * extension, and the extension copy (or replace the extension | 
					
						
							|  |  |  | 		 * with the corresponding function) */ | 
					
						
							| 
									
										
										
										
											2007-11-02 15:36:34 +00:00
										 |  |  | 		if (push_func) { | 
					
						
							| 
									
										
										
										
											2008-09-25 17:51:11 +00:00
										 |  |  | 			lua_pop(L, 1);  /* pop the copy */ | 
					
						
							| 
									
										
										
										
											2007-11-02 15:36:34 +00:00
										 |  |  | 			lua_gettable(L, context_table); | 
					
						
							|  |  |  | 			lua_insert(L, -3); | 
					
						
							|  |  |  | 			lua_pop(L, 2); | 
					
						
							|  |  |  | 		} else { | 
					
						
							| 
									
										
										
										
											2008-09-25 17:51:11 +00:00
										 |  |  | 			lua_pop(L, 4); | 
					
						
							| 
									
										
										
										
											2007-11-02 15:36:34 +00:00
										 |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		return 1; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* load the includes for this context */ | 
					
						
							|  |  |  | 	lua_getfield(L, context_table, "include"); | 
					
						
							|  |  |  | 	if (lua_isnil(L, -1)) { | 
					
						
							|  |  |  | 		lua_pop(L, 3); | 
					
						
							|  |  |  | 		return 0; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* remove the context and the order table*/ | 
					
						
							|  |  |  | 	lua_remove(L, context_order_table); | 
					
						
							|  |  |  | 	lua_remove(L, context_table); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* Now try any includes we have in this context */ | 
					
						
							|  |  |  | 	for (lua_pushnil(L); lua_next(L, -2); lua_pop(L, 1)) { | 
					
						
							|  |  |  | 		const char *c = lua_tostring(L, -1); | 
					
						
							|  |  |  | 		if (!c) | 
					
						
							|  |  |  | 			continue; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if (lua_find_extension(L, c, exten, priority, func, push_func)) { | 
					
						
							|  |  |  | 			/* remove the value, the key, and the includes table
 | 
					
						
							|  |  |  | 			 * from the stack.  Leave the function behind if | 
					
						
							|  |  |  | 			 * necessary */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			if (push_func) | 
					
						
							|  |  |  | 				lua_insert(L, -4); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			lua_pop(L, 3); | 
					
						
							|  |  |  | 			return 1; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* pop the includes table */ | 
					
						
							|  |  |  | 	lua_pop(L, 1); | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static struct ast_switch lua_switch = { | 
					
						
							|  |  |  |         .name		= "Lua", | 
					
						
							|  |  |  |         .description	= "Lua PBX Switch", | 
					
						
							|  |  |  |         .exists		= exists, | 
					
						
							|  |  |  |         .canmatch	= canmatch, | 
					
						
							|  |  |  |         .exec		= exec, | 
					
						
							|  |  |  |         .matchmore	= matchmore, | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int load_or_reload_lua_stuff(void) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2007-11-02 17:34:33 +00:00
										 |  |  | 	int res = AST_MODULE_LOAD_SUCCESS; | 
					
						
							| 
									
										
										
										
											2016-11-23 21:52:29 +01:00
										 |  |  | 	int loaded = 0; | 
					
						
							| 
									
										
										
										
											2007-11-02 17:34:33 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-11-02 15:36:34 +00:00
										 |  |  | 	lua_State *L = luaL_newstate(); | 
					
						
							|  |  |  | 	if (!L) { | 
					
						
							|  |  |  | 		ast_log(LOG_ERROR, "Error allocating lua_State, no memory\n"); | 
					
						
							| 
									
										
										
										
											2016-11-23 21:52:29 +01:00
										 |  |  | 		return AST_MODULE_LOAD_FAILURE; | 
					
						
							| 
									
										
										
										
											2007-11-02 15:36:34 +00:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-23 21:52:29 +01:00
										 |  |  | 	loaded = lua_reload_extensions(L); | 
					
						
							|  |  |  | 	if (loaded) { | 
					
						
							| 
									
										
										
										
											2007-11-02 15:36:34 +00:00
										 |  |  | 		const char *error = lua_tostring(L, -1); | 
					
						
							|  |  |  | 		ast_log(LOG_ERROR, "Error loading extensions.lua: %s\n", error); | 
					
						
							| 
									
										
										
										
											2016-11-23 21:52:29 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		if (loaded < 0) { | 
					
						
							|  |  |  | 			res = AST_MODULE_LOAD_DECLINE; | 
					
						
							|  |  |  | 		} else { | 
					
						
							|  |  |  | 			res = AST_MODULE_LOAD_FAILURE; | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2007-11-02 15:36:34 +00:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	lua_close(L); | 
					
						
							|  |  |  | 	return res; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int unload_module(void) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2008-09-25 21:18:12 +00:00
										 |  |  | 	ast_context_destroy(NULL, registrar); | 
					
						
							| 
									
										
										
										
											2007-11-02 15:36:34 +00:00
										 |  |  | 	ast_unregister_switch(&lua_switch); | 
					
						
							|  |  |  | 	lua_free_extensions(); | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int reload(void) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	return load_or_reload_lua_stuff(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int load_module(void) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2007-11-02 21:39:36 +00:00
										 |  |  | 	int res; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if ((res = load_or_reload_lua_stuff())) | 
					
						
							|  |  |  | 		return res; | 
					
						
							| 
									
										
										
										
											2007-11-02 15:36:34 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	if (ast_register_switch(&lua_switch)) { | 
					
						
							| 
									
										
										
										
											2022-06-24 14:09:43 +03:00
										 |  |  | 		ast_log(LOG_ERROR, "Unable to register Lua PBX switch\n"); | 
					
						
							| 
									
										
										
										
											2016-11-23 21:52:29 +01:00
										 |  |  | 		return AST_MODULE_LOAD_FAILURE; | 
					
						
							| 
									
										
										
										
											2007-11-02 15:36:34 +00:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return AST_MODULE_LOAD_SUCCESS; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
											  
											
												pbx_lua: fix regression with global sym export and context clash by pbx_config.
ASTERISK-23818 (lua contexts being overwritten by contexts of the same name in
pbx_config) surfaced because pbx_lua, having the AST_MODFLAG_GLOBAL_SYMBOLS
set, was always force loaded before pbx_config.  Since I couldn't find any
reason for pbx_lua to export it's symbols to the rest of Asterisk, I simply
changed the flag to AST_MODFLAG_DEFAULT.  Problem solved.  What I didn't
realize was that the symbols need to be exported not because Asterisk needs
them but because any external Lua modules like luasql.mysql need the base
Lua language APIs exported (ASTERISK-17279).
Back to ASTERISK-23818...  It looks like there's an issue in pbx.c where
context_merge was only merging includes, switches and ignore patterns if
the context was already existing AND has extensions, or if the context was
brand new.  If pbx_lua is loaded before pbx_config, the context will exist
BUT pbx_lua, being implemented as a switch, will never place extensions in
it, just the switch statement.  The result is that when pbx_config loads,
it never merges the switch statement created by pbx_lua into the final
context.
This patch sets pbx_lua's modflag back to AST_MODFLAG_GLOBAL_SYMBOLS and adds
an "else if" in context_merge that catches the case where an existing context
has includes, switchs or ingore patterns but no actual extensions.
ASTERISK-23818 #close
Reported by: Dennis Guse
Reported by: Timo Teräs
Tested by: George Joseph
Review: https://reviewboard.asterisk.org/r/3891/
........
Merged revisions 420146 from http://svn.asterisk.org/svn/asterisk/branches/1.8
........
Merged revisions 420147 from http://svn.asterisk.org/svn/asterisk/branches/11
........
Merged revisions 420148 from http://svn.asterisk.org/svn/asterisk/branches/12
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@420149 65c4cc65-6c06-0410-ace0-fbb531ad65f3
											
										 
											2014-08-06 16:12:26 +00:00
										 |  |  | AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS, "Lua PBX Switch", | 
					
						
							| 
									
										
										
										
											2015-05-05 20:49:04 -04:00
										 |  |  | 	.support_level = AST_MODULE_SUPPORT_EXTENDED, | 
					
						
							|  |  |  | 	.load = load_module, | 
					
						
							|  |  |  | 	.unload = unload_module, | 
					
						
							|  |  |  | 	.reload = reload, | 
					
						
							|  |  |  | ); |