1 /*
2 * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
3 * Copyright (C) 2005-2012, 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 * Andrew Thompson <andrew@hijacked.us>
28 * Rob Charlton <rob.charlton@savageminds.com>
29 * Karl Anderson <karl@2600hz.com>
30 *
31 * Original from mod_erlang_event.
32 * ei_helpers.c -- helper functions for ei
33 *
34 */
35 #include "mod_kazoo.h"
36
37 #define kz_resize(l) {\
38 char *dp;\
39 olen += (len + l + block);\
40 cpos = c - data;\
41 if ((dp = realloc(data, olen))) {\
42 data = dp;\
43 c = data + cpos;\
44 memset(c, 0, olen - cpos);\
45 }} \
46
47
kz_check_set_profile_var(switch_channel_t * channel,char * var,char * val)48 void kz_check_set_profile_var(switch_channel_t *channel, char* var, char *val)
49 {
50 int idx = 0;
51 while(kazoo_globals.profile_vars_prefixes[idx] != NULL) {
52 char *prefix = kazoo_globals.profile_vars_prefixes[idx];
53 if (!strncasecmp(var, prefix, strlen(prefix))) {
54 switch_channel_set_profile_var(channel, var + strlen(prefix), val);
55
56 }
57 idx++;
58 }
59 }
60
kz_switch_core_merge_variables(switch_event_t * event)61 SWITCH_DECLARE(switch_status_t) kz_switch_core_merge_variables(switch_event_t *event)
62 {
63 switch_event_t *global_vars;
64 switch_status_t status = switch_core_get_variables(&global_vars);
65 if(status == SWITCH_STATUS_SUCCESS) {
66 switch_event_merge(event, global_vars);
67 switch_event_destroy(&global_vars);
68 }
69 return status;
70 }
71
kz_switch_core_base_headers_for_expand(switch_event_t ** event)72 SWITCH_DECLARE(switch_status_t) kz_switch_core_base_headers_for_expand(switch_event_t **event)
73 {
74 switch_status_t status = SWITCH_STATUS_GENERR;
75 *event = NULL;
76 if(switch_event_create(event, SWITCH_EVENT_GENERAL) == SWITCH_STATUS_SUCCESS) {
77 status = kz_switch_core_merge_variables(*event);
78 }
79 return status;
80 }
81
kz_expand_api_execute(const char * cmd,const char * arg,switch_core_session_t * session,switch_stream_handle_t * stream)82 SWITCH_DECLARE(switch_status_t) kz_expand_api_execute(const char *cmd, const char *arg, switch_core_session_t *session, switch_stream_handle_t *stream)
83 {
84 switch_api_interface_t *api;
85 switch_status_t status;
86 char *arg_used;
87 char *cmd_used;
88
89 switch_assert(stream != NULL);
90 switch_assert(stream->data != NULL);
91 switch_assert(stream->write_function != NULL);
92
93 cmd_used = switch_strip_whitespace(cmd);
94 arg_used = switch_strip_whitespace(arg);
95
96 if (cmd_used && (api = switch_loadable_module_get_api_interface(cmd_used)) != 0) {
97 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG1, "executing [%s] => [%s]\n", cmd_used, arg_used);
98 if ((status = api->function(arg_used, session, stream)) != SWITCH_STATUS_SUCCESS) {
99 stream->write_function(stream, "COMMAND RETURNED ERROR!\n");
100 }
101 UNPROTECT_INTERFACE(api);
102 } else {
103 status = SWITCH_STATUS_FALSE;
104 stream->write_function(stream, "INVALID COMMAND!\n");
105 }
106
107 if (cmd_used != cmd) {
108 switch_safe_free(cmd_used);
109 }
110
111 if (arg_used != arg) {
112 switch_safe_free(arg_used);
113 }
114
115 return status;
116 }
117
118
kz_event_expand_headers_check(switch_event_t * event,const char * in,switch_event_t * var_list,switch_event_t * api_list,uint32_t recur)119 SWITCH_DECLARE(char *) kz_event_expand_headers_check(switch_event_t *event, const char *in, switch_event_t *var_list, switch_event_t *api_list, uint32_t recur)
120 {
121 char *p, *c = NULL;
122 char *data, *indup, *endof_indup;
123 size_t sp = 0, len = 0, olen = 0, vtype = 0, br = 0, cpos, block = 128;
124 const char *sub_val = NULL;
125 char *cloned_sub_val = NULL, *expanded_sub_val = NULL;
126 char *func_val = NULL;
127 int nv = 0;
128 char *gvar = NULL, *sb = NULL;
129
130 if (recur > 100) {
131 return (char *) in;
132 }
133
134 if (zstr(in)) {
135 return (char *) in;
136 }
137
138 nv = switch_string_var_check_const(in) || switch_string_has_escaped_data(in);
139
140 if (!nv) {
141 return (char *) in;
142 }
143
144 nv = 0;
145 olen = strlen(in) + 1;
146 indup = strdup(in);
147 switch_assert(indup);
148 endof_indup = end_of_p(indup) + 1;
149
150 if ((data = malloc(olen))) {
151 memset(data, 0, olen);
152 c = data;
153 for (p = indup; p && p < endof_indup && *p; p++) {
154 int global = 0;
155 vtype = 0;
156
157 if (*p == '\\') {
158 if (*(p + 1) == '$') {
159 nv = 1;
160 p++;
161 if (*(p + 1) == '$') {
162 p++;
163 }
164 } else if (*(p + 1) == '\'') {
165 p++;
166 continue;
167 } else if (*(p + 1) == '\\') {
168 if (len + 1 >= olen) {
169 kz_resize(1);
170 }
171
172 *c++ = *p++;
173 len++;
174 continue;
175 }
176 }
177
178 if (*p == '$' && !nv) {
179 if (*(p + 1) == '$') {
180 p++;
181 global++;
182 }
183
184 if (*(p + 1)) {
185 if (*(p + 1) == '{') {
186 vtype = global ? 3 : 1;
187 } else {
188 nv = 1;
189 }
190 } else {
191 nv = 1;
192 }
193 }
194
195 if (nv) {
196 if (len + 1 >= olen) {
197 kz_resize(1);
198 }
199
200 *c++ = *p;
201 len++;
202 nv = 0;
203 continue;
204 }
205
206 if (vtype) {
207 char *s = p, *e, *vname, *vval = NULL;
208 size_t nlen;
209
210 s++;
211
212 if ((vtype == 1 || vtype == 3) && *s == '{') {
213 br = 1;
214 s++;
215 }
216
217 e = s;
218 vname = s;
219 while (*e) {
220 if (br == 1 && *e == '}') {
221 br = 0;
222 *e++ = '\0';
223 break;
224 }
225
226 if (br > 0) {
227 if (e != s && *e == '{') {
228 br++;
229 } else if (br > 1 && *e == '}') {
230 br--;
231 }
232 }
233
234 e++;
235 }
236 p = e > endof_indup ? endof_indup : e;
237
238 vval = NULL;
239 for(sb = vname; sb && *sb; sb++) {
240 if (*sb == ' ') {
241 vval = sb;
242 break;
243 } else if (*sb == '(') {
244 vval = sb;
245 br = 1;
246 break;
247 }
248 }
249
250 if (vval) {
251 e = vval - 1;
252 *vval++ = '\0';
253
254 while (*e == ' ') {
255 *e-- = '\0';
256 }
257 e = vval;
258
259 while (e && *e) {
260 if (*e == '(') {
261 br++;
262 } else if (br > 1 && *e == ')') {
263 br--;
264 } else if (br == 1 && *e == ')') {
265 *e = '\0';
266 break;
267 }
268 e++;
269 }
270
271 vtype = 2;
272 }
273
274 if (vtype == 1 || vtype == 3) {
275 char *expanded = NULL;
276 int offset = 0;
277 int ooffset = 0;
278 char *ptr;
279 int idx = -1;
280
281 if ((expanded = kz_event_expand_headers_check(event, (char *) vname, var_list, api_list, recur+1)) == vname) {
282 expanded = NULL;
283 } else {
284 vname = expanded;
285 }
286 if ((ptr = strchr(vname, ':'))) {
287 *ptr++ = '\0';
288 offset = atoi(ptr);
289 if ((ptr = strchr(ptr, ':'))) {
290 ptr++;
291 ooffset = atoi(ptr);
292 }
293 }
294
295 if ((ptr = strchr(vname, '[')) && strchr(ptr, ']')) {
296 *ptr++ = '\0';
297 idx = atoi(ptr);
298 }
299
300 if (vtype == 3 || !(sub_val = switch_event_get_header_idx(event, vname, idx))) {
301 switch_safe_free(gvar);
302 if ((gvar = switch_core_get_variable_dup(vname))) {
303 sub_val = gvar;
304 }
305
306 if (var_list && !switch_event_check_permission_list(var_list, vname)) {
307 sub_val = "<Variable Expansion Permission Denied>";
308 }
309
310
311 if ((expanded_sub_val = kz_event_expand_headers_check(event, sub_val, var_list, api_list, recur+1)) == sub_val) {
312 expanded_sub_val = NULL;
313 } else {
314 sub_val = expanded_sub_val;
315 }
316 }
317
318 if (sub_val) {
319 if (offset || ooffset) {
320 cloned_sub_val = strdup(sub_val);
321 switch_assert(cloned_sub_val);
322 sub_val = cloned_sub_val;
323 }
324
325 if (offset >= 0) {
326 sub_val += offset;
327 } else if ((size_t) abs(offset) <= strlen(sub_val)) {
328 sub_val = cloned_sub_val + (strlen(cloned_sub_val) + offset);
329 }
330
331 if (ooffset > 0 && (size_t) ooffset < strlen(sub_val)) {
332 if ((ptr = (char *) sub_val + ooffset)) {
333 *ptr = '\0';
334 }
335 }
336 }
337
338 switch_safe_free(expanded);
339 } else {
340 switch_stream_handle_t stream = { 0 };
341 char *expanded = NULL;
342 char *expanded_vname = NULL;
343
344 SWITCH_STANDARD_STREAM(stream);
345
346 if ((expanded_vname = kz_event_expand_headers_check(event, (char *) vname, var_list, api_list, recur+1)) == vname) {
347 expanded_vname = NULL;
348 } else {
349 vname = expanded_vname;
350 }
351
352 if ((expanded = kz_event_expand_headers_check(event, vval, var_list, api_list, recur+1)) == vval) {
353 expanded = NULL;
354 } else {
355 vval = expanded;
356 }
357
358 if (!switch_core_test_flag(SCF_API_EXPANSION) || (api_list && !switch_event_check_permission_list(api_list, vname))) {
359 func_val = NULL;
360 sub_val = "<API execute Permission Denied>";
361 } else {
362 stream.param_event = event;
363 if (kz_expand_api_execute(vname, vval, NULL, &stream) == SWITCH_STATUS_SUCCESS) {
364 func_val = stream.data;
365 sub_val = func_val;
366 } else {
367 free(stream.data);
368 }
369 }
370
371 switch_safe_free(expanded);
372 switch_safe_free(expanded_vname);
373 }
374 if ((nlen = sub_val ? strlen(sub_val) : 0)) {
375 if (len + nlen >= olen) {
376 kz_resize(nlen);
377 }
378
379 len += nlen;
380 strcat(c, sub_val);
381 c += nlen;
382 }
383
384 switch_safe_free(func_val);
385 switch_safe_free(cloned_sub_val);
386 switch_safe_free(expanded_sub_val);
387 sub_val = NULL;
388 vname = NULL;
389 br = 0;
390 }
391
392 if (sp) {
393 if (len + 1 >= olen) {
394 kz_resize(1);
395 }
396
397 *c++ = ' ';
398 sp = 0;
399 len++;
400 }
401
402 if (*p == '$') {
403 p--;
404 } else {
405 if (len + 1 >= olen) {
406 kz_resize(1);
407 }
408
409 *c++ = *p;
410 len++;
411 }
412 }
413 }
414 free(indup);
415 switch_safe_free(gvar);
416
417 return data;
418 }
419
kz_event_expand_headers(switch_event_t * event,const char * in)420 SWITCH_DECLARE(char *) kz_event_expand_headers(switch_event_t *event, const char *in)
421 {
422 return kz_event_expand_headers_check(event, in, NULL, NULL, 0);
423 }
424
kz_event_expand_headers_pool(switch_memory_pool_t * pool,switch_event_t * event,char * val)425 SWITCH_DECLARE(char *) kz_event_expand_headers_pool(switch_memory_pool_t *pool, switch_event_t *event, char *val)
426 {
427 char *expanded;
428 char *dup = NULL;
429
430 expanded = kz_event_expand_headers(event, val);
431 dup = switch_core_strdup(pool, expanded);
432
433 if (expanded != val) {
434 free(expanded);
435 }
436
437 return dup;
438 }
439
kz_expand(const char * in,const char * uuid)440 SWITCH_DECLARE(char *) kz_expand(const char *in, const char *uuid)
441 {
442 switch_event_t *event = NULL;
443 char *ret = NULL;
444 kz_switch_core_base_headers_for_expand(&event);
445 if (uuid != NULL) {
446 switch_core_session_t *nsession = NULL;
447 if ((nsession = switch_core_session_locate(uuid))) {
448 switch_channel_event_set_data(switch_core_session_get_channel(nsession), event);
449 switch_core_session_rwunlock(nsession);
450 }
451 }
452 ret = kz_event_expand_headers_check(event, in, NULL, NULL, 0);
453 switch_event_destroy(&event);
454 return ret;
455 }
456
kz_expand_pool(switch_memory_pool_t * pool,const char * in)457 SWITCH_DECLARE(char *) kz_expand_pool(switch_memory_pool_t *pool, const char *in)
458 {
459 char *expanded;
460 char *dup = NULL;
461
462 if(!(expanded = kz_expand(in, NULL))) {
463 return NULL;
464 }
465 dup = switch_core_strdup(pool, expanded);
466
467 if (expanded != in) {
468 switch_safe_free(expanded);
469 }
470
471 return dup;
472 }
473
kz_switch_event_get_first_of(switch_event_t * event,const char * list[])474 char* kz_switch_event_get_first_of(switch_event_t *event, const char *list[])
475 {
476 switch_event_header_t *header = NULL;
477 int i = 0;
478 while(list[i] != NULL) {
479 if((header = switch_event_get_header_ptr(event, list[i])) != NULL)
480 break;
481 i++;
482 }
483 if(header != NULL) {
484 return header->value;
485 } else {
486 return "nodomain";
487 }
488 }
489
kz_switch_event_add_variable_name_printf(switch_event_t * event,switch_stack_t stack,const char * val,const char * fmt,...)490 SWITCH_DECLARE(switch_status_t) kz_switch_event_add_variable_name_printf(switch_event_t *event, switch_stack_t stack, const char *val, const char *fmt, ...)
491 {
492 int ret = 0;
493 char *varname;
494 va_list ap;
495 switch_status_t status = SWITCH_STATUS_SUCCESS;
496
497 switch_assert(event != NULL);
498
499
500 va_start(ap, fmt);
501 ret = switch_vasprintf(&varname, fmt, ap);
502 va_end(ap);
503
504 if (ret == -1) {
505 return SWITCH_STATUS_MEMERR;
506 }
507
508 status = switch_event_add_header_string(event, stack, varname, val);
509
510 free(varname);
511
512 return status;
513 }
514
kz_expand_json_to_event(cJSON * json,switch_event_t * event,char * prefix)515 SWITCH_DECLARE(switch_status_t) kz_expand_json_to_event(cJSON *json, switch_event_t *event, char * prefix)
516 {
517 char * fmt = switch_mprintf("%s%s%%s", prefix ? prefix : "", prefix ? "_" : "");
518 if (event) {
519 cJSON *item = NULL;
520 char *response = NULL;
521 cJSON_ArrayForEach(item, json) {
522 if (item->type == cJSON_String) {
523 response = strdup(item->valuestring);
524 } else if (item->type == cJSON_Object) {
525 char * fmt1 = switch_mprintf(fmt, item->string);
526 kz_expand_json_to_event(item, event, fmt1);
527 switch_safe_free(fmt1);
528 continue;
529 } else {
530 response = cJSON_PrintUnformatted(item);
531 }
532 kz_switch_event_add_variable_name_printf(event, SWITCH_STACK_BOTTOM, response, fmt, item->string);
533 switch_safe_free(response);
534 }
535 }
536
537 switch_safe_free(fmt);
538 return SWITCH_STATUS_SUCCESS;
539 }
540
kz_xml_child(switch_xml_t xml,const char * name)541 SWITCH_DECLARE(switch_xml_t) kz_xml_child(switch_xml_t xml, const char *name)
542 {
543 xml = (xml) ? xml->child : NULL;
544 while (xml && strcasecmp(name, xml->name))
545 xml = xml->sibling;
546 return xml;
547 }
548
kz_xml_process(switch_xml_t cfg)549 void kz_xml_process(switch_xml_t cfg)
550 {
551 switch_xml_t xml_process;
552 for (xml_process = kz_xml_child(cfg, "X-PRE-PROCESS"); xml_process; xml_process = xml_process->next) {
553 const char *cmd = switch_xml_attr(xml_process, "cmd");
554 const char *data = switch_xml_attr(xml_process, "data");
555 if(cmd != NULL && !strcasecmp(cmd, "set") && data) {
556 char *name = (char *) data;
557 char *val = strchr(name, '=');
558
559 if (val) {
560 char *ve = val++;
561 while (*val && *val == ' ') {
562 val++;
563 }
564 *ve-- = '\0';
565 while (*ve && *ve == ' ') {
566 *ve-- = '\0';
567 }
568 }
569
570 if (name && val) {
571 switch_core_set_variable(name, val);
572 }
573 }
574 }
575
576 }
577
kz_event_decode(switch_event_t * event)578 void kz_event_decode(switch_event_t *event)
579 {
580 switch_event_header_t *hp;
581 int i;
582 for (hp = event->headers; hp; hp = hp->next) {
583 if (strncmp(hp->name, "_json_", 6)) {
584 if (hp->idx) {
585 for(i = 0; i < hp->idx; i++) {
586 switch_url_decode(hp->array[i]);
587 }
588 } else {
589 switch_url_decode(hp->value);
590 }
591 }
592 }
593 }
594
kz_expand_headers(switch_event_t * resolver,switch_event_t * event)595 void kz_expand_headers(switch_event_t *resolver, switch_event_t *event) {
596 switch_event_t *clone = NULL;
597 switch_event_header_t *header = NULL;
598 switch_event_create_plain(&clone, event->event_id);
599
600 for(header = event->headers; header; header = header->next) {
601 char *expanded = kz_event_expand_headers(resolver, header->value);
602 if (expanded != header->value) {
603 switch_event_add_header_string(clone, SWITCH_STACK_BOTTOM, header->name, expanded);
604 switch_safe_free(expanded);
605 }
606 }
607
608 /* we don't want to force unique headers
609 * so we delete and then merge
610 */
611 for(header = clone->headers; header; header = header->next) {
612 switch_event_del_header(event, header->name);
613 }
614
615 switch_event_merge(event, clone);
616
617 switch_event_destroy(&clone);
618 }
619
kz_expand_headers_self(switch_event_t * event)620 void kz_expand_headers_self(switch_event_t *event) {
621 kz_expand_headers(event, event);
622 }
623
kz_expand_vars(char * xml_str)624 char * kz_expand_vars(char *xml_str) {
625 return kz_expand_vars_pool(xml_str, NULL);
626 }
627
kz_expand_vars_pool(char * xml_str,switch_memory_pool_t * pool)628 char * kz_expand_vars_pool(char *xml_str, switch_memory_pool_t *pool) {
629 char *var, *val;
630 char *rp = xml_str; /* read pointer */
631 char *ep, *wp, *buff; /* end pointer, write pointer, write buffer */
632
633 if (!(strstr(xml_str, "$${"))) {
634 return xml_str;
635 }
636
637 switch_zmalloc(buff, strlen(xml_str) * 2);
638 wp = buff;
639 ep = buff + (strlen(xml_str) * 2) - 1;
640
641 while (*rp && wp < ep) {
642 if (*rp == '$' && *(rp + 1) == '$' && *(rp + 2) == '{') {
643 char *e = switch_find_end_paren(rp + 2, '{', '}');
644
645 if (e) {
646 rp += 3;
647 var = rp;
648 *e++ = '\0';
649 rp = e;
650
651 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "trying to expand %s \n", var);
652 if ((val = switch_core_get_variable_dup(var))) {
653 char *p;
654 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "expanded %s to %s\n", var, val);
655 for (p = val; p && *p && wp <= ep; p++) {
656 *wp++ = *p;
657 }
658 switch_safe_free(val);
659 }
660 continue;
661 }
662 }
663
664 *wp++ = *rp++;
665 }
666
667 *wp++ = '\0';
668
669 if(pool) {
670 char * ret = switch_core_strdup(pool, buff);
671 switch_safe_free(buff);
672 return ret;
673 } else {
674 switch_safe_free(xml_str);
675 return buff;
676 }
677
678 }
679
kz_json_api(const char * command,cJSON * args,cJSON ** res)680 switch_status_t kz_json_api(const char * command, cJSON *args, cJSON **res)
681 {
682 switch_status_t status = SWITCH_STATUS_SUCCESS;
683 cJSON *req = cJSON_CreateObject();
684 cJSON_AddItemToObject(req, "command", cJSON_CreateString(command));
685 cJSON_AddItemToObject(req, "data", args ? args : cJSON_CreateObject());
686 status = switch_json_api_execute(req, NULL, res);
687 cJSON_Delete(req);
688 return status;
689 }
690
691 /* For Emacs:
692 * Local Variables:
693 * mode:c
694 * indent-tabs-mode:t
695 * tab-width:4
696 * c-basic-offset:4
697 * End:
698 * For VIM:
699 * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
700 */
701