1
2 #include <switch.h>
3 #include "freeswitch_lua.h"
4 using namespace LUA;
5
6 extern "C" {
7 int docall(lua_State * L, int narg, int nresults, int perror, int fatal);
8 };
9
Session()10 Session::Session():CoreSession()
11 {
12 cb_function = cb_arg = hangup_func_str = hangup_func_arg = NULL;
13 hh = mark = 0;
14 }
15
Session(char * nuuid,CoreSession * a_leg)16 Session::Session(char *nuuid, CoreSession *a_leg):CoreSession(nuuid, a_leg)
17 {
18 cb_function = cb_arg = hangup_func_str = hangup_func_arg = NULL;
19 hh = mark = 0;
20 }
21
Session(switch_core_session_t * new_session)22 Session::Session(switch_core_session_t *new_session):CoreSession(new_session)
23 {
24 cb_function = cb_arg = hangup_func_str = hangup_func_arg = NULL;
25 hh = mark = 0;
26 }
27 static switch_status_t lua_hanguphook(switch_core_session_t *session_hungup);
28
29
destroy(const char * err)30 void Session::destroy(const char *err)
31 {
32
33 if (!allocated) {
34 return;
35 }
36
37 if (session) {
38 if (!channel) {
39 channel = switch_core_session_get_channel(session);
40 }
41 switch_channel_set_private(channel, "CoreSession", NULL);
42 switch_core_event_hook_remove_state_change(session, lua_hanguphook);
43 }
44
45 switch_safe_free(hangup_func_str);
46 switch_safe_free(hangup_func_arg);
47 switch_safe_free(cb_function);
48 switch_safe_free(cb_arg);
49
50 unsetInputCallback();
51
52 CoreSession::destroy();
53
54
55 if (!zstr(err)) {
56 lua_pushstring(L, err);
57 lua_error(L);
58 }
59
60 }
61
62
~Session()63 Session::~Session()
64 {
65 destroy();
66 }
67
begin_allow_threads()68 bool Session::begin_allow_threads()
69 {
70 do_hangup_hook();
71 return true;
72 }
73
end_allow_threads()74 bool Session::end_allow_threads()
75 {
76 do_hangup_hook();
77 return true;
78 }
79
setLUA(lua_State * state)80 void Session::setLUA(lua_State * state)
81 {
82 L = state;
83
84 if (session && allocated && uuid) {
85 lua_setglobal(L, uuid);
86 lua_getglobal(L, uuid);
87 }
88
89 }
90
originate(CoreSession * a_leg_session,char * dest,int timeout)91 int Session::originate(CoreSession *a_leg_session, char *dest, int timeout)
92 {
93 if (zstr(dest)) {
94 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Missing destination.\n");
95 return 0;
96 }
97
98 int x = CoreSession::originate(a_leg_session, dest, timeout);
99
100 if (x) {
101 setLUA(L);
102 }
103
104 return x;
105 }
106
getLUA()107 lua_State *Session::getLUA()
108 {
109 if (!L) {
110 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Doh!\n");
111 }
112 return L;
113 }
114
115
ready()116 bool Session::ready()
117 {
118 bool r;
119
120 if (!session) {
121 return false;
122 }
123 sanity_check(false);
124 r = switch_channel_ready(channel) != 0;
125 do_hangup_hook();
126
127 return r;
128 }
129
check_hangup_hook()130 void Session::check_hangup_hook()
131 {
132 if (hangup_func_str && (hook_state == CS_HANGUP || hook_state == CS_ROUTING)) {
133 hh++;
134 }
135 }
136
do_hangup_hook()137 void Session::do_hangup_hook()
138 {
139 if (hh && !mark) {
140 int arg_count = 2;
141 mark++;
142
143 if (!getLUA()) {
144 return;
145 }
146
147 lua_getglobal(L, (char *) hangup_func_str);
148 lua_getglobal(L, uuid);
149
150 lua_pushstring(L, hook_state == CS_HANGUP ? "hangup" : "transfer");
151
152 if (hangup_func_arg) {
153 lua_getglobal(L, (char *) hangup_func_arg);
154 arg_count++;
155 }
156
157 docall(L, arg_count, 1, 1, 0);
158
159 const char *err = lua_tostring(L, -1);
160
161 switch_channel_set_variable(channel, "lua_hangup_hook_return_val", err);
162
163 if (!zstr(err)) {
164
165 if (!strcasecmp(err, "exit") || !strcasecmp(err, "die")) {
166 lua_error(L);
167 } else {
168 lua_pop(L, 1);
169 }
170 } else {
171 lua_pop(L, 1);
172 }
173
174
175 if (channel) {
176 switch_channel_set_private(channel, "CoreSession", NULL);
177 }
178
179 if (session) {
180 switch_core_event_hook_remove_state_change(session, lua_hanguphook);
181 }
182 switch_safe_free(hangup_func_str);
183
184 }
185 }
186
lua_hanguphook(switch_core_session_t * session_hungup)187 static switch_status_t lua_hanguphook(switch_core_session_t *session_hungup)
188 {
189 switch_channel_t *channel = switch_core_session_get_channel(session_hungup);
190 Session *coresession = NULL;
191 switch_channel_state_t state = switch_channel_get_state(channel);
192
193 if (session_hungup) {
194
195 channel = switch_core_session_get_channel(session_hungup);
196
197 if (channel) {
198 void *vs = switch_channel_get_private(channel, "CoreSession");
199 if (vs) {
200 coresession = (Session *) vs;
201 }
202 }
203
204 if (!(coresession && coresession->hook_state)) {
205 return SWITCH_STATUS_FALSE;
206 }
207
208 if (coresession && coresession->allocated && (state == CS_HANGUP || state == CS_ROUTING) && coresession->hook_state != state) {
209 coresession->hook_state = state;
210 coresession->check_hangup_hook();
211 switch_core_event_hook_remove_state_change(session_hungup, lua_hanguphook);
212 }
213 }
214
215 return SWITCH_STATUS_SUCCESS;
216 }
217
218
setHangupHook(char * func,char * arg)219 void Session::setHangupHook(char *func, char *arg)
220 {
221
222 sanity_check_noreturn;
223
224 switch_safe_free(hangup_func_str);
225 switch_safe_free(hangup_func_arg);
226
227 if (func) {
228 hangup_func_str = strdup(func);
229 if (!zstr(arg)) {
230 hangup_func_arg = strdup(arg);
231 }
232 switch_channel_set_private(channel, "CoreSession", this);
233 hook_state = switch_channel_get_state(channel);
234 switch_core_event_hook_add_state_change(session, lua_hanguphook);
235 }
236 }
237
unsetInputCallback(void)238 void Session::unsetInputCallback(void)
239 {
240 sanity_check_noreturn;
241 switch_safe_free(cb_function);
242 switch_safe_free(cb_arg);
243 args.input_callback = NULL;
244 ap = NULL;
245 switch_channel_clear_flag_recursive(channel, CF_QUEUE_TEXT_EVENTS);
246 }
247
setInputCallback(char * cbfunc,char * funcargs)248 void Session::setInputCallback(char *cbfunc, char *funcargs)
249 {
250
251 sanity_check_noreturn;
252
253 switch_safe_free(cb_function);
254 if (cbfunc) {
255 cb_function = strdup(cbfunc);
256 }
257
258 switch_safe_free(cb_arg);
259 if (funcargs) {
260 cb_arg = strdup(funcargs);
261 }
262
263 args.buf = this;
264 switch_channel_set_private(channel, "CoreSession", this);
265
266 args.input_callback = dtmf_callback;
267 ap = &args;
268
269 switch_channel_set_flag_recursive(channel, CF_QUEUE_TEXT_EVENTS);
270
271 }
272
run_dtmf_callback(void * input,switch_input_type_t itype)273 switch_status_t Session::run_dtmf_callback(void *input, switch_input_type_t itype)
274 {
275 const char *ret;
276
277 if (!getLUA()) {
278 return SWITCH_STATUS_FALSE;;
279 }
280
281 switch (itype) {
282 case SWITCH_INPUT_TYPE_DTMF:
283 {
284 switch_dtmf_t *dtmf = (switch_dtmf_t *) input;
285 char str[3] = "";
286 int arg_count = 3;
287 int r;
288
289 lua_getglobal(L, (char *) cb_function);
290 lua_getglobal(L, uuid);
291
292 lua_pushstring(L, "dtmf");
293
294 lua_newtable(L);
295 lua_pushstring(L, "digit");
296 str[0] = dtmf->digit;
297 lua_pushstring(L, str);
298 lua_rawset(L, -3);
299
300 lua_pushstring(L, "duration");
301 lua_pushnumber(L, dtmf->duration);
302 lua_rawset(L, -3);
303
304 if (!zstr(cb_arg)) {
305 lua_getglobal(L, (char *) cb_arg);
306 arg_count++;
307 }
308
309 r = docall(L, arg_count, 1, 1, 0);
310
311 if (!r) {
312 ret = lua_tostring(L, -1);
313 lua_pop(L, 1);
314 } else {
315 ret = "SCRIPT_ERROR";
316 }
317
318 return process_callback_result((char *) ret);
319 }
320 break;
321 case SWITCH_INPUT_TYPE_EVENT:
322 {
323 switch_event_t *event = (switch_event_t *) input;
324 int arg_count = 3;
325
326
327 lua_getglobal(L, (char *) cb_function);
328 lua_getglobal(L, uuid);
329 lua_pushstring(L, "event");
330 mod_lua_conjure_event(L, event, "__Input_Event__", 1);
331 lua_getglobal(L, "__Input_Event__");
332
333 if (!zstr(cb_arg)) {
334 lua_getglobal(L, (char *) cb_arg);
335 arg_count++;
336 }
337
338 if (!docall(L, arg_count, 1, 1, 0)) {
339 ret = lua_tostring(L, -1);
340 lua_pop(L, 1);
341 } else {
342 ret = "SCRIPT_ERROR";
343 }
344
345 return process_callback_result((char *) ret);
346 }
347 break;
348 }
349
350 return SWITCH_STATUS_SUCCESS;
351 }
352
353
Dbh(char * dsn,char * user,char * pass)354 Dbh::Dbh(char *dsn, char *user, char *pass)
355 {
356 dbh = NULL;
357 err = NULL;
358 char *tmp = NULL;
359
360 if (!zstr(user) || !zstr(pass)) {
361 tmp = switch_mprintf("%s%s%s%s%s", dsn,
362 zstr(user) ? "" : ":",
363 zstr(user) ? "" : user,
364 zstr(pass) ? "" : ":",
365 zstr(pass) ? "" : pass
366 );
367
368 dsn = tmp;
369 }
370
371 if (!zstr(dsn) && switch_cache_db_get_db_handle_dsn(&dbh, dsn) == SWITCH_STATUS_SUCCESS) {
372 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG10, "DBH handle %p Connected.\n", (void *) dbh);
373 } else {
374 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Connection failed. DBH NOT Connected.\n");
375 }
376
377 switch_safe_free(tmp);
378
379 }
380
~Dbh()381 Dbh::~Dbh()
382 {
383 if (dbh) release();
384
385 clear_error();
386 }
387
clear_error()388 void Dbh::clear_error()
389 {
390 switch_safe_free(err);
391 }
392
last_error()393 char *Dbh::last_error()
394 {
395 return err;
396 }
397
release()398 bool Dbh::release()
399 {
400 if (dbh) {
401 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG10, "DBH handle %p released.\n", (void *) dbh);
402 switch_cache_db_release_db_handle(&dbh);
403 return true;
404 }
405
406 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "DBH NOT Connected.\n");
407 return false;
408 }
409
connected()410 bool Dbh::connected()
411 {
412 return dbh ? true : false;
413 }
414
test_reactive(char * test_sql,char * drop_sql,char * reactive_sql)415 bool Dbh::test_reactive(char *test_sql, char *drop_sql, char *reactive_sql)
416 {
417 if (dbh) {
418 if (!zstr(test_sql) && !zstr(reactive_sql)) {
419 if (switch_cache_db_test_reactive(dbh, test_sql, drop_sql, reactive_sql) == SWITCH_TRUE) {
420 return true;
421 }
422 } else {
423 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Missing parameters.\n");
424 }
425 } else {
426 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "DBH NOT Connected.\n");
427 }
428 return false;
429 }
430
query_callback(void * pArg,int argc,char ** argv,char ** cargv)431 int Dbh::query_callback(void *pArg, int argc, char **argv, char **cargv)
432 {
433 SWIGLUA_FN *lua_fun = (SWIGLUA_FN *)pArg;
434 int ret = 0;
435
436 lua_pushvalue(lua_fun->L, lua_fun->idx); /* get the lua callback function onto the stack */
437
438 lua_newtable(lua_fun->L); /* push a row (table) */
439
440 for (int i = 0; i < argc; i++) {
441 lua_pushstring(lua_fun->L, switch_str_nil(cargv[i]));
442 lua_pushstring(lua_fun->L, switch_str_nil(argv[i]));
443 lua_settable(lua_fun->L, -3);
444 }
445
446 if (docall(lua_fun->L, 1, 1, 1, 0)) {
447 return 1;
448 }
449
450 ret = lua_tonumber(lua_fun->L, -1);
451 lua_pop(lua_fun->L, 1);
452
453 if (ret != 0) {
454 return 1;
455 }
456
457 return 0; /* 0 to continue with next row */
458 }
459
query(char * sql,SWIGLUA_FN lua_fun)460 bool Dbh::query(char *sql, SWIGLUA_FN lua_fun)
461 {
462 clear_error();
463
464 if (zstr(sql)) {
465 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Missing SQL query.\n");
466 return false;
467 }
468
469 if (dbh) {
470 if (lua_fun.L) {
471 if (switch_cache_db_execute_sql_callback(dbh, sql, query_callback, &lua_fun, &err) == SWITCH_STATUS_SUCCESS) {
472 return true;
473 }
474 } else { /* if no lua_fun arg is passed from Lua, an empty initialized struct will be sent - see freeswitch.i */
475 if (switch_cache_db_execute_sql(dbh, sql, &err) == SWITCH_STATUS_SUCCESS) {
476 return true;
477 }
478 }
479 } else {
480 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "DBH NOT Connected.\n");
481 }
482 return false;
483 }
484
affected_rows()485 int Dbh::affected_rows()
486 {
487 if (dbh) {
488 return switch_cache_db_affected_rows(dbh);
489 }
490
491 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "DBH NOT Connected.\n");
492 return 0;
493 }
494
load_extension(const char * extension)495 int Dbh::load_extension(const char *extension)
496 {
497 if (zstr(extension)) {
498 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Missing extension name.\n");
499 return 0;
500 }
501
502 if (dbh) {
503 return switch_cache_db_load_extension(dbh, extension);
504 }
505
506 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "DBH NOT Connected.\n");
507 return 0;
508 }
509
JSON()510 JSON::JSON()
511 {
512 _encode_empty_table_as_object = true;
513 }
514
~JSON()515 JSON::~JSON()
516 {
517 }
518
encode_empty_table_as_object(bool flag)519 void JSON::encode_empty_table_as_object(bool flag)
520 {
521 _encode_empty_table_as_object = flag;
522 }
523
return_unformatted_json(bool flag)524 void JSON::return_unformatted_json(bool flag)
525 {
526 _return_unformatted_json = flag;
527 }
528
decode(const char * str)529 cJSON *JSON::decode(const char *str)
530 {
531 cJSON *json = cJSON_Parse(str);
532 return json;
533 }
534
535 #define ADDITEM(json, k, v) do { \
536 if (return_array > 0) { cJSON_AddItemToArray(json, v);} else { cJSON_AddItemToObject(json, k, v); } \
537 } while (0)
538
LuaTable2cJSON(lua_State * L,int index,cJSON ** json)539 void JSON::LuaTable2cJSON(lua_State *L, int index, cJSON **json)
540 {
541 int return_array = -1;
542
543 // Push another reference to the table on top of the stack (so we know
544 // where it is, and this function can work for negative, positive and
545 // pseudo indices
546 lua_pushvalue(L, index);
547 // stack now contains: -1 => table
548 lua_pushnil(L);
549 // stack now contains: -1 => nil; -2 => table
550 while (lua_next(L, -2)) {
551 // stack now contains: -1 => value; -2 => key; -3 => table
552 // copy the key so that lua_tostring does not modify the original
553 lua_pushvalue(L, -2);
554 // stack now contains: -1 => key; -2 => value; -3 => key; -4 => table
555
556 const char *key = lua_tostring(L, -1);
557 // switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "key: %s\n", key);
558
559 if (return_array < 0) {
560 if (lua_isnumber(L, -1) && lua_tonumber(L, -1) == 1) {
561 return_array = 1;
562 *json = cJSON_CreateArray();
563 } else {
564 return_array = 0;
565 *json = cJSON_CreateObject();
566 }
567 }
568
569 switch_assert(*json);
570
571 if (lua_isnumber(L, -2)) {
572 ADDITEM(*json, key, cJSON_CreateNumber(lua_tonumber(L, -2)));
573 } else if (lua_isstring(L, -2)) {
574 ADDITEM(*json, key, cJSON_CreateString(lua_tostring(L, -2)));
575 } else if (lua_isboolean(L, -2)) {
576 ADDITEM(*json, key, cJSON_CreateBool(lua_toboolean(L, -2)));
577 } else if (lua_isnil(L, -2)) {
578 ADDITEM(*json, key, cJSON_CreateNull());
579 } else if (lua_isnone(L, -2)) {
580 // ADDITEM(*json, key, cJSON_CreateNone());
581 } else if (lua_istable(L, -2)) {
582 cJSON *child = NULL;
583 LuaTable2cJSON(L, -2, &child);
584 if (child) {
585 ADDITEM(*json, key, child);
586 } else { // empty table?
587 ADDITEM(*json, key, _encode_empty_table_as_object ? cJSON_CreateObject() : cJSON_CreateArray());
588 }
589 }
590
591 // pop value + copy of key, leaving original key
592 lua_pop(L, 2);
593 // stack now contains: -1 => key; -2 => table
594 }
595
596 // stack now contains: -1 => table (when lua_next returns 0 it pops the key
597 // but does not push anything.)
598 // Pop table
599 lua_pop(L, 1);
600 // Stack is now the same as it was on entry to this function
601 }
602
encode(SWIGLUA_TABLE lua_table)603 std::string JSON::encode(SWIGLUA_TABLE lua_table)
604 {
605 lua_State *L = lua_table.L;
606 cJSON *json = NULL;
607
608 luaL_checktype(L, lua_table.idx, LUA_TTABLE);
609 LuaTable2cJSON(L, -1, &json);
610
611 if (!json) {
612 json = _encode_empty_table_as_object ? cJSON_CreateObject() : cJSON_CreateArray();
613 }
614
615 char *s = _return_unformatted_json ? cJSON_PrintUnformatted(json) : cJSON_Print(json);
616 std::string result = std::string(s);
617 free(s);
618 cJSON_Delete(json);
619 return result;
620 }
621
cJSON2LuaTable(lua_State * L,cJSON * json)622 int JSON::cJSON2LuaTable(lua_State *L, cJSON *json) {
623 cJSON *current = NULL;
624
625 if (!json) return 0;
626
627 lua_newtable(L);
628
629 if (json->type == cJSON_Object) {
630 for (current = json->child; current; current = current->next) {
631 // printf("type: %d %s\n", current->type, current->string);
632 switch (current->type) {
633 case cJSON_String:
634 lua_pushstring(L, current->valuestring);
635 lua_setfield(L, -2, current->string);
636 break;
637 case cJSON_Number:
638 lua_pushnumber(L, current->valuedouble);
639 lua_setfield(L, -2, current->string);
640 break;
641 case cJSON_True:
642 lua_pushboolean(L, 1);
643 lua_setfield(L, -2, current->string);
644 break;
645 case cJSON_False:
646 lua_pushboolean(L, 0);
647 lua_setfield(L, -2, current->string);
648 break;
649 case cJSON_Object:
650 JSON::cJSON2LuaTable(L, current);
651 lua_setfield(L, -2, current->string);
652 break;
653 case cJSON_Array:
654 JSON::cJSON2LuaTable(L, current);
655 lua_setfield(L, -2, current->string);
656 break;
657 default:
658 break;
659 }
660 }
661 } else if (json->type == cJSON_Array) {
662 int i = 1;
663
664 for (current = json->child; current; current = current->next) {
665 // printf("array type: %d %s\n", current->type, current->valuestring);
666 switch (current->type) {
667 case cJSON_String:
668 lua_pushinteger(L, i++);
669 lua_pushstring(L, current->valuestring);
670 lua_settable(L, -3);
671 break;
672 case cJSON_Number:
673 lua_pushinteger(L, i++);
674 lua_pushnumber(L, current->valuedouble);
675 lua_settable(L, -3);
676 break;
677 case cJSON_True:
678 lua_pushinteger(L, i++);
679 lua_pushboolean(L, 1);
680 lua_settable(L, -3);
681 break;
682 case cJSON_False:
683 lua_pushinteger(L, i++);
684 lua_pushboolean(L, 0);
685 lua_settable(L, -3);
686 break;
687 case cJSON_Object:
688 lua_pushinteger(L, i++);
689 JSON::cJSON2LuaTable(L, current);
690 lua_settable(L, -3);
691 break;
692 default:
693 break;
694 }
695 }
696 }
697
698 return 1;
699 }
700
execute(const char * str)701 cJSON *JSON::execute(const char *str)
702 {
703 cJSON *cmd = cJSON_Parse(str);
704 cJSON *reply = NULL;
705
706 if (cmd) {
707 switch_json_api_execute(cmd, NULL, &reply);
708 }
709
710 cJSON_Delete(cmd);
711
712 return reply;
713 }
714
execute(SWIGLUA_TABLE table)715 cJSON *JSON::execute(SWIGLUA_TABLE table)
716 {
717 lua_State *L = table.L;
718 cJSON *json = NULL;
719 cJSON *reply = NULL;
720
721 luaL_checktype(L, table.idx, LUA_TTABLE);
722 LuaTable2cJSON(L, -1, &json);
723
724 switch_json_api_execute(json, NULL, &reply);
725 cJSON_Delete(json);
726 return reply;
727 }
728
execute2(const char * str)729 std::string JSON::execute2(const char *str)
730 {
731 cJSON *reply = execute(str);
732 char *s = _return_unformatted_json ? cJSON_PrintUnformatted(reply) : cJSON_Print(reply);
733 std::string result = std::string(s);
734 free(s);
735 cJSON_Delete(reply);
736 return result;
737 }
738
execute2(SWIGLUA_TABLE table)739 std::string JSON::execute2(SWIGLUA_TABLE table)
740 {
741 cJSON *reply = execute(table);
742 char *s = _return_unformatted_json ? cJSON_PrintUnformatted(reply) : cJSON_Print(reply);
743 std::string result = std::string(s);
744 free(s);
745 cJSON_Delete(reply);
746 return result;
747 }
748