| File: | src/mod/languages/mod_lua/mod_lua.cpp |
| Location: | line 130, column 3 |
| Description: | Value stored to 'error' is never read |
| 1 | /* |
| 2 | * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application |
| 3 | * Copyright (C) 2005-2014, Anthony Minessale II <anthm@freeswitch.org> |
| 4 | * |
| 5 | * Version: MPL 1.1 |
| 6 | * |
| 7 | * The contents of this file are subject to the Mozilla Public License Version |
| 8 | * 1.1 (the "License"); you may not use this file except in compliance with |
| 9 | * the License. You may obtain a copy of the License at |
| 10 | * http://www.mozilla.org/MPL/ |
| 11 | * |
| 12 | * Software distributed under the License is distributed on an "AS IS" basis, |
| 13 | * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License |
| 14 | * for the specific language governing rights and limitations under the |
| 15 | * License. |
| 16 | * |
| 17 | * The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application |
| 18 | * |
| 19 | * The Initial Developer of the Original Code is |
| 20 | * Anthony Minessale II <anthm@freeswitch.org> |
| 21 | * Portions created by the Initial Developer are Copyright (C) |
| 22 | * the Initial Developer. All Rights Reserved. |
| 23 | * |
| 24 | * Contributor(s): |
| 25 | * |
| 26 | * Anthony Minessale II <anthm@freeswitch.org> |
| 27 | * |
| 28 | * mod_lua.c -- Lua |
| 29 | * |
| 30 | */ |
| 31 | |
| 32 | |
| 33 | |
| 34 | #include <switch.h> |
| 35 | #include <switch_event.h> |
| 36 | SWITCH_BEGIN_EXTERN_Cextern "C" { |
| 37 | #include "lua.h" |
| 38 | #include <lauxlib.h> |
| 39 | #include <lualib.h> |
| 40 | #include "mod_lua_extra.h" |
| 41 | SWITCH_MODULE_LOAD_FUNCTION(mod_lua_load)switch_status_t mod_lua_load (switch_loadable_module_interface_t **module_interface, switch_memory_pool_t *pool); |
| 42 | SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_lua_shutdown)switch_status_t mod_lua_shutdown (void); |
| 43 | |
| 44 | SWITCH_MODULE_DEFINITION_EX(mod_lua, mod_lua_load, mod_lua_shutdown, NULL, SMODF_GLOBAL_SYMBOLS)static const char modname[] = "mod_lua" ; __attribute__((visibility ("default"))) switch_loadable_module_function_table_t mod_lua_module_interface = { 5, mod_lua_load, mod_lua_shutdown, __null, SMODF_GLOBAL_SYMBOLS }; |
| 45 | static struct { |
| 46 | switch_memory_pool_t *pool; |
| 47 | char *xml_handler; |
| 48 | } globals; |
| 49 | |
| 50 | int luaopen_freeswitch(lua_State * L); |
| 51 | int lua_thread(const char *text); |
| 52 | |
| 53 | static int panic(lua_State * L) |
| 54 | { |
| 55 | switch_log_printf(SWITCH_CHANNEL_LOGSWITCH_CHANNEL_ID_LOG, "mod_lua.cpp", (const char *)__func__, 55, __null, SWITCH_LOG_CRIT, "unprotected error in call to Lua API (%s)\n", lua_tostring(L, -1)lua_tolstring(L, (-1), __null)); |
| 56 | |
| 57 | return 0; |
| 58 | } |
| 59 | |
| 60 | static void lua_uninit(lua_State * L) |
| 61 | { |
| 62 | lua_gc(L, LUA_GCCOLLECT2, 0); |
| 63 | lua_close(L); |
| 64 | } |
| 65 | |
| 66 | static int traceback(lua_State * L) |
| 67 | { |
| 68 | lua_getglobal(L, "debug"); |
| 69 | if (!lua_istable(L, -1)(lua_type(L, (-1)) == 5)) { |
| 70 | lua_pop(L, 1)lua_settop(L, -(1)-1); |
| 71 | return 1; |
| 72 | } |
| 73 | lua_getfield(L, -1, "traceback"); |
| 74 | if (!lua_isfunction(L, -1)(lua_type(L, (-1)) == 6)) { |
| 75 | lua_pop(L, 2)lua_settop(L, -(2)-1); |
| 76 | return 1; |
| 77 | } |
| 78 | lua_pushvalue(L, 1); /* pass error message */ |
| 79 | lua_pushinteger(L, 2); /* skip this function and traceback */ |
| 80 | lua_call(L, 2, 1)lua_callk(L, (2), (1), 0, __null); /* call debug.traceback */ |
| 81 | return 1; |
| 82 | } |
| 83 | |
| 84 | int docall(lua_State * L, int narg, int nresults, int perror, int fatal) |
| 85 | { |
| 86 | int status; |
| 87 | int base = lua_gettop(L) - narg; /* function index */ |
| 88 | |
| 89 | lua_pushcfunction(L, traceback)lua_pushcclosure(L, (traceback), 0); /* push traceback function */ |
| 90 | lua_insert(L, base); /* put it under chunk and args */ |
| 91 | |
| 92 | status = lua_pcall(L, narg, nresults, base)lua_pcallk(L, (narg), (nresults), (base), 0, __null); |
| 93 | |
| 94 | lua_remove(L, base); /* remove traceback function */ |
| 95 | /* force a complete garbage collection in case of errors */ |
| 96 | if (status != 0) { |
| 97 | lua_gc(L, LUA_GCCOLLECT2, 0); |
| 98 | } |
| 99 | |
| 100 | if (status && perror) { |
| 101 | const char *err = lua_tostring(L, -1)lua_tolstring(L, (-1), __null); |
| 102 | if (!zstr(err)_zstr(err)) { |
| 103 | switch_log_printf(SWITCH_CHANNEL_LOGSWITCH_CHANNEL_ID_LOG, "mod_lua.cpp", (const char *)__func__, 103, __null, SWITCH_LOG_ERROR, "%s\n", err); |
| 104 | } |
| 105 | |
| 106 | // pass error up to top |
| 107 | if (fatal) { |
| 108 | lua_error(L); |
| 109 | } else { |
| 110 | lua_pop(L, 1)lua_settop(L, -(1)-1); /* pop error message from the stack */ |
| 111 | } |
| 112 | } |
| 113 | |
| 114 | return status; |
| 115 | } |
| 116 | |
| 117 | |
| 118 | static lua_State *lua_init(void) |
| 119 | { |
| 120 | lua_State *L = luaL_newstate(); |
| 121 | int error = 0; |
| 122 | |
| 123 | if (L) { |
| 124 | const char *buff = "os.exit = function() freeswitch.consoleLog(\"err\", \"Surely you jest! exiting is a bad plan....\\n\") end"; |
| 125 | lua_gc(L, LUA_GCSTOP0, 0); |
| 126 | luaL_openlibs(L); |
| 127 | luaopen_freeswitch(L); |
| 128 | lua_gc(L, LUA_GCRESTART1, 0); |
| 129 | lua_atpanic(L, panic); |
| 130 | error = luaL_loadbuffer(L, buff, strlen(buff), "line")luaL_loadbufferx(L,buff,strlen(buff),"line",__null) || docall(L, 0, 0, 0, 1); |
Value stored to 'error' is never read | |
| 131 | } |
| 132 | return L; |
| 133 | } |
| 134 | |
| 135 | |
| 136 | static int lua_parse_and_execute(lua_State * L, char *input_code) |
| 137 | { |
| 138 | int error = 0; |
| 139 | |
| 140 | if (zstr(input_code)_zstr(input_code)) { |
| 141 | switch_log_printf(SWITCH_CHANNEL_LOGSWITCH_CHANNEL_ID_LOG, "mod_lua.cpp", (const char *)__func__, 141, __null, SWITCH_LOG_ERROR, "No code to execute!\n"); |
| 142 | return 1; |
| 143 | } |
| 144 | |
| 145 | while(input_code && (*input_code == ' ' || *input_code == '\n' || *input_code == '\r')) input_code++; |
| 146 | |
| 147 | if (*input_code == '~') { |
| 148 | char *buff = input_code + 1; |
| 149 | error = luaL_loadbuffer(L, buff, strlen(buff), "line")luaL_loadbufferx(L,buff,strlen(buff),"line",__null) || docall(L, 0, 0, 0, 1); //lua_pcall(L, 0, 0, 0); |
| 150 | } else if (!strncasecmp(input_code, "#!/lua", 6)) { |
| 151 | char *buff = input_code + 6; |
| 152 | error = luaL_loadbuffer(L, buff, strlen(buff), "line")luaL_loadbufferx(L,buff,strlen(buff),"line",__null) || docall(L, 0, 0, 0, 1); //lua_pcall(L, 0, 0, 0); |
| 153 | } else { |
| 154 | char *args = strchr(input_code, ' '); |
| 155 | if (args) { |
| 156 | char *code = NULL__null; |
| 157 | int x, argc; |
| 158 | char *argv[128] = { 0 }; |
| 159 | *args++ = '\0'; |
| 160 | |
| 161 | if ((argc = switch_separate_string(args, ' ', argv, (sizeof(argv) / sizeof(argv[0]))))) { |
| 162 | switch_stream_handle_t stream = { 0 }; |
| 163 | SWITCH_STANDARD_STREAM(stream)memset(&stream, 0, sizeof(stream)); stream.data = malloc( 1024); ((stream.data) ? static_cast<void> (0) : __assert_fail ("stream.data", "mod_lua.cpp", 163, __PRETTY_FUNCTION__)); memset (stream.data, 0, 1024); stream.end = stream.data; stream.data_size = 1024; stream.write_function = switch_console_stream_write; stream.raw_write_function = switch_console_stream_raw_write; stream.alloc_len = 1024; stream.alloc_chunk = 1024; |
| 164 | |
| 165 | stream.write_function(&stream, " argv = {[0]='%y', ", input_code); |
| 166 | for (x = 0; x < argc; x++) { |
| 167 | stream.write_function(&stream, "'%y'%s", argv[x], x == argc - 1 ? "" : ", "); |
| 168 | } |
| 169 | stream.write_function(&stream, " };"); |
| 170 | code = (char *) stream.data; |
| 171 | } else { |
| 172 | code = switch_mprintf("argv = {[0]='%s'};", input_code); |
| 173 | } |
| 174 | |
| 175 | if (code) { |
| 176 | error = luaL_loadbuffer(L, code, strlen(code), "line")luaL_loadbufferx(L,code,strlen(code),"line",__null) || docall(L, 0, 0, 0, 1); |
| 177 | switch_safe_free(code)if (code) {free(code);code=__null;}; |
| 178 | } |
| 179 | } else { |
| 180 | // Force empty argv table |
| 181 | char *code = NULL__null; |
| 182 | code = switch_mprintf("argv = {[0]='%s'};", input_code); |
| 183 | error = luaL_loadbuffer(L, code, strlen(code), "line")luaL_loadbufferx(L,code,strlen(code),"line",__null) || docall(L, 0, 0, 0, 1); |
| 184 | switch_safe_free(code)if (code) {free(code);code=__null;}; |
| 185 | } |
| 186 | |
| 187 | if (!error) { |
| 188 | char *file = input_code, *fdup = NULL__null; |
| 189 | |
| 190 | if (!switch_is_file_path(file)) { |
| 191 | fdup = switch_mprintf("%s/%s", SWITCH_GLOBAL_dirs.script_dir, file); |
| 192 | switch_assert(fdup)((fdup) ? static_cast<void> (0) : __assert_fail ("fdup" , "mod_lua.cpp", 192, __PRETTY_FUNCTION__)); |
| 193 | file = fdup; |
| 194 | } |
| 195 | error = luaL_loadfile(L, file)luaL_loadfilex(L,file,__null) || docall(L, 0, 0, 0, 1); |
| 196 | switch_safe_free(fdup)if (fdup) {free(fdup);fdup=__null;}; |
| 197 | } |
| 198 | } |
| 199 | |
| 200 | if (error) { |
| 201 | const char *err = lua_tostring(L, -1)lua_tolstring(L, (-1), __null); |
| 202 | if (!zstr(err)_zstr(err)) { |
| 203 | switch_log_printf(SWITCH_CHANNEL_LOGSWITCH_CHANNEL_ID_LOG, "mod_lua.cpp", (const char *)__func__, 203, __null, SWITCH_LOG_ERROR, "%s\n", err); |
| 204 | } |
| 205 | lua_pop(L, 1)lua_settop(L, -(1)-1); /* pop error message from the stack */ |
| 206 | } |
| 207 | |
| 208 | return error; |
| 209 | } |
| 210 | |
| 211 | struct lua_thread_helper { |
| 212 | switch_memory_pool_t *pool; |
| 213 | char *input_code; |
| 214 | }; |
| 215 | |
| 216 | static void *SWITCH_THREAD_FUNC lua_thread_run(switch_thread_t *thread, void *obj) |
| 217 | { |
| 218 | struct lua_thread_helper *lth = (struct lua_thread_helper *) obj; |
| 219 | switch_memory_pool_t *pool = lth->pool; |
| 220 | lua_State *L = lua_init(); /* opens Lua */ |
| 221 | |
| 222 | lua_parse_and_execute(L, lth->input_code); |
| 223 | |
| 224 | lth = NULL__null; |
| 225 | |
| 226 | switch_core_destroy_memory_pool(&pool)switch_core_perform_destroy_memory_pool(&pool, "mod_lua.cpp" , (const char *)__func__, 226); |
| 227 | |
| 228 | lua_uninit(L); |
| 229 | |
| 230 | return NULL__null; |
| 231 | } |
| 232 | |
| 233 | |
| 234 | static switch_xml_t lua_fetch(const char *section, |
| 235 | const char *tag_name, const char *key_name, const char *key_value, switch_event_t *params, void *user_data) |
| 236 | { |
| 237 | |
| 238 | switch_xml_t xml = NULL__null; |
| 239 | char *mycmd = NULL__null; |
| 240 | |
| 241 | if (!zstr(globals.xml_handler)_zstr(globals.xml_handler)) { |
| 242 | lua_State *L = lua_init(); |
| 243 | const char *str; |
| 244 | int error; |
| 245 | |
| 246 | mycmd = strdup(globals.xml_handler); |
| 247 | switch_assert(mycmd)((mycmd) ? static_cast<void> (0) : __assert_fail ("mycmd" , "mod_lua.cpp", 247, __PRETTY_FUNCTION__)); |
| 248 | |
| 249 | lua_newtable(L)lua_createtable(L, 0, 0); |
| 250 | |
| 251 | lua_pushstring(L, "section"); |
| 252 | lua_pushstring(L, switch_str_nil(section)(section ? section : "")); |
| 253 | lua_rawset(L, -3); |
| 254 | lua_pushstring(L, "tag_name"); |
| 255 | lua_pushstring(L, switch_str_nil(tag_name)(tag_name ? tag_name : "")); |
| 256 | lua_rawset(L, -3); |
| 257 | lua_pushstring(L, "key_name"); |
| 258 | lua_pushstring(L, switch_str_nil(key_name)(key_name ? key_name : "")); |
| 259 | lua_rawset(L, -3); |
| 260 | lua_pushstring(L, "key_value"); |
| 261 | lua_pushstring(L, switch_str_nil(key_value)(key_value ? key_value : "")); |
| 262 | lua_rawset(L, -3); |
| 263 | lua_setglobal(L, "XML_REQUEST"); |
| 264 | |
| 265 | if (params) { |
| 266 | mod_lua_conjure_event(L, params, "params", 1); |
| 267 | } |
| 268 | |
| 269 | if((error = lua_parse_and_execute(L, mycmd))){ |
| 270 | switch_log_printf(SWITCH_CHANNEL_LOGSWITCH_CHANNEL_ID_LOG, "mod_lua.cpp", (const char *)__func__, 270, __null, SWITCH_LOG_ERROR, "LUA script parse/execute error!\n"); |
| 271 | goto end; |
| 272 | } |
| 273 | |
| 274 | lua_getglobal(L, "XML_STRING"); |
| 275 | str = lua_tostring(L, 1)lua_tolstring(L, (1), __null); |
| 276 | |
| 277 | if (str) { |
| 278 | if (zstr(str)_zstr(str)) { |
| 279 | switch_log_printf(SWITCH_CHANNEL_LOGSWITCH_CHANNEL_ID_LOG, "mod_lua.cpp", (const char *)__func__, 279, __null, SWITCH_LOG_ERROR, "No Result\n"); |
| 280 | } else if (!(xml = switch_xml_parse_str_dynamic((char *)str, SWITCH_TRUE))) { |
| 281 | /* const char -> char conversion was OK because switch_xml_parse_str_dynamic makes a duplicate of str |
| 282 | and saves this duplcate as root->m which is freed when switch_xml_free is issued |
| 283 | */ |
| 284 | switch_log_printf(SWITCH_CHANNEL_LOGSWITCH_CHANNEL_ID_LOG, "mod_lua.cpp", (const char *)__func__, 284, __null, SWITCH_LOG_ERROR, "Error Parsing XML Result!\n"); |
| 285 | } |
| 286 | } |
| 287 | |
| 288 | lua_uninit(L); |
| 289 | |
| 290 | } |
| 291 | |
| 292 | end: |
| 293 | |
| 294 | switch_safe_free(mycmd)if (mycmd) {free(mycmd);mycmd=__null;}; |
| 295 | |
| 296 | return xml; |
| 297 | } |
| 298 | |
| 299 | |
| 300 | static void lua_event_handler(switch_event_t *event); |
| 301 | |
| 302 | static switch_status_t do_config(void) |
| 303 | { |
| 304 | const char *cf = "lua.conf"; |
| 305 | switch_xml_t cfg, xml, settings, param, hook; |
| 306 | switch_stream_handle_t path_stream = {0}; |
| 307 | switch_stream_handle_t cpath_stream = {0}; |
| 308 | |
| 309 | if (!(xml = switch_xml_open_cfg(cf, &cfg, NULL__null))) { |
| 310 | switch_log_printf(SWITCH_CHANNEL_LOGSWITCH_CHANNEL_ID_LOG, "mod_lua.cpp", (const char *)__func__, 310, __null, SWITCH_LOG_ERROR, "open of %s failed\n", cf); |
| 311 | return SWITCH_STATUS_TERM; |
| 312 | } |
| 313 | |
| 314 | SWITCH_STANDARD_STREAM(path_stream)memset(&path_stream, 0, sizeof(path_stream)); path_stream .data = malloc(1024); ((path_stream.data) ? static_cast<void > (0) : __assert_fail ("path_stream.data", "mod_lua.cpp", 314 , __PRETTY_FUNCTION__)); memset(path_stream.data, 0, 1024); path_stream .end = path_stream.data; path_stream.data_size = 1024; path_stream .write_function = switch_console_stream_write; path_stream.raw_write_function = switch_console_stream_raw_write; path_stream.alloc_len = 1024 ; path_stream.alloc_chunk = 1024; |
| 315 | SWITCH_STANDARD_STREAM(cpath_stream)memset(&cpath_stream, 0, sizeof(cpath_stream)); cpath_stream .data = malloc(1024); ((cpath_stream.data) ? static_cast<void > (0) : __assert_fail ("cpath_stream.data", "mod_lua.cpp", 315, __PRETTY_FUNCTION__)); memset(cpath_stream.data, 0, 1024 ); cpath_stream.end = cpath_stream.data; cpath_stream.data_size = 1024; cpath_stream.write_function = switch_console_stream_write ; cpath_stream.raw_write_function = switch_console_stream_raw_write ; cpath_stream.alloc_len = 1024; cpath_stream.alloc_chunk = 1024; |
| 316 | if ((settings = switch_xml_child(cfg, "settings"))) { |
| 317 | for (param = switch_xml_child(settings, "param"); param; param = param->next) { |
| 318 | char *var = (char *) switch_xml_attr_soft(param, "name"); |
| 319 | char *val = (char *) switch_xml_attr_soft(param, "value"); |
| 320 | |
| 321 | if (!strcmp(var, "xml-handler-script")) { |
| 322 | globals.xml_handler = switch_core_strdup(globals.pool, val)switch_core_perform_strdup(globals.pool, val, "mod_lua.cpp", ( const char *)__func__, 322); |
| 323 | } else if (!strcmp(var, "xml-handler-bindings")) { |
| 324 | if (!zstr(globals.xml_handler)_zstr(globals.xml_handler)) { |
| 325 | switch_log_printf(SWITCH_CHANNEL_LOGSWITCH_CHANNEL_ID_LOG, "mod_lua.cpp", (const char *)__func__, 325, __null, SWITCH_LOG_INFO, "binding '%s' to '%s'\n", globals.xml_handler, val); |
| 326 | switch_xml_bind_search_function(lua_fetch, switch_xml_parse_section_string(val), NULL)switch_xml_bind_search_function_ret(lua_fetch, switch_xml_parse_section_string (val), __null, __null); |
| 327 | } |
| 328 | } else if (!strcmp(var, "module-directory") && !zstr(val)_zstr(val)) { |
| 329 | switch_log_printf(SWITCH_CHANNEL_LOGSWITCH_CHANNEL_ID_LOG, "mod_lua.cpp", (const char *)__func__, 329, __null, SWITCH_LOG_INFO, "lua: appending module directory: '%s'\n", val); |
| 330 | if (cpath_stream.data_len) { |
| 331 | cpath_stream.write_function(&cpath_stream, ";"); |
| 332 | } |
| 333 | cpath_stream.write_function(&cpath_stream, "%s", val); |
| 334 | } else if (!strcmp(var, "script-directory") && !zstr(val)_zstr(val)) { |
| 335 | switch_log_printf(SWITCH_CHANNEL_LOGSWITCH_CHANNEL_ID_LOG, "mod_lua.cpp", (const char *)__func__, 335, __null, SWITCH_LOG_INFO, "lua: appending script directory: '%s'\n", val); |
| 336 | if (path_stream.data_len) { |
| 337 | path_stream.write_function(&path_stream, ";"); |
| 338 | } |
| 339 | path_stream.write_function(&path_stream, "%s", val); |
| 340 | } |
| 341 | } |
| 342 | |
| 343 | for (hook = switch_xml_child(settings, "hook"); hook; hook = hook->next) { |
| 344 | char *event = (char *) switch_xml_attr_soft(hook, "event"); |
| 345 | char *subclass = (char *) switch_xml_attr_soft(hook, "subclass"); |
| 346 | //char *script = strdup( (char *) switch_xml_attr_soft(hook, "script")); |
| 347 | char *script = (char *) switch_xml_attr_soft(hook, "script"); |
| 348 | switch_event_types_t evtype; |
| 349 | |
| 350 | if (!zstr(script)_zstr(script)) { |
| 351 | script = switch_core_strdup(globals.pool, script)switch_core_perform_strdup(globals.pool, script, "mod_lua.cpp" , (const char *)__func__, 351); |
| 352 | } |
| 353 | |
| 354 | switch_log_printf(SWITCH_CHANNEL_LOGSWITCH_CHANNEL_ID_LOG, "mod_lua.cpp", (const char *)__func__, 354, __null, SWITCH_LOG_INFO, "hook params: '%s' | '%s' | '%s'\n", event, subclass, script); |
| 355 | |
| 356 | if (switch_name_event(event,&evtype) == SWITCH_STATUS_SUCCESS) { |
| 357 | if (!zstr(script)_zstr(script)) { |
| 358 | if (switch_event_bind(modname, evtype, !zstr(subclass)_zstr(subclass) ? subclass : SWITCH_EVENT_SUBCLASS_ANY__null, |
| 359 | lua_event_handler, script) == SWITCH_STATUS_SUCCESS) { |
| 360 | switch_log_printf(SWITCH_CHANNEL_LOGSWITCH_CHANNEL_ID_LOG, "mod_lua.cpp", (const char *)__func__, 360, __null, SWITCH_LOG_INFO, "event handler for '%s' set to '%s'\n", switch_event_name(evtype), script); |
| 361 | } else { |
| 362 | switch_log_printf(SWITCH_CHANNEL_LOGSWITCH_CHANNEL_ID_LOG, "mod_lua.cpp", (const char *)__func__, 362, __null, SWITCH_LOG_ERROR, "cannot set event handler: unsuccessful bind\n"); |
| 363 | } |
| 364 | } else { |
| 365 | switch_log_printf(SWITCH_CHANNEL_LOGSWITCH_CHANNEL_ID_LOG, "mod_lua.cpp", (const char *)__func__, 365, __null, SWITCH_LOG_ERROR, "cannot set event handler: no script name for event type '%s'\n", event); |
| 366 | } |
| 367 | } else { |
| 368 | switch_log_printf(SWITCH_CHANNEL_LOGSWITCH_CHANNEL_ID_LOG, "mod_lua.cpp", (const char *)__func__, 368, __null, SWITCH_LOG_ERROR, "cannot set event handler: unknown event type '%s'\n", event); |
| 369 | } |
| 370 | } |
| 371 | } |
| 372 | |
| 373 | if (cpath_stream.data_len) { |
| 374 | char *lua_cpath = NULL__null; |
| 375 | if ((lua_cpath = getenv("LUA_CPATH"))) { |
| 376 | switch_log_printf(SWITCH_CHANNEL_LOGSWITCH_CHANNEL_ID_LOG, "mod_lua.cpp", (const char *)__func__, 376, __null, SWITCH_LOG_INFO, "lua: appending LUA_CPATH: '%s'\n", lua_cpath); |
| 377 | cpath_stream.write_function(&cpath_stream, ";%s", lua_cpath); |
| 378 | } |
| 379 | #ifdef WIN32 |
| 380 | if (_putenv_s("LUA_CPATH", (char *)cpath_stream.data) != 0) { |
| 381 | #else |
| 382 | if (setenv("LUA_CPATH", (char *)cpath_stream.data, 1) == ENOMEM12) { |
| 383 | #endif |
| 384 | switch_log_printf(SWITCH_CHANNEL_LOGSWITCH_CHANNEL_ID_LOG, "mod_lua.cpp", (const char *)__func__, 384, __null, SWITCH_LOG_INFO, "lua: LUA_CPATH unable to be set, out of memory: '%s'\n", (char *)cpath_stream.data); |
| 385 | } else { |
| 386 | switch_log_printf(SWITCH_CHANNEL_LOGSWITCH_CHANNEL_ID_LOG, "mod_lua.cpp", (const char *)__func__, 386, __null, SWITCH_LOG_INFO, "lua: LUA_CPATH set to: '%s'\n", (char *)cpath_stream.data); |
| 387 | } |
| 388 | } |
| 389 | switch_safe_free(cpath_stream.data)if (cpath_stream.data) {free(cpath_stream.data);cpath_stream. data=__null;}; |
| 390 | |
| 391 | if (path_stream.data_len) { |
| 392 | char *lua_path = NULL__null; |
| 393 | if ((lua_path = getenv("LUA_PATH"))) { |
| 394 | switch_log_printf(SWITCH_CHANNEL_LOGSWITCH_CHANNEL_ID_LOG, "mod_lua.cpp", (const char *)__func__, 394, __null, SWITCH_LOG_INFO, "lua: appending LUA_PATH: '%s'\n", lua_path); |
| 395 | path_stream.write_function(&path_stream, ";%s", lua_path); |
| 396 | } |
| 397 | #ifdef WIN32 |
| 398 | if (_putenv_s("LUA_PATH", (char *)path_stream.data) != 0) { |
| 399 | #else |
| 400 | if (setenv("LUA_PATH", (char *)path_stream.data, 1) == ENOMEM12) { |
| 401 | #endif |
| 402 | switch_log_printf(SWITCH_CHANNEL_LOGSWITCH_CHANNEL_ID_LOG, "mod_lua.cpp", (const char *)__func__, 402, __null, SWITCH_LOG_INFO, "lua: LUA_PATH unable to be set, out of memory: '%s'\n", (char *)path_stream.data); |
| 403 | } else { |
| 404 | switch_log_printf(SWITCH_CHANNEL_LOGSWITCH_CHANNEL_ID_LOG, "mod_lua.cpp", (const char *)__func__, 404, __null, SWITCH_LOG_INFO, "lua: LUA_PATH set to: '%s'\n", (char *)path_stream.data); |
| 405 | } |
| 406 | } |
| 407 | |
| 408 | if ((settings = switch_xml_child(cfg, "settings"))) { |
| 409 | for (param = switch_xml_child(settings, "param"); param; param = param->next) { |
| 410 | char *var = (char *) switch_xml_attr_soft(param, "name"); |
| 411 | char *val = (char *) switch_xml_attr_soft(param, "value"); |
| 412 | if (!strcmp(var, "startup-script")) { |
| 413 | if (val) { |
| 414 | lua_thread(val); |
| 415 | /* wait 10ms to avoid lua init issues */ |
| 416 | switch_yield(10000)switch_sleep(10000);; |
| 417 | } |
| 418 | } |
| 419 | } |
| 420 | } |
| 421 | |
| 422 | switch_safe_free(path_stream.data)if (path_stream.data) {free(path_stream.data);path_stream.data =__null;}; |
| 423 | |
| 424 | switch_xml_free(xml); |
| 425 | |
| 426 | return SWITCH_STATUS_SUCCESS; |
| 427 | } |
| 428 | |
| 429 | int lua_thread(const char *text) |
| 430 | { |
| 431 | switch_thread_t *thread; |
| 432 | switch_threadattr_t *thd_attr = NULL__null; |
| 433 | switch_memory_pool_t *pool; |
| 434 | lua_thread_helper *lth; |
| 435 | |
| 436 | switch_core_new_memory_pool(&pool)switch_core_perform_new_memory_pool(&pool, "mod_lua.cpp", (const char *)__func__, 436); |
| 437 | lth = (lua_thread_helper *) switch_core_alloc(pool, sizeof(*lth))switch_core_perform_alloc(pool, sizeof(*lth), "mod_lua.cpp", ( const char *)__func__, 437); |
| 438 | lth->pool = pool; |
| 439 | lth->input_code = switch_core_strdup(lth->pool, text)switch_core_perform_strdup(lth->pool, text, "mod_lua.cpp", (const char *)__func__, 439); |
| 440 | |
| 441 | switch_threadattr_create(&thd_attr, lth->pool); |
| 442 | switch_threadattr_detach_set(thd_attr, 1); |
| 443 | switch_threadattr_stacksize_set(thd_attr, SWITCH_THREAD_STACKSIZE240 * 1024); |
| 444 | switch_thread_create(&thread, thd_attr, lua_thread_run, lth, lth->pool); |
| 445 | |
| 446 | return 0; |
| 447 | } |
| 448 | |
| 449 | static void lua_event_handler(switch_event_t *event) |
| 450 | { |
| 451 | lua_State *L = lua_init(); |
| 452 | char *script = NULL__null; |
| 453 | |
| 454 | if (event->bind_user_data) { |
| 455 | script = strdup((char *)event->bind_user_data); |
| 456 | } |
| 457 | |
| 458 | mod_lua_conjure_event(L, event, "event", 1); |
| 459 | switch_log_printf(SWITCH_CHANNEL_LOGSWITCH_CHANNEL_ID_LOG, "mod_lua.cpp", (const char *)__func__, 459, __null, SWITCH_LOG_DEBUG, "lua event hook: execute '%s'\n", (char *)script); |
| 460 | lua_parse_and_execute(L, (char *)script); |
| 461 | lua_uninit(L); |
| 462 | |
| 463 | switch_safe_free(script)if (script) {free(script);script=__null;}; |
| 464 | } |
| 465 | |
| 466 | SWITCH_STANDARD_APP(lua_function)static void lua_function (switch_core_session_t *session, const char *data) |
| 467 | { |
| 468 | lua_State *L = lua_init(); |
| 469 | char *mycmd; |
| 470 | |
| 471 | if (zstr(data)_zstr(data)) { |
| 472 | switch_log_printf(SWITCH_CHANNEL_LOGSWITCH_CHANNEL_ID_LOG, "mod_lua.cpp", (const char *)__func__, 472, __null, SWITCH_LOG_ERROR, "no args specified!\n"); |
| 473 | return; |
| 474 | } |
| 475 | |
| 476 | mod_lua_conjure_session(L, session, "session", 1); |
| 477 | |
| 478 | mycmd = strdup((char *) data); |
| 479 | switch_assert(mycmd)((mycmd) ? static_cast<void> (0) : __assert_fail ("mycmd" , "mod_lua.cpp", 479, __PRETTY_FUNCTION__)); |
| 480 | |
| 481 | lua_parse_and_execute(L, mycmd); |
| 482 | lua_uninit(L); |
| 483 | free(mycmd); |
| 484 | |
| 485 | } |
| 486 | |
| 487 | SWITCH_STANDARD_API(luarun_api_function)static switch_status_t luarun_api_function ( const char *cmd, switch_core_session_t *session, switch_stream_handle_t *stream ) |
| 488 | { |
| 489 | |
| 490 | if (zstr(cmd)_zstr(cmd)) { |
| 491 | stream->write_function(stream, "-ERR no args specified!\n"); |
| 492 | } else { |
| 493 | lua_thread(cmd); |
| 494 | stream->write_function(stream, "+OK\n"); |
| 495 | } |
| 496 | |
| 497 | return SWITCH_STATUS_SUCCESS; |
| 498 | } |
| 499 | |
| 500 | SWITCH_STANDARD_CHAT_APP(lua_chat_function)static switch_status_t lua_chat_function (switch_event_t *message , const char *data) |
| 501 | { |
| 502 | lua_State *L = lua_init(); |
| 503 | char *dup = NULL__null; |
| 504 | |
| 505 | if (data) { |
| 506 | dup = strdup(data); |
| 507 | } |
| 508 | |
| 509 | mod_lua_conjure_event(L, message, "message", 1); |
| 510 | lua_parse_and_execute(L, (char *)dup); |
| 511 | lua_uninit(L); |
| 512 | |
| 513 | switch_safe_free(dup)if (dup) {free(dup);dup=__null;}; |
| 514 | |
| 515 | return SWITCH_STATUS_SUCCESS; |
| 516 | |
| 517 | } |
| 518 | |
| 519 | SWITCH_STANDARD_API(lua_api_function)static switch_status_t lua_api_function ( const char *cmd, switch_core_session_t *session, switch_stream_handle_t *stream) |
| 520 | { |
| 521 | |
| 522 | lua_State *L = lua_init(); |
| 523 | char *mycmd; |
| 524 | int error; |
| 525 | |
| 526 | if (zstr(cmd)_zstr(cmd)) { |
| 527 | stream->write_function(stream, ""); |
| 528 | } else { |
| 529 | |
| 530 | mycmd = strdup(cmd); |
| 531 | switch_assert(mycmd)((mycmd) ? static_cast<void> (0) : __assert_fail ("mycmd" , "mod_lua.cpp", 531, __PRETTY_FUNCTION__)); |
| 532 | |
| 533 | if (session) { |
| 534 | mod_lua_conjure_session(L, session, "session", 1); |
| 535 | } |
| 536 | |
| 537 | mod_lua_conjure_stream(L, stream, "stream", 1); |
| 538 | |
| 539 | if (stream->param_event) { |
| 540 | mod_lua_conjure_event(L, stream->param_event, "env", 1); |
| 541 | } |
| 542 | |
| 543 | if ((error = lua_parse_and_execute(L, mycmd))) { |
| 544 | char * http = switch_event_get_header(stream->param_event, "http-uri")switch_event_get_header_idx(stream->param_event, "http-uri" , -1); |
| 545 | if (http && (!strncasecmp(http, "/api/", 5) || !strncasecmp(http, "/webapi/", 8))) { |
| 546 | /* api -> fs api streams the Content-Type e.g. text/html or text/xml */ |
| 547 | /* api -> default Content-Type is text/plain */ |
| 548 | /* webapi, txtapi -> Content-Type defined in mod_xmlrpc text/html resp. text/plain */ |
| 549 | stream->write_function(stream, "<H2>Error Executing Script</H2>"); |
| 550 | } else { |
| 551 | stream->write_function(stream, "-ERR Cannot execute script\n"); |
| 552 | } |
| 553 | } |
| 554 | lua_uninit(L); |
| 555 | free(mycmd); |
| 556 | } |
| 557 | return SWITCH_STATUS_SUCCESS; |
| 558 | } |
| 559 | |
| 560 | SWITCH_STANDARD_DIALPLAN(lua_dialplan_hunt)static switch_caller_extension_t *lua_dialplan_hunt (switch_core_session_t *session, void *arg, switch_caller_profile_t *caller_profile ) |
| 561 | { |
| 562 | lua_State *L = lua_init(); |
| 563 | switch_caller_extension_t *extension = NULL__null; |
| 564 | switch_channel_t *channel = switch_core_session_get_channel(session); |
| 565 | char *cmd = NULL__null; |
| 566 | |
| 567 | if (!caller_profile) { |
| 568 | if (!(caller_profile = switch_channel_get_caller_profile(channel))) { |
| 569 | switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session)SWITCH_CHANNEL_ID_SESSION, "mod_lua.cpp", (const char *)__func__ , 569, (const char*)(session), SWITCH_LOG_ERROR, "Error Obtaining Profile!\n"); |
| 570 | goto done; |
| 571 | } |
| 572 | } |
| 573 | |
| 574 | if (!caller_profile->context) { |
| 575 | caller_profile->context = "lua/dialplan.lua"; |
| 576 | } |
| 577 | |
| 578 | switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session)SWITCH_CHANNEL_ID_SESSION, "mod_lua.cpp", (const char *)__func__ , 578, (const char*)(session), SWITCH_LOG_INFO, "Processing %s->%s in context/script %s\n", |
| 579 | caller_profile->caller_id_name, caller_profile->destination_number, caller_profile->context); |
| 580 | |
| 581 | if ((extension = switch_caller_extension_new(session, "_anon_", caller_profile->destination_number)) == 0) { |
| 582 | switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session)SWITCH_CHANNEL_ID_SESSION, "mod_lua.cpp", (const char *)__func__ , 582, (const char*)(session), SWITCH_LOG_CRIT, "Memory Error!\n"); |
| 583 | goto done; |
| 584 | } |
| 585 | |
| 586 | cmd = strdup(caller_profile->context); |
| 587 | switch_assert(cmd)((cmd) ? static_cast<void> (0) : __assert_fail ("cmd", "mod_lua.cpp" , 587, __PRETTY_FUNCTION__)); |
| 588 | |
| 589 | mod_lua_conjure_session(L, session, "session", 1); |
| 590 | lua_parse_and_execute(L, cmd); |
| 591 | |
| 592 | /* expecting ACTIONS = { {"app1", "app_data1"}, { "app2" }, "app3" } -- each of three is valid */ |
| 593 | lua_getglobal(L, "ACTIONS"); |
| 594 | if (!lua_istable(L, 1)(lua_type(L, (1)) == 5)) { |
| 595 | switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session)SWITCH_CHANNEL_ID_SESSION, "mod_lua.cpp", (const char *)__func__ , 595, (const char*)(session), SWITCH_LOG_ERROR, |
| 596 | "Global variable ACTIONS may only be a table\n"); |
| 597 | goto done; |
| 598 | } |
| 599 | |
| 600 | lua_pushnil(L); /* STACK = tab | nil */ |
| 601 | |
| 602 | while (lua_next(L, 1) != 0) { /* STACK = tab | k1 .. kn | vn */ |
| 603 | char *application = NULL__null, *app_data = NULL__null; |
| 604 | |
| 605 | if (lua_isstring(L, -1)) { |
| 606 | application = strdup(lua_tostring(L, -1)lua_tolstring(L, (-1), __null)); |
| 607 | app_data = strdup(""); |
| 608 | |
| 609 | } else if (lua_istable(L, -1)(lua_type(L, (-1)) == 5)) { |
| 610 | int i = lua_gettop(L); |
| 611 | |
| 612 | lua_pushnil(L); /* STACK = tab1 | k1 .. kn | tab2 | nil */ |
| 613 | |
| 614 | if (lua_next(L, i) != 0) { /* STACK = tab1 | k1 .. kn | tab2 | k | v */ |
| 615 | |
| 616 | if (!lua_isstring(L, -1)) { |
| 617 | switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session)SWITCH_CHANNEL_ID_SESSION, "mod_lua.cpp", (const char *)__func__ , 617, (const char*)(session), SWITCH_LOG_ERROR, |
| 618 | "First element in each table in the ACTIONS table may only be a string - application name\n"); |
| 619 | goto rollback; |
| 620 | } |
| 621 | |
| 622 | application = strdup(lua_tostring(L, -1)lua_tolstring(L, (-1), __null)); |
| 623 | |
| 624 | lua_pop(L, 1)lua_settop(L, -(1)-1); |
| 625 | |
| 626 | if (lua_next(L, i) == 0) { /* STACK = tab1 | k1 .. kn | tab2 | k | k | v */ |
| 627 | app_data = strdup(""); |
| 628 | |
| 629 | } else { |
| 630 | if (!lua_isstring(L, -1)) { |
| 631 | switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session)SWITCH_CHANNEL_ID_SESSION, "mod_lua.cpp", (const char *)__func__ , 631, (const char*)(session), SWITCH_LOG_ERROR, |
| 632 | "Second (optional) element in each table in the ACTIONS table may only be a string - app_data\n"); |
| 633 | free(application); |
| 634 | goto rollback; |
| 635 | } |
| 636 | app_data = strdup(lua_tostring(L, -1)lua_tolstring(L, (-1), __null)); |
| 637 | } |
| 638 | |
| 639 | } |
| 640 | |
| 641 | lua_settop(L, i); /* STACK = tab1 | k1 .. kn | tab2 */ |
| 642 | |
| 643 | } else { |
| 644 | switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session)SWITCH_CHANNEL_ID_SESSION, "mod_lua.cpp", (const char *)__func__ , 644, (const char*)(session), SWITCH_LOG_ERROR, |
| 645 | "ACTIONS table may only contain strings or tables\n"); |
| 646 | goto rollback; |
| 647 | } |
| 648 | |
| 649 | switch_log_printf(SWITCH_CHANNEL_SESSION_LOG_CLEAN(session)SWITCH_CHANNEL_ID_LOG_CLEAN, "mod_lua.cpp", (const char *)__func__ , 649, switch_core_session_get_uuid((session)), SWITCH_LOG_DEBUG, |
| 650 | "Dialplan: %s Action %s(%s)\n", |
| 651 | switch_channel_get_name(channel), application, app_data); |
| 652 | |
| 653 | switch_caller_extension_add_application(session, extension, application, app_data); |
| 654 | free(app_data); |
| 655 | free(application); |
| 656 | |
| 657 | lua_pop(L, 1)lua_settop(L, -(1)-1); |
| 658 | } |
| 659 | |
| 660 | /* all went fine */ |
| 661 | goto done; |
| 662 | |
| 663 | rollback: |
| 664 | switch_log_printf(SWITCH_CHANNEL_SESSION_LOG_CLEAN(session)SWITCH_CHANNEL_ID_LOG_CLEAN, "mod_lua.cpp", (const char *)__func__ , 664, switch_core_session_get_uuid((session)), SWITCH_LOG_DEBUG, |
| 665 | "Rollback, all applications previously added to this extension in current context/script are discarded\n"); |
| 666 | |
| 667 | /* extension was created on session's memory pool, so just make a new, empty one here */ |
| 668 | if ((extension = switch_caller_extension_new(session, "_anon_", caller_profile->destination_number)) == 0) { |
| 669 | switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session)SWITCH_CHANNEL_ID_SESSION, "mod_lua.cpp", (const char *)__func__ , 669, (const char*)(session), SWITCH_LOG_CRIT, "Memory Error!\n"); |
| 670 | } |
| 671 | |
| 672 | done: |
| 673 | switch_safe_free(cmd)if (cmd) {free(cmd);cmd=__null;}; |
| 674 | lua_uninit(L); |
| 675 | return extension; |
| 676 | } |
| 677 | |
| 678 | SWITCH_MODULE_LOAD_FUNCTION(mod_lua_load)switch_status_t mod_lua_load (switch_loadable_module_interface_t **module_interface, switch_memory_pool_t *pool) |
| 679 | { |
| 680 | switch_api_interface_t *api_interface; |
| 681 | switch_application_interface_t *app_interface; |
| 682 | switch_dialplan_interface_t *dp_interface; |
| 683 | switch_chat_application_interface_t *chat_app_interface; |
| 684 | |
| 685 | /* connect my internal structure to the blank pointer passed to me */ |
| 686 | *module_interface = switch_loadable_module_create_module_interface(pool, modname); |
| 687 | |
| 688 | SWITCH_ADD_API(api_interface, "luarun", "run a script", luarun_api_function, "<script>")for (;;) { api_interface = (switch_api_interface_t *)switch_loadable_module_create_interface (*module_interface, SWITCH_API_INTERFACE); api_interface-> interface_name = "luarun"; api_interface->desc = "run a script" ; api_interface->function = luarun_api_function; api_interface ->syntax = "<script>"; break; }; |
| 689 | SWITCH_ADD_API(api_interface, "lua", "run a script as an api function", lua_api_function, "<script>")for (;;) { api_interface = (switch_api_interface_t *)switch_loadable_module_create_interface (*module_interface, SWITCH_API_INTERFACE); api_interface-> interface_name = "lua"; api_interface->desc = "run a script as an api function" ; api_interface->function = lua_api_function; api_interface ->syntax = "<script>"; break; }; |
| 690 | SWITCH_ADD_APP(app_interface, "lua", "Launch LUA ivr", "Run a lua ivr on a channel", lua_function, "<script>",for (;;) { app_interface = (switch_application_interface_t *) switch_loadable_module_create_interface(*module_interface, SWITCH_APPLICATION_INTERFACE ); app_interface->interface_name = "lua"; app_interface-> application_function = lua_function; app_interface->short_desc = "Launch LUA ivr"; app_interface->long_desc = "Run a lua ivr on a channel" ; app_interface->syntax = "<script>"; app_interface-> flags = SAF_SUPPORT_NOMEDIA | SAF_ROUTING_EXEC | SAF_ZOMBIE_EXEC ; break; } |
| 691 | SAF_SUPPORT_NOMEDIA | SAF_ROUTING_EXEC | SAF_ZOMBIE_EXEC)for (;;) { app_interface = (switch_application_interface_t *) switch_loadable_module_create_interface(*module_interface, SWITCH_APPLICATION_INTERFACE ); app_interface->interface_name = "lua"; app_interface-> application_function = lua_function; app_interface->short_desc = "Launch LUA ivr"; app_interface->long_desc = "Run a lua ivr on a channel" ; app_interface->syntax = "<script>"; app_interface-> flags = SAF_SUPPORT_NOMEDIA | SAF_ROUTING_EXEC | SAF_ZOMBIE_EXEC ; break; }; |
| 692 | SWITCH_ADD_DIALPLAN(dp_interface, "LUA", lua_dialplan_hunt)for (;;) { dp_interface = (switch_dialplan_interface_t *)switch_loadable_module_create_interface (*module_interface, SWITCH_DIALPLAN_INTERFACE); dp_interface-> hunt_function = lua_dialplan_hunt; dp_interface->interface_name = "LUA"; break; }; |
| 693 | |
| 694 | SWITCH_ADD_CHAT_APP(chat_app_interface, "lua", "execute a lua script", "execute a lua script", lua_chat_function, "<script>", SCAF_NONE)for (;;) { chat_app_interface = (switch_chat_application_interface_t *)switch_loadable_module_create_interface(*module_interface, SWITCH_CHAT_APPLICATION_INTERFACE); chat_app_interface->interface_name = "lua"; chat_app_interface->chat_application_function = lua_chat_function ; chat_app_interface->short_desc = "execute a lua script"; chat_app_interface->long_desc = "execute a lua script"; chat_app_interface ->syntax = "<script>"; chat_app_interface->flags = SCAF_NONE; break; }; |
| 695 | |
| 696 | |
| 697 | globals.pool = pool; |
| 698 | do_config(); |
| 699 | |
| 700 | /* indicate that the module should continue to be loaded */ |
| 701 | return SWITCH_STATUS_NOUNLOAD; |
| 702 | } |
| 703 | |
| 704 | SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_lua_shutdown)switch_status_t mod_lua_shutdown (void) |
| 705 | { |
| 706 | switch_event_unbind_callback(lua_event_handler); |
| 707 | |
| 708 | return SWITCH_STATUS_SUCCESS; |
| 709 | } |
| 710 | |
| 711 | |
| 712 | SWITCH_END_EXTERN_C} |
| 713 | /* For Emacs: |
| 714 | * Local Variables: |
| 715 | * mode:c |
| 716 | * indent-tabs-mode:t |
| 717 | * tab-width:4 |
| 718 | * c-basic-offset:4 |
| 719 | * End: |
| 720 | * For VIM: |
| 721 | * vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet: |
| 722 | */ |