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 | */ |