Bug Summary

File:src/mod/languages/mod_lua/mod_lua.cpp
Location:line 130, column 3
Description:Value stored to 'error' is never read

Annotated Source Code

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>
36SWITCH_BEGIN_EXTERN_Cextern "C" {
37#include "lua.h"
38#include <lauxlib.h>
39#include <lualib.h>
40#include "mod_lua_extra.h"
41SWITCH_MODULE_LOAD_FUNCTION(mod_lua_load)switch_status_t mod_lua_load (switch_loadable_module_interface_t
**module_interface, switch_memory_pool_t *pool)
;
42SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_lua_shutdown)switch_status_t mod_lua_shutdown (void);
43
44SWITCH_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
}
;
45static struct {
46 switch_memory_pool_t *pool;
47 char *xml_handler;
48} globals;
49
50int luaopen_freeswitch(lua_State * L);
51int lua_thread(const char *text);
52
53static 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
60static void lua_uninit(lua_State * L)
61{
62 lua_gc(L, LUA_GCCOLLECT2, 0);
63 lua_close(L);
64}
65
66static 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
84int 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
118static 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
136static 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
211struct lua_thread_helper {
212 switch_memory_pool_t *pool;
213 char *input_code;
214};
215
216static 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
234static 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
300static void lua_event_handler(switch_event_t *event);
301
302static 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
429int 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
449static 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
466SWITCH_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
487SWITCH_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
500SWITCH_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
519SWITCH_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
560SWITCH_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
678SWITCH_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
704SWITCH_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
712SWITCH_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 */