Newer
Older
/*
* 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.
*/
* \file
*
* \author Matthew Nicholson <mnicholson@digium.com>
* \brief Lua PBX Switch
*
*/
/*** MODULEINFO
<depend>lua</depend>
<support_level>extended</support_level>
***/
#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"
#include "asterisk/hashtab.h"
Tilghman Lesher
committed
#include <lua.h>
#include <lauxlib.h>
#include <lualib.h>
static char *config = "extensions.lua";
static char *registrar = "pbx_lua";
#ifdef LOW_MEMORY
#define LUA_EXT_DATA_SIZE 256
#else
#define LUA_EXT_DATA_SIZE 8192
#endif
#define LUA_BUF_SIZE 4096
/* 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
Dennis Guse
committed
static char *lua_read_extensions_file(lua_State *L, long *size, int *file_not_openable);
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);
static int lua_register_switches(lua_State *L);
static int lua_register_hints(lua_State *L);
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);
Jason Parker
committed
static int lua_check_hangup(lua_State *L);
static void lua_update_registry(lua_State *L, const char *context, const char *exten, int priority);
static void lua_push_variable_table(lua_State *L);
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);
Jason Parker
committed
static void lua_create_hangup_function(lua_State *L);
static void lua_concat_args(lua_State *L, int start, int nargs);
Tilghman Lesher
committed
static void lua_state_destroy(void *data);
static void lua_datastore_fixup(void *data, struct ast_channel *old_chan, struct ast_channel *new_chan);
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);
static char *config_file_data = NULL;
static long config_file_size = 0;
static struct ast_context *local_contexts = NULL;
static struct ast_hashtab *local_table = NULL;
static const struct ast_datastore_info lua_datastore = {
.type = "lua",
.destroy = lua_state_destroy,
.chan_fixup = lua_datastore_fixup,
};
/*!
* \brief The destructor for lua_datastore
*/
Tilghman Lesher
committed
static void lua_state_destroy(void *data)
{
if (data)
lua_close(data);
}
/*!
* \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");
}
/*!
* \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);
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.
*
* \return LUA error
*
* \code
* app.playback('demo-congrats')
* \endcode
*/
static int lua_pbx_exec(lua_State *L)
{
int res, nargs = lua_gettop(L);
const char *data = "";
char *app_name, *context, *exten;
char tmp[80], tmp2[80], tmp3[LUA_EXT_DATA_SIZE];
int priority, autoservice;
struct ast_app *app;
struct ast_channel *chan;
lua_getfield(L, 1, "name");
app_name = ast_strdupa(lua_tostring(L, -1));
if (!(app = pbx_findapp(app_name))) {
lua_pushstring(L, "application '");
lua_pushstring(L, app_name);
lua_pushstring(L, "' not found");
lua_concat(L, 3);
return lua_error(L);
}
lua_getfield(L, LUA_REGISTRYINDEX, "channel");
context = ast_strdupa(ast_channel_context(chan));
exten = ast_strdupa(ast_channel_exten(chan));
priority = ast_channel_priority(chan);
lua_concat_args(L, 2, nargs);
data = lua_tostring(L, -1);
ast_verb(3, "Executing [%s@%s:%d] %s(\"%s\", \"%s\")\n",
exten, context, priority,
term_color(tmp, app_name, COLOR_BRCYAN, 0, sizeof(tmp)),
term_color(tmp2, ast_channel_name(chan), COLOR_BRMAGENTA, 0, sizeof(tmp2)),
term_color(tmp3, data, COLOR_BRMAGENTA, 0, sizeof(tmp3)));
lua_getfield(L, LUA_REGISTRYINDEX, "autoservice");
autoservice = lua_toboolean(L, -1);
lua_pop(L, 1);
if (autoservice)
ast_autoservice_stop(chan);
res = pbx_exec(chan, app, data);
lua_pop(L, 1); /* pop data */
data = "";
if (autoservice)
ast_autoservice_start(chan);
/* error executing an application, report it */
if (res) {
lua_pushinteger(L, res);
return lua_error(L);
}
if (strcmp(context, ast_channel_context(chan))) {
lua_pushstring(L, context);
lua_pushstring(L, ast_channel_context(chan));
} else if (strcmp(exten, ast_channel_exten(chan))) {
lua_pushstring(L, exten);
lua_pushstring(L, ast_channel_exten(chan));
} else if (priority != ast_channel_priority(chan)) {
lua_pushinteger(L, priority);
lua_pushinteger(L, ast_channel_priority(chan));
} else {
/* no goto - restore the original position back
* to lua state, in case this was a recursive dialplan
* call (a dialplan application re-entering dialplan) */
lua_update_registry(L, context, exten, priority);
return 0;
/* goto detected - construct error message */
lua_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);
return 0;
/*!
* \brief [lua_CFunction] Used to get the value of a variable or dialplan
* function (for access from lua, don't call directly)
* The value of the variable or function is returned. This function is the
* 'get()' function in the following example as would be seen in
* extensions.lua.
*
* \return LUA error
*
* \code
* channel.variable:get()
* \endcode
*/
static int lua_get_variable_value(lua_State *L)
{
struct ast_channel *chan;
char *value = NULL, *name;
char *workspace = ast_alloca(LUA_BUF_SIZE);
workspace[0] = '\0';
if (!lua_istable(L, 1)) {
lua_pushstring(L, "User probably used '.' instead of ':' for retrieving a channel variable value");
return lua_error(L);
}
lua_getfield(L, LUA_REGISTRYINDEX, "channel");
lua_pop(L, 1);
lua_getfield(L, 1, "name");
name = ast_strdupa(lua_tostring(L, -1));
lua_getfield(L, LUA_REGISTRYINDEX, "autoservice");
autoservice = lua_toboolean(L, -1);
lua_pop(L, 1);
if (autoservice)
ast_autoservice_stop(chan);
/* if this is a dialplan function then use ast_func_read(), otherwise
* use pbx_retrieve_variable() */
if (!ast_strlen_zero(name) && name[strlen(name) - 1] == ')') {
value = ast_func_read(chan, name, workspace, LUA_BUF_SIZE) ? NULL : workspace;
} else {
pbx_retrieve_variable(chan, name, &value, workspace, LUA_BUF_SIZE, ast_channel_varshead(chan));
if (autoservice)
ast_autoservice_start(chan);
if (value) {
lua_pushstring(L, value);
} else {
lua_pushnil(L);
}
return 1;
}
/*!
* \brief [lua_CFunction] Used to set the value of a variable or dialplan
* function (for access from lua, don't call directly)
* This function is the 'set()' function in the following example as would be
* seen in extensions.lua.
*
* \return LUA error
*
* \endcode
*/
static int lua_set_variable_value(lua_State *L)
{
const char *name, *value;
struct ast_channel *chan;
int autoservice;
if (!lua_istable(L, 1)) {
lua_pushstring(L, "User probably used '.' instead of ':' for setting a channel variable");
return lua_error(L);
}
lua_getfield(L, 1, "name");
name = ast_strdupa(lua_tostring(L, -1));
value = luaL_checkstring(L, 2);
lua_getfield(L, LUA_REGISTRYINDEX, "channel");
lua_pop(L, 1);
lua_getfield(L, LUA_REGISTRYINDEX, "autoservice");
autoservice = lua_toboolean(L, -1);
lua_pop(L, 1);
if (autoservice)
ast_autoservice_stop(chan);
pbx_builtin_setvar_helper(chan, name, value);
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
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.
*
* The value on the top of the stack is popped and used as the name.
*
* \param L the lua_State to use
*/
static void lua_push_variable_table(lua_State *L)
{
lua_newtable(L);
luaL_getmetatable(L, "variable");
lua_setmetatable(L, -2);
lua_insert(L, -2); /* move the table after the name */
lua_setfield(L, -2, "name");
lua_pushcfunction(L, &lua_get_variable_value);
lua_setfield(L, -2, "get");
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");
}
/*!
* \brief Create the global 'channel' table for accessing channel variables
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
*
* \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
*
* \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");
lua_pushcfunction(L, &lua_autoservice_stop);
lua_setglobal(L, "autoservice_stop");
lua_pushcfunction(L, &lua_autoservice_status);
lua_setglobal(L, "autoservice_status");
lua_pushboolean(L, 1);
lua_setfield(L, LUA_REGISTRYINDEX, "autoservice");
}
Jason Parker
committed
/*!
* \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");
}
/*!
* \brief [lua_CFunction] Return a lua 'variable' object (for access from lua, don't call
* directly)
* 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)
{
const char *name = luaL_checkstring(L, 2);
char *workspace = ast_alloca(LUA_BUF_SIZE);
lua_getfield(L, LUA_REGISTRYINDEX, "channel");
lua_pushvalue(L, 2);
lua_push_variable_table(L);
/* 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] != ')') {
pbx_retrieve_variable(chan, name, &value, workspace, LUA_BUF_SIZE, ast_channel_varshead(chan));
}
if (value) {
lua_pushstring(L, value);
lua_setfield(L, -2, "value");
}
}
/*!
* \brief [lua_CFunction] Set the value of a channel variable or dialplan
* function (for access from lua, don't call directly)
* This function is called to set a variable or dialplan function. It would be
* called in the following example as would be seen in extensions.lua.
*
* \code
* channel.variable = "value"
* \endcode
*/
static int lua_set_variable(lua_State *L)
{
struct ast_channel *chan;
int autoservice;
const char *name = luaL_checkstring(L, 2);
const char *value = luaL_checkstring(L, 3);
lua_getfield(L, LUA_REGISTRYINDEX, "channel");
lua_pop(L, 1);
lua_getfield(L, LUA_REGISTRYINDEX, "autoservice");
autoservice = lua_toboolean(L, -1);
lua_pop(L, 1);
if (autoservice)
ast_autoservice_stop(chan);
pbx_builtin_setvar_helper(chan, name, value);
if (autoservice)
ast_autoservice_start(chan);
return 0;
}
/*!
* \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;
if (start <= nargs && !lua_isnil(L, start)) {
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);
}
/*!
* \brief [lua_CFunction] Create a 'variable' object for accessing a dialplan
* function (for access from lua, don't call directly)
* 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);
/* 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);
lua_push_variable_table(L);
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)
{
lua_getfield(L, LUA_REGISTRYINDEX, "autoservice");
if (lua_toboolean(L, -1)) {
/* autservice already running */
lua_pop(L, 1);
return 0;
}
lua_pop(L, 1);
lua_getfield(L, LUA_REGISTRYINDEX, "channel");
ast_autoservice_start(chan);
lua_pushboolean(L, 1);
lua_setfield(L, LUA_REGISTRYINDEX, "autoservice");
* \brief [lua_CFunction] Tell pbx_lua to stop maintaining an autoservice on
* 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)
{
lua_getfield(L, LUA_REGISTRYINDEX, "autoservice");
if (!lua_toboolean(L, -1)) {
/* no autservice running */
lua_pop(L, 1);
return 0;
}
lua_pop(L, 1);
lua_getfield(L, LUA_REGISTRYINDEX, "channel");
ast_autoservice_stop(chan);
lua_pushboolean(L, 0);
lua_setfield(L, LUA_REGISTRYINDEX, "autoservice");
}
/*!
* \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;
}
Jason Parker
committed
/*!
* \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;
}
/*!
* \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);
/* prepare to prepend a new line to the traceback */
lua_pushliteral(L, "\n");
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;
}
if (!lua_isfunction(L, -1)) {
/* Same here for traceback function */
lua_pop(L, 3);
/* Original err message is on stack top now */
return 1;
}
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);
/* prepend the new line we prepared above */
lua_concat(L, 2);
/*!
* \brief Store the sort order of each context
* 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)
{
int extensions, extensions_order;
/* create the extensions_order table */
lua_newtable(L);
lua_setfield(L, LUA_REGISTRYINDEX, "extensions_order");
lua_getfield(L, LUA_REGISTRYINDEX, "extensions_order");
extensions_order = lua_gettop(L);
/* sort each context in the extensions table */
/* load the 'extensions' table */
lua_getglobal(L, "extensions");
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;
/* 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);
/* create the context_order table */
context_order = lua_gettop(L);
/* iterate through this context an populate the corrisponding
* table in the extensions_order table */
for (lua_pushnil(L); lua_next(L, context); lua_pop(L, 1)) {
int exten = lua_gettop(L) - 1;
lua_pushinteger(L, lua_objlen(L, context_order) + 1);
#else
lua_pushinteger(L, lua_rawlen(L, context_order) + 1);
#endif
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;
}
}
/* remove the extensions table and the extensions_order table */
lua_pop(L, 2);
return 0;
}
* \brief Register dialplan switches for our pbx_lua contexts.
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
*
* 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;
}
}
/* remove the extensions table */
lua_pop(L, 1);
return 0;
}
* \brief Register dialplan hints for our pbx_lua contexts.
*
* 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);