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 * Raymond Chandler <intralanman@freeswitch.org>
28 *
29 * mod_sms.c -- Abstract SMS
30 *
31 */
32 #include <switch.h>
33 #define SMS_CHAT_PROTO "GLOBAL_SMS"
34 #define MY_EVENT_SEND_MESSAGE "SMS::SEND_MESSAGE"
35 #define MY_EVENT_DELIVERY_REPORT "SMS::DELIVERY_REPORT"
36
37 /* Prototypes */
38 SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_sms_shutdown);
39 SWITCH_MODULE_RUNTIME_FUNCTION(mod_sms_runtime);
40 SWITCH_MODULE_LOAD_FUNCTION(mod_sms_load);
41 SWITCH_MODULE_DEFINITION(mod_sms, mod_sms_load, mod_sms_shutdown, NULL);
42
43
send_report(switch_event_t * event,const char * Status)44 static void send_report(switch_event_t *event, const char * Status) {
45 switch_event_t *report = NULL;
46 switch_event_header_t *header;
47
48 if (switch_event_create_subclass(&report, SWITCH_EVENT_CUSTOM, MY_EVENT_DELIVERY_REPORT) == SWITCH_STATUS_SUCCESS) {
49
50 switch_event_add_header_string(report, SWITCH_STACK_BOTTOM, "Status", Status);
51
52
53 for (header = event->headers; header; header = header->next) {
54 if (!strcmp(header->name, "Event-Subclass")) {
55 continue;
56 }
57 if (!strcmp(header->name, "Event-Name")) {
58 continue;
59 }
60 if (header->idx) {
61 int i;
62 for (i = 0; i < header->idx; i++) {
63 switch_event_add_header_string(report, SWITCH_STACK_PUSH, header->name, header->array[i]);
64 }
65 } else {
66 switch_event_add_header_string(report, SWITCH_STACK_BOTTOM, header->name, header->value);
67 }
68 }
69 switch_event_fire(&report);
70 }
71 }
72
event_handler(switch_event_t * event)73 static void event_handler(switch_event_t *event)
74 {
75 const char *dest_proto = switch_event_get_header(event, "dest_proto");
76 const char *check_failure = switch_event_get_header(event, "Delivery-Failure");
77 const char *check_nonblocking = switch_event_get_header(event, "Nonblocking-Delivery");
78
79 switch_event_add_header(event, SWITCH_STACK_BOTTOM, "skip_global_process", "true");
80
81 if (switch_true(check_failure)) {
82
83 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Delivery Failure\n");
84 DUMP_EVENT(event);
85 send_report(event, "Failure");
86 return;
87 } else if ( check_failure && switch_false(check_failure) ) {
88 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "SMS Delivery Success\n");
89 send_report(event, "Success");
90 return;
91 } else if ( check_nonblocking && switch_true(check_nonblocking) ) {
92 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "SMS Delivery assumed successful due to being sent in non-blocking manner\n");
93 send_report(event, "Accepted");
94 return;
95 }
96
97 switch_core_chat_send(dest_proto, event);
98 }
99
100 typedef enum {
101 BREAK_ON_TRUE,
102 BREAK_ON_FALSE,
103 BREAK_ALWAYS,
104 BREAK_NEVER
105 } break_t;
106
107
108 #define check_tz() \
109 do { \
110 tzoff = switch_event_get_header(event, "tod_tz_offset"); \
111 tzname_ = switch_event_get_header(event, "timezone"); \
112 if (!zstr(tzoff) && switch_is_number(tzoff)) { \
113 offset = atoi(tzoff); \
114 break; \
115 } else { \
116 tzoff = NULL; \
117 } \
118 } while(tzoff)
119
parse_exten(switch_event_t * event,switch_xml_t xexten,switch_event_t ** extension)120 static int parse_exten(switch_event_t *event, switch_xml_t xexten, switch_event_t **extension)
121 {
122 switch_xml_t xcond, xaction, xexpression;
123 char *exten_name = (char *) switch_xml_attr(xexten, "name");
124 int proceed = 0;
125 char *expression_expanded = NULL, *field_expanded = NULL;
126 switch_regex_t *re = NULL;
127 const char *to = switch_event_get_header(event, "to");
128 const char *tzoff = NULL, *tzname_ = NULL;
129 int offset = 0;
130
131 check_tz();
132
133 if (!to) {
134 to = "nobody";
135 }
136
137 if (!exten_name) {
138 exten_name = "_anon_";
139 }
140
141 for (xcond = switch_xml_child(xexten, "condition"); xcond; xcond = xcond->next) {
142 char *field = NULL;
143 char *do_break_a = NULL;
144 char *expression = NULL;
145 const char *field_data = NULL;
146 int ovector[30];
147 switch_bool_t anti_action = SWITCH_TRUE;
148 break_t do_break_i = BREAK_ON_FALSE;
149 int time_match;
150
151 check_tz();
152 time_match = switch_xml_std_datetime_check(xcond, tzoff ? &offset : NULL, tzname_);
153
154 switch_safe_free(field_expanded);
155 switch_safe_free(expression_expanded);
156
157 if (switch_xml_child(xcond, "condition")) {
158 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Nested conditions are not allowed!\n");
159 proceed = 1;
160 goto done;
161 }
162
163 field = (char *) switch_xml_attr(xcond, "field");
164
165 if ((xexpression = switch_xml_child(xcond, "expression"))) {
166 expression = switch_str_nil(xexpression->txt);
167 } else {
168 expression = (char *) switch_xml_attr_soft(xcond, "expression");
169 }
170
171 if ((expression_expanded = switch_event_expand_headers(event, expression)) == expression) {
172 expression_expanded = NULL;
173 } else {
174 expression = expression_expanded;
175 }
176
177 if ((do_break_a = (char *) switch_xml_attr(xcond, "break"))) {
178 if (!strcasecmp(do_break_a, "on-true")) {
179 do_break_i = BREAK_ON_TRUE;
180 } else if (!strcasecmp(do_break_a, "on-false")) {
181 do_break_i = BREAK_ON_FALSE;
182 } else if (!strcasecmp(do_break_a, "always")) {
183 do_break_i = BREAK_ALWAYS;
184 } else if (!strcasecmp(do_break_a, "never")) {
185 do_break_i = BREAK_NEVER;
186 } else {
187 do_break_a = NULL;
188 }
189 }
190
191 if (time_match == 1) {
192 switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG,
193 "Chatplan: %s Date/Time Match (PASS) [%s] break=%s\n",
194 to, exten_name, do_break_a ? do_break_a : "on-false");
195 anti_action = SWITCH_FALSE;
196 } else if (time_match == 0) {
197 switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG,
198 "Chatplan: %s Date/Time Match (FAIL) [%s] break=%s\n",
199 to, exten_name, do_break_a ? do_break_a : "on-false");
200 }
201
202 if (field) {
203 if (strchr(field, '$')) {
204 if ((field_expanded = switch_event_expand_headers(event, field)) == field) {
205 field_expanded = NULL;
206 field_data = field;
207 } else {
208 field_data = field_expanded;
209 }
210 } else {
211 field_data = switch_event_get_header(event, field);
212 }
213 if (!field_data) {
214 field_data = "";
215 }
216
217 if ((proceed = switch_regex_perform(field_data, expression, &re, ovector, sizeof(ovector) / sizeof(ovector[0])))) {
218 switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG,
219 "Chatplan: %s Regex (PASS) [%s] %s(%s) =~ /%s/ break=%s\n",
220 to, exten_name, field, field_data, expression, do_break_a ? do_break_a : "on-false");
221 anti_action = SWITCH_FALSE;
222 } else {
223 switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG,
224 "Chatplan: %s Regex (FAIL) [%s] %s(%s) =~ /%s/ break=%s\n",
225 to, exten_name, field, field_data, expression, do_break_a ? do_break_a : "on-false");
226 }
227 } else if (time_match == -1) {
228 switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG,
229 "Chatplan: %s Absolute Condition [%s]\n", to, exten_name);
230 anti_action = SWITCH_FALSE;
231 }
232
233 if (anti_action) {
234 for (xaction = switch_xml_child(xcond, "anti-action"); xaction; xaction = xaction->next) {
235 const char *application = switch_xml_attr_soft(xaction, "application");
236 const char *loop = switch_xml_attr(xaction, "loop");
237 const char *data;
238 const char *inline_ = switch_xml_attr_soft(xaction, "inline");
239 int xinline = switch_true(inline_);
240 int loop_count = 1;
241
242 if (!zstr(xaction->txt)) {
243 data = xaction->txt;
244 } else {
245 data = (char *) switch_xml_attr_soft(xaction, "data");
246 }
247
248 if (!*extension) {
249 if ((switch_event_create(extension, SWITCH_EVENT_CLONE)) != SWITCH_STATUS_SUCCESS) {
250 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Memory Error!\n");
251 abort();
252 }
253 }
254
255 if (loop) {
256 loop_count = atoi(loop);
257 }
258
259 for (;loop_count > 0; loop_count--) {
260 switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG,
261 "Chatplan: %s ANTI-Action %s(%s) %s\n", to, application, data, xinline ? "INLINE" : "");
262
263 if (xinline) {
264 switch_core_execute_chat_app(event, application, data);
265 } else {
266 switch_event_add_header_string(*extension, SWITCH_STACK_BOTTOM, application, zstr(data) ? "__undef" : data);
267 }
268 }
269 proceed = 1;
270 }
271 } else {
272 if (field && strchr(expression, '(')) {
273 switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "DP_MATCH", NULL);
274 switch_capture_regex(re, proceed, field_data, ovector, "DP_MATCH", switch_regex_set_event_header_callback, event);
275 }
276
277 for (xaction = switch_xml_child(xcond, "action"); xaction; xaction = xaction->next) {
278 char *application = (char *) switch_xml_attr_soft(xaction, "application");
279 const char *loop = switch_xml_attr(xaction, "loop");
280 char *data = NULL;
281 char *substituted = NULL;
282 uint32_t len = 0;
283 char *app_data = NULL;
284 const char *inline_ = switch_xml_attr_soft(xaction, "inline");
285 int xinline = switch_true(inline_);
286 int loop_count = 1;
287
288 if (!zstr(xaction->txt)) {
289 data = xaction->txt;
290 } else {
291 data = (char *) switch_xml_attr_soft(xaction, "data");
292 }
293
294 if (field && strchr(expression, '(')) {
295 len = (uint32_t) (strlen(data) + strlen(field_data) + 10) * proceed;
296 if (!(substituted = (char *) malloc(len))) {
297 abort();
298 }
299 memset(substituted, 0, len);
300 switch_perform_substitution(re, proceed, data, field_data, substituted, len, ovector);
301 app_data = substituted;
302 } else {
303 app_data = data;
304 }
305
306 if (!*extension) {
307 if ((switch_event_create(extension, SWITCH_EVENT_CLONE)) != SWITCH_STATUS_SUCCESS) {
308 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Memory Error!\n");
309 abort();
310 }
311 }
312
313 if (loop) {
314 loop_count = atoi(loop);
315 }
316 for (;loop_count > 0; loop_count--) {
317 switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG,
318 "Chatplan: %s Action %s(%s) %s\n", to, application, app_data, xinline ? "INLINE" : "");
319
320 if (xinline) {
321 switch_core_execute_chat_app(event, application, app_data);
322 } else {
323 switch_event_add_header_string(*extension, SWITCH_STACK_BOTTOM, application, zstr(app_data) ? "__undef" : app_data);
324 }
325 }
326 switch_safe_free(substituted);
327 }
328 }
329 switch_regex_safe_free(re);
330
331 if (((anti_action == SWITCH_FALSE && do_break_i == BREAK_ON_TRUE) ||
332 (anti_action == SWITCH_TRUE && do_break_i == BREAK_ON_FALSE)) || do_break_i == BREAK_ALWAYS) {
333 break;
334 }
335 }
336
337 done:
338 switch_regex_safe_free(re);
339 switch_safe_free(field_expanded);
340 switch_safe_free(expression_expanded);
341 return proceed;
342 }
343
344
chatplan_hunt(switch_event_t * event)345 static switch_event_t *chatplan_hunt(switch_event_t *event)
346 {
347 switch_event_t *extension = NULL;
348 switch_xml_t alt_root = NULL, cfg, xml = NULL, xcontext, xexten = NULL;
349 const char *alt_path;
350 const char *context;
351 const char *from;
352 const char *to;
353
354 if (!(context = switch_event_get_header(event, "context"))) {
355 context = "default";
356 }
357
358 if (!(from = switch_event_get_header(event, "from_user"))) {
359 from = switch_event_get_header(event, "from");
360 }
361
362 if (!(to = switch_event_get_header(event, "to_user"))) {
363 to = switch_event_get_header(event, "to");
364 }
365
366 alt_path = switch_event_get_header(event, "alt_path");
367
368 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Processing text message %s->%s in context %s\n", from, to, context);
369
370 /* get our handle to the "chatplan" section of the config */
371
372 if (!zstr(alt_path)) {
373 switch_xml_t conf = NULL, tag = NULL;
374 if (!(alt_root = switch_xml_parse_file_simple(alt_path))) {
375 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Open of [%s] failed\n", alt_path);
376 goto done;
377 }
378
379 if ((conf = switch_xml_find_child(alt_root, "section", "name", "chatplan")) && (tag = switch_xml_find_child(conf, "chatplan", NULL, NULL))) {
380 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Getting chatplan from alternate path: %s\n", alt_path);
381 xml = alt_root;
382 cfg = tag;
383 } else {
384 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Open of chatplan failed\n");
385 goto done;
386 }
387 } else {
388 if (switch_xml_locate("chatplan", NULL, NULL, NULL, &xml, &cfg, event, SWITCH_FALSE) != SWITCH_STATUS_SUCCESS) {
389 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Open of chatplan failed\n");
390 goto done;
391 }
392 }
393
394 /* get a handle to the context tag */
395 if (!(xcontext = switch_xml_find_child(cfg, "context", "name", context))) {
396 if (!(xcontext = switch_xml_find_child(cfg, "context", "name", "global"))) {
397 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Context %s not found\n", context);
398 goto done;
399 }
400 }
401
402 xexten = switch_xml_child(xcontext, "extension");
403
404 while (xexten) {
405 int proceed = 0;
406 const char *cont = switch_xml_attr(xexten, "continue");
407 const char *exten_name = switch_xml_attr(xexten, "name");
408
409 if (!exten_name) {
410 exten_name = "UNKNOWN";
411 }
412
413 switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG,
414 "Chatplan: %s parsing [%s->%s] continue=%s\n",
415 to, context, exten_name, cont ? cont : "false");
416
417 proceed = parse_exten(event, xexten, &extension);
418
419 if (proceed && !switch_true(cont)) {
420 break;
421 }
422
423 xexten = xexten->next;
424 }
425
426 switch_xml_free(xml);
427 xml = NULL;
428
429 done:
430 switch_xml_free(xml);
431 return extension;
432 }
433
434
chat_send(switch_event_t * message_event)435 static switch_status_t chat_send(switch_event_t *message_event)
436 {
437 switch_status_t status = SWITCH_STATUS_BREAK;
438 switch_event_t *exten;
439 int forwards = 0;
440 const char *var;
441
442 var = switch_event_get_header(message_event, "max_forwards");
443
444 if (!var) {
445 forwards = 70;
446 } else {
447 forwards = atoi(var);
448
449 if (forwards) {
450 forwards--;
451 }
452
453 if (!forwards) {
454 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Max forwards reached\n");
455 DUMP_EVENT(message_event);
456 return SWITCH_STATUS_FALSE;
457 }
458 }
459
460 if (forwards) {
461 switch_event_add_header(message_event, SWITCH_STACK_BOTTOM, "max_forwards", "%d", forwards);
462 }
463
464 if ((exten = chatplan_hunt(message_event))) {
465 switch_event_header_t *hp;
466
467 for (hp = exten->headers; hp; hp = hp->next) {
468 status = switch_core_execute_chat_app(message_event, hp->name, hp->value);
469 if (!SWITCH_READ_ACCEPTABLE(status)) {
470 status = SWITCH_STATUS_SUCCESS;
471 break;
472 }
473 }
474
475 switch_event_destroy(&exten);
476 } else {
477 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "SMS chatplan no actions found\n");
478 }
479
480 return status;
481
482 }
483
SWITCH_STANDARD_CHAT_APP(info_function)484 SWITCH_STANDARD_CHAT_APP(info_function)
485 {
486 char *buf;
487 int level = SWITCH_LOG_INFO;
488
489 if (!zstr(data)) {
490 level = switch_log_str2level(data);
491 }
492
493 switch_event_serialize(message, &buf, SWITCH_FALSE);
494 switch_assert(buf);
495 switch_log_printf(SWITCH_CHANNEL_LOG, level, "CHANNEL_DATA:\n%s\n", buf);
496 free(buf);
497
498 return SWITCH_STATUS_SUCCESS;
499 }
500
SWITCH_STANDARD_CHAT_APP(system_function)501 SWITCH_STANDARD_CHAT_APP(system_function)
502 {
503 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Executing command: %s\n", data);
504 if (switch_system(data, SWITCH_TRUE) < 0) {
505 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Failed to execute command: %s\n", data);
506 return SWITCH_STATUS_FALSE;
507 }
508 return SWITCH_STATUS_SUCCESS;
509 }
510
SWITCH_STANDARD_CHAT_APP(stop_function)511 SWITCH_STANDARD_CHAT_APP(stop_function)
512 {
513 switch_set_flag(message, EF_NO_CHAT_EXEC);
514 return SWITCH_STATUS_FALSE;
515 }
516
SWITCH_STANDARD_CHAT_APP(send_function)517 SWITCH_STANDARD_CHAT_APP(send_function)
518 {
519 const char *dest_proto = data;
520
521 if (zstr(dest_proto)) {
522 dest_proto = switch_event_get_header(message, "dest_proto");
523 }
524
525 switch_event_add_header(message, SWITCH_STACK_BOTTOM, "skip_global_process", "true");
526
527 switch_core_chat_send(dest_proto, message);
528
529 return SWITCH_STATUS_SUCCESS;
530 }
531
SWITCH_STANDARD_CHAT_APP(set_function)532 SWITCH_STANDARD_CHAT_APP(set_function)
533 {
534 char *var, *val;
535
536 if (!data) return SWITCH_STATUS_SUCCESS;
537
538 var = strdup(data);
539
540 if (!var) return SWITCH_STATUS_SUCCESS;
541
542 if ((val = strchr(var, '='))) {
543 *val++ = '\0';
544 }
545
546 if (zstr(val)) {
547 switch_event_del_header(message, var);
548 } else {
549 switch_event_add_header_string(message, SWITCH_STACK_BOTTOM, var, val);
550 }
551
552 free(var);
553
554 return SWITCH_STATUS_SUCCESS;
555 }
556
SWITCH_STANDARD_CHAT_APP(unset_function)557 SWITCH_STANDARD_CHAT_APP(unset_function)
558 {
559 char *var;
560
561 if (!data) return SWITCH_STATUS_SUCCESS;
562
563 var = strdup(data);
564
565 if (!var) return SWITCH_STATUS_SUCCESS;
566
567 if (!zstr(var)) {
568 switch_event_del_header(message, var);
569 }
570
571 free(var);
572
573 return SWITCH_STATUS_SUCCESS;
574 }
575
SWITCH_STANDARD_CHAT_APP(fire_function)576 SWITCH_STANDARD_CHAT_APP(fire_function)
577 {
578 switch_event_t *fireme;
579
580 switch_event_dup(&fireme, message);
581 switch_event_fire(&fireme);
582
583 return SWITCH_STATUS_SUCCESS;
584 }
585
SWITCH_STANDARD_CHAT_APP(reply_function)586 SWITCH_STANDARD_CHAT_APP(reply_function)
587 {
588 switch_event_t *reply;
589 const char *proto = switch_event_get_header(message, "proto");
590
591 if (proto) {
592 switch_ivr_create_message_reply(&reply, message, SMS_CHAT_PROTO);
593
594 if (!zstr(data)) {
595 switch_event_set_body(reply, data);
596 }
597
598 switch_core_chat_deliver(proto, &reply);
599
600 return SWITCH_STATUS_SUCCESS;
601 }
602
603 return SWITCH_STATUS_SUCCESS;
604 }
605
606 /* Macro expands to: switch_status_t mod_sms_load(switch_loadable_module_interface_t **module_interface, switch_memory_pool_t *pool) */
SWITCH_MODULE_LOAD_FUNCTION(mod_sms_load)607 SWITCH_MODULE_LOAD_FUNCTION(mod_sms_load)
608 {
609 switch_chat_interface_t *chat_interface;
610 switch_chat_application_interface_t *chat_app_interface;
611
612 if (switch_event_reserve_subclass(MY_EVENT_DELIVERY_REPORT) != SWITCH_STATUS_SUCCESS) {
613 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't register subclass %s!\n", MY_EVENT_DELIVERY_REPORT);
614 return SWITCH_STATUS_TERM;
615 }
616
617 if (switch_event_bind(modname, SWITCH_EVENT_CUSTOM, MY_EVENT_SEND_MESSAGE, event_handler, NULL) != SWITCH_STATUS_SUCCESS) {
618 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't bind!\n");
619 return SWITCH_STATUS_GENERR;
620 }
621
622 /* connect my internal structure to the blank pointer passed to me */
623 *module_interface = switch_loadable_module_create_module_interface(pool, modname);
624
625 SWITCH_ADD_CHAT(chat_interface, SMS_CHAT_PROTO, chat_send);
626
627 SWITCH_ADD_CHAT_APP(chat_app_interface, "info", "Display Call Info", "Display Call Info", info_function, "", SCAF_NONE);
628 SWITCH_ADD_CHAT_APP(chat_app_interface, "reply", "reply to a message", "reply to a message", reply_function, "", SCAF_NONE);
629 SWITCH_ADD_CHAT_APP(chat_app_interface, "stop", "stop execution", "stop execution", stop_function, "", SCAF_NONE);
630 SWITCH_ADD_CHAT_APP(chat_app_interface, "set", "set a variable", "set a variable", set_function, "", SCAF_NONE);
631 SWITCH_ADD_CHAT_APP(chat_app_interface, "unset", "unset a variable", "unset a variable", unset_function, "", SCAF_NONE);
632 SWITCH_ADD_CHAT_APP(chat_app_interface, "send", "send the message as-is", "send the message as-is", send_function, "", SCAF_NONE);
633 SWITCH_ADD_CHAT_APP(chat_app_interface, "fire", "fire the message", "fire the message", fire_function, "", SCAF_NONE);
634 SWITCH_ADD_CHAT_APP(chat_app_interface, "system", "execute a system command", "execute a sytem command", system_function, "", SCAF_NONE);
635
636 /* indicate that the module should continue to be loaded */
637 return SWITCH_STATUS_SUCCESS;
638 }
639
640 /*
641 Called when the system shuts down
642 Macro expands to: switch_status_t mod_sms_shutdown() */
SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_sms_shutdown)643 SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_sms_shutdown)
644 {
645 switch_event_unbind_callback(event_handler);
646
647 switch_event_free_subclass(MY_EVENT_DELIVERY_REPORT);
648
649 return SWITCH_STATUS_SUCCESS;
650 }
651
652
653
654
655 /* For Emacs:
656 * Local Variables:
657 * mode:c
658 * indent-tabs-mode:t
659 * tab-width:4
660 * c-basic-offset:4
661 * End:
662 * For VIM:
663 * vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet
664 */
665