Sun May 20 06:33:56 2012

Asterisk developer's documentation


pbx_lua.c

Go to the documentation of this file.
00001 /*
00002  * Asterisk -- An open source telephony toolkit.
00003  *
00004  * Copyright (C) 1999 - 2007, Digium, Inc.
00005  *
00006  * Matthew Nicholson <mnicholson@digium.com>
00007  *
00008  * See http://www.asterisk.org for more information about
00009  * the Asterisk project. Please do not directly contact
00010  * any of the maintainers of this project for assistance;
00011  * the project provides a web site, mailing lists and IRC
00012  * channels for your use.
00013  *
00014  * This program is free software, distributed under the terms of
00015  * the GNU General Public License Version 2. See the LICENSE file
00016  * at the top of the source tree.
00017  */
00018 
00019 /*! 
00020  * \file
00021  *
00022  * \author Matthew Nicholson <mnicholson@digium.com>
00023  * \brief Lua PBX Switch
00024  *
00025  */
00026 
00027 /*** MODULEINFO
00028    <depend>lua</depend>
00029    <support_level>extended</support_level>
00030  ***/
00031 
00032 #include "asterisk.h"
00033 
00034 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 358647 $")
00035 
00036 #include "asterisk/logger.h"
00037 #include "asterisk/channel.h"
00038 #include "asterisk/pbx.h"
00039 #include "asterisk/module.h"
00040 #include "asterisk/cli.h"
00041 #include "asterisk/utils.h"
00042 #include "asterisk/term.h"
00043 #include "asterisk/paths.h"
00044 #include "asterisk/hashtab.h"
00045 
00046 #include <lua.h>
00047 #include <lauxlib.h>
00048 #include <lualib.h>
00049 
00050 static char *config = "extensions.lua";
00051 static char *registrar = "pbx_lua";
00052 
00053 #ifdef LOW_MEMORY
00054 #define LUA_EXT_DATA_SIZE 256
00055 #else
00056 #define LUA_EXT_DATA_SIZE 8192
00057 #endif
00058 #define LUA_BUF_SIZE 4096
00059 
00060 /* This value is used by the lua engine to signal that a Goto or dialplan jump
00061  * was detected. Ensure this value does not conflict with any values dialplan
00062  * applications might return */
00063 #define LUA_GOTO_DETECTED 5
00064 
00065 static char *lua_read_extensions_file(lua_State *L, long *size);
00066 static int lua_load_extensions(lua_State *L, struct ast_channel *chan);
00067 static int lua_reload_extensions(lua_State *L);
00068 static void lua_free_extensions(void);
00069 static int lua_sort_extensions(lua_State *L);
00070 static int lua_register_switches(lua_State *L);
00071 static int lua_register_hints(lua_State *L);
00072 static int lua_extension_cmp(lua_State *L);
00073 static int lua_find_extension(lua_State *L, const char *context, const char *exten, int priority, ast_switch_f *func, int push_func);
00074 static int lua_pbx_findapp(lua_State *L);
00075 static int lua_pbx_exec(lua_State *L);
00076 
00077 static int lua_get_variable_value(lua_State *L);
00078 static int lua_set_variable_value(lua_State *L);
00079 static int lua_get_variable(lua_State *L);
00080 static int lua_set_variable(lua_State *L);
00081 static int lua_func_read(lua_State *L);
00082 
00083 static int lua_autoservice_start(lua_State *L);
00084 static int lua_autoservice_stop(lua_State *L);
00085 static int lua_autoservice_status(lua_State *L);
00086 static int lua_check_hangup(lua_State *L);
00087 static int lua_error_function(lua_State *L);
00088 
00089 static void lua_update_registry(lua_State *L, const char *context, const char *exten, int priority);
00090 static void lua_push_variable_table(lua_State *L);
00091 static void lua_create_app_table(lua_State *L);
00092 static void lua_create_channel_table(lua_State *L);
00093 static void lua_create_variable_metatable(lua_State *L);
00094 static void lua_create_application_metatable(lua_State *L);
00095 static void lua_create_autoservice_functions(lua_State *L);
00096 static void lua_create_hangup_function(lua_State *L);
00097 static void lua_concat_args(lua_State *L, int start, int nargs);
00098 
00099 static void lua_state_destroy(void *data);
00100 static void lua_datastore_fixup(void *data, struct ast_channel *old_chan, struct ast_channel *new_chan);
00101 static lua_State *lua_get_state(struct ast_channel *chan);
00102 
00103 static int exists(struct ast_channel *chan, const char *context, const char *exten, int priority, const char *callerid, const char *data);
00104 static int canmatch(struct ast_channel *chan, const char *context, const char *exten, int priority, const char *callerid, const char *data);
00105 static int matchmore(struct ast_channel *chan, const char *context, const char *exten, int priority, const char *callerid, const char *data);
00106 static int exec(struct ast_channel *chan, const char *context, const char *exten, int priority, const char *callerid, const char *data);
00107 
00108 AST_MUTEX_DEFINE_STATIC(config_file_lock);
00109 static char *config_file_data = NULL;
00110 static long config_file_size = 0;
00111 
00112 static struct ast_context *local_contexts = NULL;
00113 static struct ast_hashtab *local_table = NULL;
00114 
00115 static const struct ast_datastore_info lua_datastore = {
00116    .type = "lua",
00117    .destroy = lua_state_destroy,
00118    .chan_fixup = lua_datastore_fixup,
00119 };
00120 
00121 
00122 /*!
00123  * \brief The destructor for lua_datastore
00124  */
00125 static void lua_state_destroy(void *data)
00126 {
00127    if (data)
00128       lua_close(data);
00129 }
00130 
00131 /*!
00132  * \brief The fixup function for the lua_datastore.
00133  * \param data the datastore data, in this case it will be a lua_State
00134  * \param old_chan the channel we are moving from
00135  * \param new_chan the channel we are moving to
00136  *
00137  * This function updates our internal channel pointer.
00138  */
00139 static void lua_datastore_fixup(void *data, struct ast_channel *old_chan, struct ast_channel *new_chan)
00140 {
00141    lua_State *L = data;
00142    lua_pushlightuserdata(L, new_chan);
00143    lua_setfield(L, LUA_REGISTRYINDEX, "channel");
00144 }
00145 
00146 /*!
00147  * \brief [lua_CFunction] Find an app and return it in a lua table (for access from lua, don't
00148  * call directly)
00149  *
00150  * This function would be called in the following example as it would be found
00151  * in extensions.lua.
00152  *
00153  * \code
00154  * app.dial
00155  * \endcode
00156  */
00157 static int lua_pbx_findapp(lua_State *L)
00158 {
00159    const char *app_name = luaL_checkstring(L, 2);
00160    
00161    lua_newtable(L);
00162 
00163    lua_pushstring(L, "name");
00164    lua_pushstring(L, app_name);
00165    lua_settable(L, -3);
00166 
00167    luaL_getmetatable(L, "application");
00168    lua_setmetatable(L, -2);
00169 
00170    return 1;
00171 }
00172 
00173 /*!
00174  * \brief [lua_CFunction] This function is part of the 'application' metatable
00175  * and is used to execute applications similar to pbx_exec() (for access from
00176  * lua, don't call directly)
00177  *
00178  * \param L the lua_State to use
00179  * \return nothing
00180  *
00181  * This funciton is executed as the '()' operator for apps accessed through the
00182  * 'app' table.
00183  *
00184  * \code
00185  * app.playback('demo-congrats')
00186  * \endcode
00187  */
00188 static int lua_pbx_exec(lua_State *L)
00189 {
00190    int res, nargs = lua_gettop(L);
00191    const char *data = "";
00192    char *app_name, *context, *exten;
00193    char tmp[80], tmp2[80], tmp3[LUA_EXT_DATA_SIZE];
00194    int priority, autoservice;
00195    struct ast_app *app;
00196    struct ast_channel *chan;
00197 
00198    lua_getfield(L, 1, "name");
00199    app_name = ast_strdupa(lua_tostring(L, -1));
00200    lua_pop(L, 1);
00201    
00202    if (!(app = pbx_findapp(app_name))) {
00203       lua_pushstring(L, "application '");
00204       lua_pushstring(L, app_name);
00205       lua_pushstring(L, "' not found");
00206       lua_concat(L, 3);
00207       return lua_error(L);
00208    }
00209    
00210 
00211    lua_getfield(L, LUA_REGISTRYINDEX, "channel");
00212    chan = lua_touserdata(L, -1);
00213    lua_pop(L, 1);
00214    
00215    context = ast_strdupa(ast_channel_context(chan));
00216    exten = ast_strdupa(ast_channel_exten(chan));
00217    priority = ast_channel_priority(chan);
00218    
00219    lua_concat_args(L, 2, nargs);
00220    data = lua_tostring(L, -1);
00221 
00222    ast_verb(3, "Executing [%s@%s:%d] %s(\"%s\", \"%s\")\n",
00223          exten, context, priority,
00224          term_color(tmp, app_name, COLOR_BRCYAN, 0, sizeof(tmp)),
00225          term_color(tmp2, ast_channel_name(chan), COLOR_BRMAGENTA, 0, sizeof(tmp2)),
00226          term_color(tmp3, data, COLOR_BRMAGENTA, 0, sizeof(tmp3)));
00227 
00228    lua_getfield(L, LUA_REGISTRYINDEX, "autoservice");
00229    autoservice = lua_toboolean(L, -1);
00230    lua_pop(L, 1);
00231 
00232    if (autoservice)
00233       ast_autoservice_stop(chan);
00234 
00235    res = pbx_exec(chan, app, data);
00236 
00237    lua_pop(L, 1); /* pop data */
00238    data = "";
00239 
00240    if (autoservice)
00241       ast_autoservice_start(chan);
00242 
00243    /* error executing an application, report it */
00244    if (res) {
00245       lua_pushinteger(L, res);
00246       return lua_error(L);
00247    }
00248 
00249    if (strcmp(context, ast_channel_context(chan))) {
00250       lua_pushstring(L, context);
00251       lua_pushstring(L, ast_channel_context(chan));
00252       lua_pushliteral(L, "context");
00253    } else if (strcmp(exten, ast_channel_exten(chan))) {
00254       lua_pushstring(L, exten);
00255       lua_pushstring(L, ast_channel_exten(chan));
00256       lua_pushliteral(L, "exten");
00257    } else if (priority != ast_channel_priority(chan)) {
00258       lua_pushinteger(L, priority);
00259       lua_pushinteger(L, ast_channel_priority(chan));
00260       lua_pushliteral(L, "priority");
00261    } else {
00262       /* no goto - restore the original position back
00263        * to lua state, in case this was a recursive dialplan
00264        * call (a dialplan application re-entering dialplan) */
00265       lua_update_registry(L, context, exten, priority);
00266       return 0;
00267    }
00268 
00269    /* goto detected - construct error message */
00270    lua_insert(L, -3);
00271                                        
00272    lua_pushliteral(L, " changed from ");                        
00273    lua_insert(L, -3);                                  
00274                                         
00275    lua_pushliteral(L, " to ");                              
00276    lua_insert(L, -2);                                  
00277                                         
00278    lua_concat(L, 5);                            
00279                                         
00280    ast_debug(2, "Goto detected: %s\n", lua_tostring(L, -1));               
00281    lua_pop(L, 1);                               
00282                                         
00283    /* let the lua engine know it needs to return control to the pbx */              
00284    lua_pushinteger(L, LUA_GOTO_DETECTED);                      
00285    lua_error(L);
00286 
00287    return 0;
00288 }
00289 
00290 /*!
00291  * \brief [lua_CFunction] Used to get the value of a variable or dialplan
00292  * function (for access from lua, don't call directly)
00293  *
00294  * The value of the variable or function is returned.  This function is the
00295  * 'get()' function in the following example as would be seen in
00296  * extensions.lua.
00297  *
00298  * \code
00299  * channel.variable:get()
00300  * \endcode
00301  */
00302 static int lua_get_variable_value(lua_State *L)
00303 {
00304    struct ast_channel *chan;
00305    char *value = NULL, *name;
00306    char *workspace = alloca(LUA_BUF_SIZE);
00307    int autoservice;
00308 
00309    workspace[0] = '\0';
00310 
00311    if (!lua_istable(L, 1)) {
00312       lua_pushstring(L, "User probably used '.' instead of ':' for retrieving a channel variable value");
00313       return lua_error(L);
00314    }
00315    
00316    lua_getfield(L, LUA_REGISTRYINDEX, "channel");
00317    chan = lua_touserdata(L, -1);
00318    lua_pop(L, 1);
00319 
00320    lua_getfield(L, 1, "name");
00321    name = ast_strdupa(lua_tostring(L, -1));
00322    lua_pop(L, 1);
00323    
00324    lua_getfield(L, LUA_REGISTRYINDEX, "autoservice");
00325    autoservice = lua_toboolean(L, -1);
00326    lua_pop(L, 1);
00327 
00328    if (autoservice)
00329       ast_autoservice_stop(chan);
00330    
00331    /* if this is a dialplan function then use ast_func_read(), otherwise
00332     * use pbx_retrieve_variable() */
00333    if (!ast_strlen_zero(name) && name[strlen(name) - 1] == ')') {
00334       value = ast_func_read(chan, name, workspace, LUA_BUF_SIZE) ? NULL : workspace;
00335    } else {
00336       pbx_retrieve_variable(chan, name, &value, workspace, LUA_BUF_SIZE, ast_channel_varshead(chan));
00337    }
00338    
00339    if (autoservice)
00340       ast_autoservice_start(chan);
00341 
00342    if (value) {
00343       lua_pushstring(L, value);
00344    } else {
00345       lua_pushnil(L);
00346    }
00347 
00348    return 1;
00349 }
00350 
00351 /*!
00352  * \brief [lua_CFunction] Used to set the value of a variable or dialplan
00353  * function (for access from lua, don't call directly)
00354  * 
00355  * This function is the 'set()' function in the following example as would be
00356  * seen in extensions.lua.
00357  *
00358  * \code
00359  * channel.variable:set("value")
00360  * \endcode
00361  */
00362 static int lua_set_variable_value(lua_State *L)
00363 {
00364    const char *name, *value;
00365    struct ast_channel *chan;
00366    int autoservice;
00367 
00368    if (!lua_istable(L, 1)) {
00369       lua_pushstring(L, "User probably used '.' instead of ':' for setting a channel variable");
00370       return lua_error(L);
00371    }
00372 
00373    lua_getfield(L, 1, "name");
00374    name = ast_strdupa(lua_tostring(L, -1));
00375    lua_pop(L, 1);
00376 
00377    value = luaL_checkstring(L, 2);
00378    
00379    lua_getfield(L, LUA_REGISTRYINDEX, "channel");
00380    chan = lua_touserdata(L, -1);
00381    lua_pop(L, 1);
00382 
00383    lua_getfield(L, LUA_REGISTRYINDEX, "autoservice");
00384    autoservice = lua_toboolean(L, -1);
00385    lua_pop(L, 1);
00386 
00387    if (autoservice)
00388       ast_autoservice_stop(chan);
00389 
00390    pbx_builtin_setvar_helper(chan, name, value);
00391    
00392    if (autoservice)
00393       ast_autoservice_start(chan);
00394 
00395    return 0;
00396 }
00397 
00398 /*!
00399  * \brief Update the lua registry with the given context, exten, and priority.
00400  *
00401  * \param L the lua_State to use
00402  * \param context the new context
00403  * \param exten the new exten
00404  * \param priority the new priority
00405  */
00406 static void lua_update_registry(lua_State *L, const char *context, const char *exten, int priority)
00407 {
00408    lua_pushstring(L, context);
00409    lua_setfield(L, LUA_REGISTRYINDEX, "context");
00410 
00411    lua_pushstring(L, exten);
00412    lua_setfield(L, LUA_REGISTRYINDEX, "exten");
00413 
00414    lua_pushinteger(L, priority);
00415    lua_setfield(L, LUA_REGISTRYINDEX, "priority");
00416 }
00417 
00418 /*!
00419  * \brief Push a 'variable' table on the stack for access the channel variable
00420  * with the given name.
00421  *
00422  * The value on the top of the stack is popped and used as the name.
00423  *
00424  * \param L the lua_State to use
00425  * \param name the name of the variable
00426  */
00427 static void lua_push_variable_table(lua_State *L)
00428 {
00429    lua_newtable(L);
00430    luaL_getmetatable(L, "variable");
00431    lua_setmetatable(L, -2);
00432 
00433    lua_insert(L, -2); /* move the table after the name */
00434    lua_setfield(L, -2, "name");
00435    
00436    lua_pushcfunction(L, &lua_get_variable_value);
00437    lua_setfield(L, -2, "get");
00438    
00439    lua_pushcfunction(L, &lua_set_variable_value);
00440    lua_setfield(L, -2, "set");
00441 }
00442 
00443 /*!
00444  * \brief Create the global 'app' table for executing applications
00445  *
00446  * \param L the lua_State to use
00447  */
00448 static void lua_create_app_table(lua_State *L)
00449 {
00450    lua_newtable(L);
00451    luaL_newmetatable(L, "app");
00452 
00453    lua_pushstring(L, "__index");
00454    lua_pushcfunction(L, &lua_pbx_findapp);
00455    lua_settable(L, -3);
00456 
00457    lua_setmetatable(L, -2);
00458    lua_setglobal(L, "app");
00459 }
00460 
00461 /*!
00462  * \brief Create the global 'channel' table for accesing channel variables
00463  *
00464  * \param L the lua_State to use
00465  */
00466 static void lua_create_channel_table(lua_State *L)
00467 {
00468    lua_newtable(L);
00469    luaL_newmetatable(L, "channel_data");
00470 
00471    lua_pushstring(L, "__index");
00472    lua_pushcfunction(L, &lua_get_variable);
00473    lua_settable(L, -3);
00474 
00475    lua_pushstring(L, "__newindex");
00476    lua_pushcfunction(L, &lua_set_variable);
00477    lua_settable(L, -3);
00478 
00479    lua_setmetatable(L, -2);
00480    lua_setglobal(L, "channel");
00481 }
00482 
00483 /*!
00484  * \brief Create the 'variable' metatable, used to retrieve channel variables
00485  *
00486  * \param L the lua_State to use
00487  */
00488 static void lua_create_variable_metatable(lua_State *L)
00489 {
00490    luaL_newmetatable(L, "variable");
00491 
00492    lua_pushstring(L, "__call");
00493    lua_pushcfunction(L, &lua_func_read);
00494    lua_settable(L, -3);
00495 
00496    lua_pop(L, 1);
00497 }
00498 
00499 /*!
00500  * \brief Create the 'application' metatable, used to execute asterisk
00501  * applications from lua 
00502  *
00503  * \param L the lua_State to use
00504  */
00505 static void lua_create_application_metatable(lua_State *L)
00506 {
00507    luaL_newmetatable(L, "application");
00508 
00509    lua_pushstring(L, "__call");
00510    lua_pushcfunction(L, &lua_pbx_exec);
00511    lua_settable(L, -3);
00512 
00513    lua_pop(L, 1);
00514 }
00515 
00516 /*!
00517  * \brief Create the autoservice functions
00518  *
00519  * \param L the lua_State to use
00520  */
00521 static void lua_create_autoservice_functions(lua_State *L)
00522 {
00523    lua_pushcfunction(L, &lua_autoservice_start);
00524    lua_setglobal(L, "autoservice_start");
00525    
00526    lua_pushcfunction(L, &lua_autoservice_stop);
00527    lua_setglobal(L, "autoservice_stop");
00528 
00529    lua_pushcfunction(L, &lua_autoservice_status);
00530    lua_setglobal(L, "autoservice_status");
00531 
00532    lua_pushboolean(L, 1);
00533    lua_setfield(L, LUA_REGISTRYINDEX, "autoservice");
00534 }
00535 
00536 /*!
00537  * \brief Create the hangup check function
00538  *
00539  * \param L the lua_State to use
00540  */
00541 static void lua_create_hangup_function(lua_State *L)
00542 {
00543    lua_pushcfunction(L, &lua_check_hangup);
00544    lua_setglobal(L, "check_hangup");
00545 }
00546 
00547 /*!
00548  * \brief [lua_CFunction] Return a lua 'variable' object (for access from lua, don't call
00549  * directly)
00550  * 
00551  * This function is called to lookup a variable construct a 'variable' object.
00552  * It would be called in the following example as would be seen in
00553  * extensions.lua.
00554  *
00555  * \code
00556  * channel.variable
00557  * \endcode
00558  */
00559 static int lua_get_variable(lua_State *L)
00560 {
00561    struct ast_channel *chan;
00562    const char *name = luaL_checkstring(L, 2);
00563    char *value = NULL;
00564    char *workspace = alloca(LUA_BUF_SIZE);
00565    workspace[0] = '\0';
00566    
00567    lua_getfield(L, LUA_REGISTRYINDEX, "channel");
00568    chan = lua_touserdata(L, -1);
00569    lua_pop(L, 1);
00570 
00571    lua_pushvalue(L, 2);
00572    lua_push_variable_table(L);
00573    
00574    /* if this is not a request for a dialplan funciton attempt to retrieve
00575     * the value of the variable */
00576    if (!ast_strlen_zero(name) && name[strlen(name) - 1] != ')') {
00577       pbx_retrieve_variable(chan, name, &value, workspace, LUA_BUF_SIZE, ast_channel_varshead(chan));
00578    }
00579 
00580    if (value) {
00581       lua_pushstring(L, value);
00582       lua_setfield(L, -2, "value");
00583    }
00584 
00585    return 1;   
00586 }
00587 
00588 /*!
00589  * \brief [lua_CFunction] Set the value of a channel variable or dialplan
00590  * function (for access from lua, don't call directly)
00591  * 
00592  * This function is called to set a variable or dialplan function.  It would be
00593  * called in the following example as would be seen in extensions.lua.
00594  *
00595  * \code
00596  * channel.variable = "value"
00597  * \endcode
00598  */
00599 static int lua_set_variable(lua_State *L)
00600 {
00601    struct ast_channel *chan;
00602    int autoservice;
00603    const char *name = luaL_checkstring(L, 2);
00604    const char *value = luaL_checkstring(L, 3);
00605 
00606    lua_getfield(L, LUA_REGISTRYINDEX, "channel");
00607    chan = lua_touserdata(L, -1);
00608    lua_pop(L, 1);
00609 
00610    lua_getfield(L, LUA_REGISTRYINDEX, "autoservice");
00611    autoservice = lua_toboolean(L, -1);
00612    lua_pop(L, 1);
00613 
00614    if (autoservice)
00615       ast_autoservice_stop(chan);
00616 
00617    pbx_builtin_setvar_helper(chan, name, value);
00618    
00619    if (autoservice)
00620       ast_autoservice_start(chan);
00621 
00622    return 0;
00623 }
00624 
00625 /*!
00626  * \brief Concatenate a list of lua function arguments into a comma separated
00627  * string.
00628  * \param L the lua_State to use
00629  * \param start the index of the first argument
00630  * \param nargs the number of args
00631  *
00632  * The resulting string will be left on the top of the stack.
00633  */
00634 static void lua_concat_args(lua_State *L, int start, int nargs) {
00635    int concat = 0;
00636    int i = start + 1;
00637 
00638    if (start <= nargs && !lua_isnil(L, start)) {
00639       lua_pushvalue(L, start);
00640       concat += 1;
00641    }
00642 
00643    for (; i <= nargs; i++) {
00644       if (lua_isnil(L, i)) {
00645          lua_pushliteral(L, ",");
00646          concat += 1;
00647       } else {
00648          lua_pushliteral(L, ",");
00649          lua_pushvalue(L, i);
00650          concat += 2;
00651       }
00652    }
00653 
00654    lua_concat(L, concat);
00655 }
00656 
00657 /*!
00658  * \brief [lua_CFunction] Create a 'variable' object for accessing a dialplan
00659  * function (for access from lua, don't call directly)
00660  * 
00661  * This function is called to create a 'variable' object to access a dialplan
00662  * function.  It would be called in the following example as would be seen in
00663  * extensions.lua.
00664  *
00665  * \code
00666  * channel.func("arg1", "arg2", "arg3")
00667  * \endcode
00668  *
00669  * To actually do anything with the resulting value you must use the 'get()'
00670  * and 'set()' methods (the reason is the resulting value is not a value, but
00671  * an object in the form of a lua table).
00672  */
00673 static int lua_func_read(lua_State *L)
00674 {
00675    int nargs = lua_gettop(L);
00676 
00677    /* build a string in the form of "func_name(arg1,arg2,arg3)" */
00678    lua_getfield(L, 1, "name");
00679    lua_pushliteral(L, "(");
00680    lua_concat_args(L, 2, nargs);
00681    lua_pushliteral(L, ")");
00682    lua_concat(L, 4);
00683 
00684    lua_push_variable_table(L);
00685    return 1;
00686 }
00687 
00688 /*!
00689  * \brief [lua_CFunction] Tell pbx_lua to maintain an autoservice on this
00690  * channel (for access from lua, don't call directly)
00691  *
00692  * \param L the lua_State to use
00693  *
00694  * This function will set a flag that will cause pbx_lua to maintain an
00695  * autoservice on this channel.  The autoservice will automatically be stopped
00696  * and restarted before calling applications and functions.
00697  */
00698 static int lua_autoservice_start(lua_State *L)
00699 {
00700    struct ast_channel *chan;
00701 
00702    lua_getfield(L, LUA_REGISTRYINDEX, "autoservice");
00703    if (lua_toboolean(L, -1)) {
00704       /* autservice already running */
00705       lua_pop(L, 1);
00706       return 0;
00707    }
00708    lua_pop(L, 1);
00709 
00710    lua_getfield(L, LUA_REGISTRYINDEX, "channel");
00711    chan = lua_touserdata(L, -1);
00712    lua_pop(L, 1);
00713 
00714    ast_autoservice_start(chan);
00715 
00716    lua_pushboolean(L, 1);
00717    lua_setfield(L, LUA_REGISTRYINDEX, "autoservice");
00718    return 0;
00719 }
00720 
00721 /*!
00722  * \brief [lua_CFunction] Tell pbx_lua to stop maintaning an autoservice on
00723  * this channel (for access from lua, don't call directly)
00724  *
00725  * \param L the lua_State to use
00726  *
00727  * This function will stop any autoservice running and turn off the autoservice
00728  * flag.  If this function returns false, it's probably because no autoservice
00729  * was running to begin with.
00730  */
00731 static int lua_autoservice_stop(lua_State *L)
00732 {
00733    struct ast_channel *chan;
00734 
00735    lua_getfield(L, LUA_REGISTRYINDEX, "autoservice");
00736    if (!lua_toboolean(L, -1)) {
00737       /* no autservice running */
00738       lua_pop(L, 1);
00739       return 0;
00740    }
00741    lua_pop(L, 1);
00742 
00743    lua_getfield(L, LUA_REGISTRYINDEX, "channel");
00744    chan = lua_touserdata(L, -1);
00745    lua_pop(L, 1);
00746 
00747    ast_autoservice_stop(chan);
00748 
00749    lua_pushboolean(L, 0);
00750    lua_setfield(L, LUA_REGISTRYINDEX, "autoservice");
00751    return 0;
00752 }
00753 
00754 /*!
00755  * \brief [lua_CFunction] Get the status of the autoservice flag (for access
00756  * from lua, don't call directly)
00757  *
00758  * \param L the lua_State to use
00759  *
00760  * \return This function returns the status of the autoservice flag as a
00761  * boolean to its lua caller.
00762  */
00763 static int lua_autoservice_status(lua_State *L)
00764 {
00765    lua_getfield(L, LUA_REGISTRYINDEX, "autoservice");
00766    return 1;
00767 }
00768 
00769 /*!
00770  * \brief [lua_CFunction] Check if this channel has been hungup or not (for
00771  * access from lua, don't call directly)
00772  *
00773  * \param L the lua_State to use
00774  *
00775  * \return This function returns true if the channel was hungup
00776  */
00777 static int lua_check_hangup(lua_State *L)
00778 {
00779    struct ast_channel *chan;
00780    lua_getfield(L, LUA_REGISTRYINDEX, "channel");
00781    chan = lua_touserdata(L, -1);
00782    lua_pop(L, 1);
00783 
00784    lua_pushboolean(L, ast_check_hangup(chan));
00785    return 1;
00786 }
00787 
00788 /*!
00789  * \brief [lua_CFunction] Handle lua errors (for access from lua, don't call
00790  * directly)
00791  *
00792  * \param L the lua_State to use
00793  */
00794 static int lua_error_function(lua_State *L)
00795 {
00796    int message_index;
00797 
00798    /* pass number arguments right through back to asterisk*/
00799    if (lua_isnumber(L, -1)) {
00800       return 1;
00801    }
00802 
00803    /* if we are here then we have a string error message, let's attach a
00804     * backtrace to it */
00805    message_index = lua_gettop(L);
00806 
00807    /* prepare to prepend a new line to the traceback */
00808    lua_pushliteral(L, "\n");
00809 
00810    lua_getglobal(L, "debug");
00811    lua_getfield(L, -1, "traceback");
00812    lua_remove(L, -2); /* remove the 'debug' table */
00813 
00814    lua_pushvalue(L, message_index);
00815    lua_remove(L, message_index);
00816 
00817    lua_pushnumber(L, 2);
00818 
00819    lua_call(L, 2, 1);
00820 
00821    /* prepend the new line we prepared above */
00822    lua_concat(L, 2);
00823 
00824    return 1;
00825 }
00826 
00827 /*!
00828  * \brief Store the sort order of each context
00829  
00830  * In the event of an error, an error string will be pushed onto the lua stack.
00831  *
00832  * \retval 0 success
00833  * \retval 1 failure
00834  */
00835 static int lua_sort_extensions(lua_State *L)
00836 {
00837    int extensions, extensions_order;
00838 
00839    /* create the extensions_order table */
00840    lua_newtable(L);
00841    lua_setfield(L, LUA_REGISTRYINDEX, "extensions_order");
00842    lua_getfield(L, LUA_REGISTRYINDEX, "extensions_order");
00843    extensions_order = lua_gettop(L);
00844 
00845    /* sort each context in the extensions table */
00846    /* load the 'extensions' table */
00847    lua_getglobal(L, "extensions");
00848    extensions = lua_gettop(L);
00849    if (lua_isnil(L, -1)) {
00850       lua_pop(L, 1);
00851       lua_pushstring(L, "Unable to find 'extensions' table in extensions.lua\n");
00852       return 1;
00853    }
00854 
00855    /* iterate through the extensions table and create a
00856     * matching table (holding the sort order) in the
00857     * extensions_order table for each context that is found
00858     */
00859    for (lua_pushnil(L); lua_next(L, extensions); lua_pop(L, 1)) {
00860       int context = lua_gettop(L);
00861       int context_name = context - 1;
00862       int context_order;
00863 
00864       /* copy the context_name to be used as the key for the
00865        * context_order table in the extensions_order table later */
00866       lua_pushvalue(L, context_name);
00867 
00868       /* create the context_order table */
00869       lua_newtable(L);
00870       context_order = lua_gettop(L);
00871 
00872       /* iterate through this context an popluate the corrisponding
00873        * table in the extensions_order table */
00874       for (lua_pushnil(L); lua_next(L, context); lua_pop(L, 1)) {
00875          int exten = lua_gettop(L) - 1;
00876 
00877          lua_pushinteger(L, lua_objlen(L, context_order) + 1);
00878          lua_pushvalue(L, exten);
00879          lua_settable(L, context_order);
00880       }
00881       lua_settable(L, extensions_order); /* put the context_order table in the extensions_order table */
00882 
00883       /* now sort the new table */
00884 
00885       /* push the table.sort function */
00886       lua_getglobal(L, "table");
00887       lua_getfield(L, -1, "sort");
00888       lua_remove(L, -2); /* remove the 'table' table */
00889 
00890       /* push the context_order table */
00891       lua_pushvalue(L, context_name);
00892       lua_gettable(L, extensions_order);
00893 
00894       /* push the comp function */
00895       lua_pushcfunction(L, &lua_extension_cmp);
00896 
00897       if (lua_pcall(L, 2, 0, 0)) {
00898          lua_insert(L, -5);
00899          lua_pop(L, 4);
00900          return 1;
00901       }
00902    }
00903    
00904    /* remove the extensions table and the extensions_order table */
00905    lua_pop(L, 2);
00906    return 0;
00907 }
00908 
00909 /*!
00910  * \brief Register dialplan switches for our pbx_lua contexs.
00911  *
00912  * In the event of an error, an error string will be pushed onto the lua stack.
00913  *
00914  * \retval 0 success
00915  * \retval 1 failure
00916  */
00917 static int lua_register_switches(lua_State *L)
00918 {
00919    int extensions;
00920    struct ast_context *con = NULL;
00921 
00922    /* create the hash table for our contexts */
00923    /* XXX do we ever need to destroy this? pbx_config does not */
00924    if (!local_table)
00925       local_table = ast_hashtab_create(17, ast_hashtab_compare_contexts, ast_hashtab_resize_java, ast_hashtab_newsize_java, ast_hashtab_hash_contexts, 0);
00926 
00927    /* load the 'extensions' table */
00928    lua_getglobal(L, "extensions");
00929    extensions = lua_gettop(L);
00930    if (lua_isnil(L, -1)) {
00931       lua_pop(L, 1);
00932       lua_pushstring(L, "Unable to find 'extensions' table in extensions.lua\n");
00933       return 1;
00934    }
00935 
00936    /* iterate through the extensions table and register a context and
00937     * dialplan switch for each lua context
00938     */
00939    for (lua_pushnil(L); lua_next(L, extensions); lua_pop(L, 1)) {
00940       int context = lua_gettop(L);
00941       int context_name = context - 1;
00942       const char *context_str = lua_tostring(L, context_name);
00943 
00944       /* find or create this context */
00945       con = ast_context_find_or_create(&local_contexts, local_table, context_str, registrar);
00946       if (!con) {
00947          /* remove extensions table and context key and value */
00948          lua_pop(L, 3);
00949          lua_pushstring(L, "Failed to find or create context\n");
00950          return 1;
00951       }
00952 
00953       /* register the switch */
00954       if (ast_context_add_switch2(con, "Lua", "", 0, registrar)) {
00955          /* remove extensions table and context key and value */
00956          lua_pop(L, 3);
00957          lua_pushstring(L, "Unable to create switch for context\n");
00958          return 1;
00959       }
00960    }
00961    
00962    /* remove the extensions table */
00963    lua_pop(L, 1);
00964    return 0;
00965 }
00966 
00967 /*!
00968  * \brief Register dialplan hints for our pbx_lua contexs.
00969  *
00970  * In the event of an error, an error string will be pushed onto the lua stack.
00971  *
00972  * \retval 0 success
00973  * \retval 1 failure
00974  */
00975 static int lua_register_hints(lua_State *L)
00976 {
00977    int hints;
00978    struct ast_context *con = NULL;
00979 
00980    /* create the hash table for our contexts */
00981    /* XXX do we ever need to destroy this? pbx_config does not */
00982    if (!local_table)
00983       local_table = ast_hashtab_create(17, ast_hashtab_compare_contexts, ast_hashtab_resize_java, ast_hashtab_newsize_java, ast_hashtab_hash_contexts, 0);
00984 
00985    /* load the 'hints' table */
00986    lua_getglobal(L, "hints");
00987    hints = lua_gettop(L);
00988    if (lua_isnil(L, -1)) {
00989       /* hints table not found, move along */
00990       lua_pop(L, 1);
00991       return 0;
00992    }
00993 
00994    /* iterate through the hints table and register each context and
00995     * the hints that go along with it
00996     */
00997    for (lua_pushnil(L); lua_next(L, hints); lua_pop(L, 1)) {
00998       int context = lua_gettop(L);
00999       int context_name = context - 1;
01000       const char *context_str = lua_tostring(L, context_name);
01001 
01002       /* find or create this context */
01003       con = ast_context_find_or_create(&local_contexts, local_table, context_str, registrar);
01004       if (!con) {
01005          /* remove hints table and context key and value */
01006          lua_pop(L, 3);
01007          lua_pushstring(L, "Failed to find or create context\n");
01008          return 1;
01009       }
01010 
01011       /* register each hint */
01012       for (lua_pushnil(L); lua_next(L, context); lua_pop(L, 1)) {
01013          const char *hint_value = lua_tostring(L, -1);
01014          const char *hint_name;
01015 
01016          /* the hint value is not a string, ignore it */
01017          if (!hint_value) {
01018             continue;
01019          }
01020 
01021          /* copy the name then convert it to a string */
01022          lua_pushvalue(L, -2);
01023          if (!(hint_name = lua_tostring(L, -1))) {
01024             /* ignore non-string value */
01025             lua_pop(L, 1);
01026             continue;
01027          }
01028 
01029          if (ast_add_extension2(con, 0, hint_name, PRIORITY_HINT, NULL, NULL, hint_value, NULL, NULL, registrar)) {
01030             /* remove hints table, hint name, hint value,
01031              * key copy, context name, and contex table */
01032             lua_pop(L, 6);
01033             lua_pushstring(L, "Error creating hint\n");
01034             return 1;
01035          }
01036 
01037          /* pop the name copy */
01038          lua_pop(L, 1);
01039       }
01040    }
01041 
01042    /* remove the hints table */
01043    lua_pop(L, 1);
01044 
01045    return 0;
01046 }
01047 
01048 /*!
01049  * \brief [lua_CFunction] Compare two extensions (for access from lua, don't
01050  * call directly)
01051  *
01052  * This function returns true if the first extension passed should match after
01053  * the second.  It behaves like the '<' operator.
01054  */
01055 static int lua_extension_cmp(lua_State *L)
01056 {
01057    const char *a = luaL_checkstring(L, -2);
01058    const char *b = luaL_checkstring(L, -1);
01059 
01060    if (ast_extension_cmp(a, b) == -1)
01061       lua_pushboolean(L, 1);
01062    else
01063       lua_pushboolean(L, 0);
01064 
01065    return 1;
01066 }
01067 
01068 /*!
01069  * \brief Load the extensions.lua file in to a buffer and execute the file
01070  *
01071  * \param L the lua_State to use
01072  * \param size a pointer to store the size of the buffer
01073  *
01074  * \note The caller is expected to free the buffer at some point.
01075  *
01076  * \return a pointer to the buffer
01077  */
01078 static char *lua_read_extensions_file(lua_State *L, long *size)
01079 {
01080    FILE *f;
01081    int error_func;
01082    char *data;
01083    char *path = alloca(strlen(config) + strlen(ast_config_AST_CONFIG_DIR) + 2);
01084    sprintf(path, "%s/%s", ast_config_AST_CONFIG_DIR, config);
01085 
01086    if (!(f = fopen(path, "r"))) {
01087       lua_pushstring(L, "cannot open '");
01088       lua_pushstring(L, path);
01089       lua_pushstring(L, "' for reading: ");
01090       lua_pushstring(L, strerror(errno));
01091       lua_concat(L, 4);
01092 
01093       return NULL;
01094    }
01095 
01096    if (fseek(f, 0l, SEEK_END)) {
01097       fclose(f);
01098       lua_pushliteral(L, "error determining the size of the config file");
01099       return NULL;
01100    }
01101 
01102    *size = ftell(f);
01103 
01104    if (fseek(f, 0l, SEEK_SET)) {
01105       *size = 0;
01106       fclose(f);
01107       lua_pushliteral(L, "error reading config file");
01108       return NULL;
01109    }
01110 
01111    if (!(data = ast_malloc(*size))) {
01112       *size = 0;
01113       fclose(f);
01114       lua_pushstring(L, "not enough memory");
01115       return NULL;
01116    }
01117 
01118    if (fread(data, sizeof(char), *size, f) != *size) {
01119       *size = 0;
01120       fclose(f);
01121       lua_pushliteral(L, "problem reading configuration file");
01122       return NULL;
01123    }
01124    fclose(f);
01125 
01126    lua_pushcfunction(L, &lua_error_function);
01127    error_func = lua_gettop(L);
01128 
01129    if (luaL_loadbuffer(L, data, *size, "extensions.lua")
01130          || lua_pcall(L, 0, LUA_MULTRET, error_func)
01131          || lua_sort_extensions(L)
01132          || lua_register_switches(L)
01133          || lua_register_hints(L)) {
01134       ast_free(data);
01135       data = NULL;
01136       *size = 0;
01137    }
01138 
01139    lua_remove(L, error_func);
01140    return data;
01141 }
01142 
01143 /*!
01144  * \brief Load the extensions.lua file from the internal buffer
01145  *
01146  * \param L the lua_State to use
01147  * \param chan channel to work on
01148  *
01149  * This function also sets up some constructs used by the extensions.lua file.
01150  * In the event of an error, an error string will be pushed onto the lua stack.
01151  *
01152  * \retval 0 success
01153  * \retval 1 failure
01154  */
01155 static int lua_load_extensions(lua_State *L, struct ast_channel *chan)
01156 {
01157    
01158    /* store a pointer to this channel */
01159    lua_pushlightuserdata(L, chan);
01160    lua_setfield(L, LUA_REGISTRYINDEX, "channel");
01161    
01162    luaL_openlibs(L);
01163 
01164    /* load and sort extensions */
01165    ast_mutex_lock(&config_file_lock);
01166    if (luaL_loadbuffer(L, config_file_data, config_file_size, "extensions.lua")
01167          || lua_pcall(L, 0, LUA_MULTRET, 0)
01168          || lua_sort_extensions(L)) {
01169       ast_mutex_unlock(&config_file_lock);
01170       return 1;
01171    }
01172    ast_mutex_unlock(&config_file_lock);
01173 
01174    /* now we setup special tables and functions */
01175 
01176    lua_create_app_table(L);
01177    lua_create_channel_table(L);
01178 
01179    lua_create_variable_metatable(L);
01180    lua_create_application_metatable(L);
01181 
01182    lua_create_autoservice_functions(L);
01183    lua_create_hangup_function(L);
01184 
01185    return 0;
01186 }
01187 
01188 /*!
01189  * \brief Reload the extensions file and update the internal buffers if it
01190  * loads correctly.
01191  *
01192  * \warning This function should not be called on a lua_State returned from
01193  * lua_get_state().
01194  *
01195  * \param L the lua_State to use (must be freshly allocated with
01196  * luaL_newstate(), don't use lua_get_state())
01197  */
01198 static int lua_reload_extensions(lua_State *L)
01199 {
01200    long size = 0;
01201    char *data = NULL;
01202 
01203    luaL_openlibs(L);
01204 
01205    if (!(data = lua_read_extensions_file(L, &size))) {
01206       return 1;
01207    }
01208 
01209    ast_mutex_lock(&config_file_lock);
01210 
01211    if (config_file_data)
01212       ast_free(config_file_data);
01213 
01214    config_file_data = data;
01215    config_file_size = size;
01216    
01217    /* merge our new contexts */
01218    ast_merge_contexts_and_delete(&local_contexts, local_table, registrar);
01219    /* merge_contexts_and_delete will actually, at the correct moment, 
01220       set the global dialplan pointers to your local_contexts and local_table.
01221       It then will free up the old tables itself. Just be sure not to
01222       hang onto the pointers. */
01223    local_table = NULL;
01224    local_contexts = NULL;
01225 
01226    ast_mutex_unlock(&config_file_lock);
01227    return 0;
01228 }
01229 
01230 /*!
01231  * \brief Free the internal extensions buffer.
01232  */
01233 static void lua_free_extensions()
01234 {
01235    ast_mutex_lock(&config_file_lock);
01236    config_file_size = 0;
01237    ast_free(config_file_data);
01238    ast_mutex_unlock(&config_file_lock);
01239 }
01240 
01241 /*!
01242  * \brief Get the lua_State for this channel
01243  *
01244  * If no channel is passed then a new state is allocated.  States with no
01245  * channel assocatied with them should only be used for matching extensions.
01246  * If the channel does not yet have a lua state associated with it, one will be
01247  * created.
01248  *
01249  * \note If no channel was passed then the caller is expected to free the state
01250  * using lua_close().
01251  *
01252  * \return a lua_State
01253  */
01254 static lua_State *lua_get_state(struct ast_channel *chan)
01255 {
01256    struct ast_datastore *datastore = NULL;
01257    lua_State *L;
01258 
01259    if (!chan) {
01260       L = luaL_newstate();
01261       if (!L) {
01262          ast_log(LOG_ERROR, "Error allocating lua_State, no memory\n");
01263          return NULL;
01264       }
01265 
01266       if (lua_load_extensions(L, NULL)) {
01267          const char *error = lua_tostring(L, -1);
01268          ast_log(LOG_ERROR, "Error loading extensions.lua: %s\n", error);
01269          lua_close(L);
01270          return NULL;
01271       }
01272       return L;
01273    } else {
01274       ast_channel_lock(chan);
01275       datastore = ast_channel_datastore_find(chan, &lua_datastore, NULL);
01276       ast_channel_unlock(chan);
01277 
01278       if (!datastore) {
01279          /* nothing found, allocate a new lua state */
01280          datastore = ast_datastore_alloc(&lua_datastore, NULL);
01281          if (!datastore) {
01282             ast_log(LOG_ERROR, "Error allocation channel datastore for lua_State\n");
01283             return NULL;
01284          }
01285 
01286          datastore->data = luaL_newstate();
01287          if (!datastore->data) {
01288             ast_datastore_free(datastore);
01289             ast_log(LOG_ERROR, "Error allocating lua_State, no memory\n");
01290             return NULL;
01291          }
01292 
01293          ast_channel_lock(chan);
01294          ast_channel_datastore_add(chan, datastore);
01295          ast_channel_unlock(chan);
01296 
01297          L = datastore->data;
01298 
01299          if (lua_load_extensions(L, chan)) {
01300             const char *error = lua_tostring(L, -1);
01301             ast_log(LOG_ERROR, "Error loading extensions.lua for %s: %s\n", ast_channel_name(chan), error);
01302 
01303             ast_channel_lock(chan);
01304             ast_channel_datastore_remove(chan, datastore);
01305             ast_channel_unlock(chan);
01306 
01307             ast_datastore_free(datastore);
01308             return NULL;
01309          }
01310       }
01311 
01312       return datastore->data;
01313    }
01314 }
01315 
01316 static int exists(struct ast_channel *chan, const char *context, const char *exten, int priority, const char *callerid, const char *data)
01317 {
01318    int res;
01319    lua_State *L;
01320    struct ast_module_user *u = ast_module_user_add(chan);
01321    if (!u) {
01322       ast_log(LOG_ERROR, "Error adjusting use count, probably could not allocate memory\n");
01323       return 0;
01324    }
01325 
01326    L = lua_get_state(chan);
01327    if (!L) {
01328       ast_module_user_remove(u);
01329       return 0;
01330    }
01331 
01332    res = lua_find_extension(L, context, exten, priority, &exists, 0);
01333 
01334    if (!chan) lua_close(L);
01335    ast_module_user_remove(u);
01336    return res;
01337 }
01338 
01339 static int canmatch(struct ast_channel *chan, const char *context, const char *exten, int priority, const char *callerid, const char *data)
01340 {
01341    int res;
01342    lua_State *L;
01343    struct ast_module_user *u = ast_module_user_add(chan);
01344    if (!u) {
01345       ast_log(LOG_ERROR, "Error adjusting use count, probably could not allocate memory\n");
01346       return 0;
01347    }
01348 
01349    L = lua_get_state(chan);
01350    if (!L) {
01351       ast_module_user_remove(u);
01352       return 0;
01353    }
01354 
01355    res = lua_find_extension(L, context, exten, priority, &canmatch, 0);
01356 
01357    if (!chan) lua_close(L);
01358    ast_module_user_remove(u);
01359    return res;
01360 }
01361 
01362 static int matchmore(struct ast_channel *chan, const char *context, const char *exten, int priority, const char *callerid, const char *data)
01363 {
01364    int res;
01365    lua_State *L;
01366    struct ast_module_user *u = ast_module_user_add(chan);
01367    if (!u) {
01368       ast_log(LOG_ERROR, "Error adjusting use count, probably could not allocate memory\n");
01369       return 0;
01370    }
01371 
01372    L = lua_get_state(chan);
01373    if (!L) {
01374       ast_module_user_remove(u);
01375       return 0;
01376    }
01377    
01378    res = lua_find_extension(L, context, exten, priority, &matchmore, 0);
01379 
01380    if (!chan) lua_close(L);
01381    ast_module_user_remove(u);
01382    return res;
01383 }
01384 
01385 
01386 static int exec(struct ast_channel *chan, const char *context, const char *exten, int priority, const char *callerid, const char *data)
01387 {
01388    int res, error_func;
01389    lua_State *L;
01390    struct ast_module_user *u = ast_module_user_add(chan);
01391    if (!u) {
01392       ast_log(LOG_ERROR, "Error adjusting use count, probably could not allocate memory\n");
01393       return -1;
01394    }
01395    
01396    L = lua_get_state(chan);
01397    if (!L) {
01398       ast_module_user_remove(u);
01399       return -1;
01400    }
01401 
01402    lua_pushcfunction(L, &lua_error_function);
01403    error_func = lua_gettop(L);
01404 
01405    /* push the extension function onto the stack */
01406    if (!lua_find_extension(L, context, exten, priority, &exists, 1)) {
01407       lua_pop(L, 1); /* pop the debug function */
01408       ast_log(LOG_ERROR, "Could not find extension %s in context %s\n", exten, context);
01409       if (!chan) lua_close(L);
01410       ast_module_user_remove(u);
01411       return -1;
01412    }
01413 
01414    lua_getfield(L, LUA_REGISTRYINDEX, "autoservice");
01415    if (lua_toboolean(L, -1)) {
01416       ast_autoservice_start(chan);
01417    }
01418    lua_pop(L, 1);
01419 
01420    lua_update_registry(L, context, exten, priority);
01421    
01422    lua_pushstring(L, context);
01423    lua_pushstring(L, exten);
01424    
01425    res = lua_pcall(L, 2, 0, error_func);
01426    if (res) {
01427       if (res == LUA_ERRRUN) {
01428          res = -1;
01429          if (lua_isnumber(L, -1)) {
01430             res = lua_tointeger(L, -1);
01431 
01432             if (res == LUA_GOTO_DETECTED) {
01433                res = 0;
01434             }
01435          } else if (lua_isstring(L, -1)) {
01436             const char *error = lua_tostring(L, -1);
01437             ast_log(LOG_ERROR, "Error executing lua extension: %s\n", error);
01438          }
01439       } else if (res == LUA_ERRERR) {
01440          res = -1;
01441          ast_log(LOG_ERROR, "Error in the lua error handler (this is probably a bug in pbx_lua)\n");
01442       } else if (res == LUA_ERRMEM) {
01443          res = -1;
01444          ast_log(LOG_ERROR, "Memory allocation error\n");
01445       }
01446       lua_pop(L, 1);
01447    }
01448    lua_remove(L, error_func);
01449 
01450    lua_getfield(L, LUA_REGISTRYINDEX, "autoservice");
01451    if (lua_toboolean(L, -1)) {
01452       ast_autoservice_stop(chan);
01453    }
01454    lua_pop(L, 1);
01455 
01456    if (!chan) lua_close(L);
01457    ast_module_user_remove(u);
01458    return res;
01459 }
01460 
01461 /*!
01462  * \brief Locate an extensions and optionally push the matching function on the
01463  * stack
01464  *
01465  * \param L the lua_State to use
01466  * \param context the context to look in
01467  * \param exten the extension to look up
01468  * \param priority the priority to check, '1' is the only valid priority
01469  * \param func the calling func, used to adjust matching behavior between,
01470  * match, canmatch, and matchmore
01471  * \param push_func whether or not to push the lua function for the given
01472  * extension onto the stack
01473  */
01474 static int lua_find_extension(lua_State *L, const char *context, const char *exten, int priority, ast_switch_f *func, int push_func)
01475 {
01476    int context_table, context_order_table, i;
01477 
01478    ast_debug(2, "Looking up %s@%s:%i\n", exten, context, priority);
01479    if (priority != 1)
01480       return 0;
01481 
01482    /* load the 'extensions' table */
01483    lua_getglobal(L, "extensions");
01484    if (lua_isnil(L, -1)) {
01485       ast_log(LOG_ERROR, "Unable to find 'extensions' table in extensions.lua\n");
01486       lua_pop(L, 1);
01487       return 0;
01488    }
01489 
01490    /* load the given context */
01491    lua_getfield(L, -1, context);
01492    if (lua_isnil(L, -1)) {
01493       lua_pop(L, 2);
01494       return 0;
01495    }
01496 
01497    /* remove the extensions table */
01498    lua_remove(L, -2);
01499 
01500    context_table = lua_gettop(L);
01501 
01502    /* load the extensions order table for this context */
01503    lua_getfield(L, LUA_REGISTRYINDEX, "extensions_order");
01504    lua_getfield(L, -1, context);
01505 
01506    lua_remove(L, -2);  /* remove the extensions order table */
01507 
01508    context_order_table = lua_gettop(L);
01509    
01510    /* step through the extensions looking for a match */
01511    for (i = 1; i < lua_objlen(L, context_order_table) + 1; i++) {
01512       int e_index_copy, match = 0;
01513       const char *e;
01514 
01515       lua_pushinteger(L, i);
01516       lua_gettable(L, context_order_table);
01517       lua_gettop(L);
01518 
01519       /* copy the key at the top of the stack for use later */
01520       lua_pushvalue(L, -1);
01521       e_index_copy = lua_gettop(L);
01522 
01523       if (!(e = lua_tostring(L, e_index_copy))) {
01524          lua_pop(L, 2);
01525          continue;
01526       }
01527 
01528       /* make sure this is not the 'include' extension */
01529       if (!strcasecmp(e, "include")) {
01530          lua_pop(L, 2);
01531          continue;
01532       }
01533 
01534       if (func == &matchmore)
01535          match = ast_extension_close(e, exten, E_MATCHMORE);
01536       else if (func == &canmatch)
01537          match = ast_extension_close(e, exten, E_CANMATCH);
01538       else
01539          match = ast_extension_match(e, exten);
01540 
01541       /* the extension matching functions return 0 on fail, 1 on
01542        * match, 2 on earlymatch */
01543 
01544       if (!match) {
01545          /* pop the copy and the extension */
01546          lua_pop(L, 2);
01547          continue;   /* keep trying */
01548       }
01549 
01550       if (func == &matchmore && match == 2) {
01551          /* We match an extension ending in '!'. The decision in
01552           * this case is final and counts as no match. */
01553          lua_pop(L, 4);
01554          return 0;
01555       }
01556 
01557       /* remove the context table, the context order table, the
01558        * extension, and the extension copy (or replace the extension
01559        * with the corresponding function) */
01560       if (push_func) {
01561          lua_pop(L, 1);  /* pop the copy */
01562          lua_gettable(L, context_table);
01563          lua_insert(L, -3);
01564          lua_pop(L, 2);
01565       } else {
01566          lua_pop(L, 4);
01567       }
01568 
01569       return 1;
01570    }
01571 
01572    /* load the includes for this context */
01573    lua_getfield(L, context_table, "include");
01574    if (lua_isnil(L, -1)) {
01575       lua_pop(L, 3);
01576       return 0;
01577    }
01578 
01579    /* remove the context and the order table*/
01580    lua_remove(L, context_order_table);
01581    lua_remove(L, context_table);
01582 
01583    /* Now try any includes we have in this context */
01584    for (lua_pushnil(L); lua_next(L, -2); lua_pop(L, 1)) {
01585       const char *c = lua_tostring(L, -1);
01586       if (!c)
01587          continue;
01588 
01589       if (lua_find_extension(L, c, exten, priority, func, push_func)) {
01590          /* remove the value, the key, and the includes table
01591           * from the stack.  Leave the function behind if
01592           * necessary */
01593 
01594          if (push_func)
01595             lua_insert(L, -4);
01596 
01597          lua_pop(L, 3);
01598          return 1;
01599       }
01600    }
01601 
01602    /* pop the includes table */
01603    lua_pop(L, 1);
01604    return 0;
01605 }
01606 
01607 static struct ast_switch lua_switch = {
01608         .name     = "Lua",
01609         .description = "Lua PBX Switch",
01610         .exists      = exists,
01611         .canmatch = canmatch,
01612         .exec     = exec,
01613         .matchmore   = matchmore,
01614 };
01615 
01616 
01617 static int load_or_reload_lua_stuff(void)
01618 {
01619    int res = AST_MODULE_LOAD_SUCCESS;
01620 
01621    lua_State *L = luaL_newstate();
01622    if (!L) {
01623       ast_log(LOG_ERROR, "Error allocating lua_State, no memory\n");
01624       return AST_MODULE_LOAD_DECLINE;
01625    }
01626 
01627    if (lua_reload_extensions(L)) {
01628       const char *error = lua_tostring(L, -1);
01629       ast_log(LOG_ERROR, "Error loading extensions.lua: %s\n", error);
01630       res = AST_MODULE_LOAD_DECLINE;
01631    }
01632 
01633    lua_close(L);
01634    return res;
01635 }
01636 
01637 static int unload_module(void)
01638 {
01639    ast_context_destroy(NULL, registrar);
01640    ast_unregister_switch(&lua_switch);
01641    lua_free_extensions();
01642    return 0;
01643 }
01644 
01645 static int reload(void)
01646 {
01647    return load_or_reload_lua_stuff();
01648 }
01649 
01650 static int load_module(void)
01651 {
01652    int res;
01653 
01654    if ((res = load_or_reload_lua_stuff()))
01655       return res;
01656 
01657    if (ast_register_switch(&lua_switch)) {
01658       ast_log(LOG_ERROR, "Unable to register LUA PBX switch\n");
01659       return AST_MODULE_LOAD_DECLINE;
01660    }
01661 
01662    return AST_MODULE_LOAD_SUCCESS;
01663 }
01664 
01665 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS, "Lua PBX Switch",
01666       .load = load_module,
01667       .unload = unload_module,
01668       .reload = reload,
01669           );
01670 

Generated on Sun May 20 06:33:57 2012 for Asterisk - The Open Source Telephony Project by  doxygen 1.5.6