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