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  * Karl Anderson <karl@2600hz.com>
27  * Darren Schreiber <darren@2600hz.com>
28  *
29  *
30  * kazoo_dptools.c -- clones of mod_dptools commands slightly modified for kazoo
31  *
32  */
33 #include "mod_kazoo.h"
34 
35 #define SET_SHORT_DESC "Set a channel variable"
36 #define SET_LONG_DESC "Set a channel variable for the channel calling the application."
37 #define SET_SYNTAX "<varname>=<value>"
38 
39 #define MULTISET_SHORT_DESC "Set many channel variables"
40 #define MULTISET_LONG_DESC "Set many channel variables for the channel calling the application"
41 #define MULTISET_SYNTAX "[^^<delim>]<varname>=<value> <var2>=<val2>"
42 
43 #define UNSET_SHORT_DESC "Unset a channel variable"
44 #define UNSET_LONG_DESC "Unset a channel variable for the channel calling the application."
45 #define UNSET_SYNTAX "<varname>"
46 
47 #define MULTIUNSET_SHORT_DESC "Unset many channel variables"
48 #define MULTIUNSET_LONG_DESC "Unset many channel variables for the channel calling the application."
49 #define MULTIUNSET_SYNTAX "[^^<delim>]<varname> <var2> <var3>"
50 
51 #define EXPORT_SHORT_DESC "Export many channel variables"
52 #define EXPORT_LONG_DESC "Export many channel variables for the channel calling the application"
53 #define EXPORT_SYNTAX "[^^<delim>]<varname>=<value> <var2>=<val2>"
54 
55 #define PREFIX_UNSET_SHORT_DESC "clear variables by prefix"
56 #define PREFIX_UNSET_LONG_DESC "clears the channel variables that start with prefix supplied"
57 #define PREFIX_UNSET_SYNTAX "<prefix>"
58 
59 #define UUID_MULTISET_SHORT_DESC "Set many channel variables"
60 #define UUID_MULTISET_LONG_DESC "Set many channel variables for a specific channel"
61 #define UUID_MULTISET_SYNTAX "<uuid> [^^<delim>]<varname>=<value> <var2>=<val2>"
62 
63 #define KZ_ENDLESS_PLAYBACK_SHORT_DESC "Playback File Endlessly until break"
64 #define KZ_ENDLESS_PLAYBACK_LONG_DESC "Endlessly Playback a file to the channel until a break occurs"
65 #define KZ_ENDLESS_PLAYBACK_SYNTAX "<path>"
66 
67 #define NOOP_SHORT_DESC "no operation"
68 #define NOOP_LONG_DESC "no operation. serves as a control point"
69 #define NOOP_SYNTAX "[<noop-id>]"
70 
base_set(switch_core_session_t * session,const char * data,int urldecode,switch_stack_t stack)71 static void base_set (switch_core_session_t *session, const char *data, int urldecode, switch_stack_t stack)
72 {
73 	char *var, *val = NULL;
74 
75 	if (zstr(data)) {
76 		switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "No variable name specified.\n");
77 	} else {
78 		switch_channel_t *channel = switch_core_session_get_channel(session);
79 		char *expanded = NULL;
80 
81 		var = switch_core_session_strdup(session, data);
82 
83 		if (!(val = strchr(var, '='))) {
84 			val = strchr(var, ',');
85 		}
86 
87 		if (val) {
88 			*val++ = '\0';
89 			if (zstr(val)) {
90 				val = NULL;
91 			}
92 		}
93 
94 		if (val) {
95 			if(urldecode) {
96 				switch_url_decode(val);
97 			}
98 			expanded = switch_channel_expand_variables(channel, val);
99 		}
100 
101 		switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "%s SET [%s]=[%s] => [%s]\n", switch_channel_get_name(channel), var, val,
102 						  expanded ? expanded : "UNDEF");
103 		switch_channel_add_variable_var_check(channel, var, expanded, SWITCH_FALSE, stack);
104 		kz_check_set_profile_var(channel, var, expanded);
105 		if (expanded && expanded != val) {
106 			switch_safe_free(expanded);
107 		}
108 	}
109 }
110 
kz_is_exported(switch_core_session_t * session,char * varname)111 static int kz_is_exported(switch_core_session_t *session, char *varname)
112 {
113 	char *array[256] = {0};
114 	int i, argc;
115 	switch_channel_t *channel = switch_core_session_get_channel(session);
116 	const char *exports = switch_channel_get_variable(channel, SWITCH_EXPORT_VARS_VARIABLE);
117 	char *arg = switch_core_session_strdup(session, exports);
118 	argc = switch_split(arg, ',', array);
119 	for(i=0; i < argc; i++) {
120 		if(!strcasecmp(array[i], varname))
121 			return 1;
122 	}
123 
124 	return 0;
125 }
126 
base_export(switch_core_session_t * session,const char * data,int urldecode,switch_stack_t stack)127 static void base_export (switch_core_session_t *session, const char *data, int urldecode, switch_stack_t stack)
128 {
129         char *var, *val = NULL;
130 
131         if (zstr(data)) {
132                 switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "No variable name specified.\n");
133         } else {
134                 switch_channel_t *channel = switch_core_session_get_channel(session);
135                 char *expanded = NULL;
136 
137                 var = switch_core_session_strdup(session, data);
138 
139                 if (!(val = strchr(var, '='))) {
140                         val = strchr(var, ',');
141                 }
142 
143                 if (val) {
144                         *val++ = '\0';
145                         if (zstr(val)) {
146                                 val = NULL;
147                         }
148                 }
149 
150 				if (val) {
151 					if(urldecode) {
152 						switch_url_decode(val);
153 					}
154 					expanded = switch_channel_expand_variables(channel, val);
155 
156 					if(!kz_is_exported(session, var)) {
157 						switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "%s EXPORT [%s]=[%s]\n", switch_channel_get_name(channel), var, expanded ? expanded : "UNDEF");
158 						switch_channel_export_variable_var_check(channel, var, expanded, SWITCH_EXPORT_VARS_VARIABLE, SWITCH_FALSE);
159 					} else {
160 						if(strcmp(switch_str_nil(switch_channel_get_variable_dup(channel, var, SWITCH_FALSE, -1)), expanded)) {
161 							switch_channel_set_variable(channel, var, expanded);
162 						}
163 					}
164 					if (expanded && expanded != val) {
165 						switch_safe_free(expanded);
166 					}
167 				}
168         }
169 }
170 
SWITCH_STANDARD_APP(prefix_unset_function)171 SWITCH_STANDARD_APP(prefix_unset_function)
172 {
173 	switch_channel_t *channel = switch_core_session_get_channel(session);
174 	switch_event_header_t *ei = NULL;
175 	switch_event_t *clear;
176 	char *arg = (char *) data;
177 
178 	if(switch_event_create(&clear, SWITCH_EVENT_CLONE) != SWITCH_STATUS_SUCCESS) {
179 		return;
180 	}
181 
182 	for (ei = switch_channel_variable_first(channel); ei; ei = ei->next) {
183 		const char *name = ei->name;
184 		char *value = ei->value;
185 		if (!strncasecmp(name, arg, strlen(arg))) {
186 			switch_event_add_header_string(clear, SWITCH_STACK_BOTTOM, name, value);
187 		}
188 	}
189 
190 	switch_channel_variable_last(channel);
191 	for (ei = clear->headers; ei; ei = ei->next) {
192 		char *varname = ei->name;
193 		switch_channel_set_variable(channel, varname, NULL);
194 	}
195 
196 	switch_event_destroy(&clear);
197 }
198 
kz_multiset(switch_core_session_t * session,const char * data,int urldecode)199 void kz_multiset(switch_core_session_t *session, const char* data, int urldecode)
200 {
201 	char delim = ' ';
202 	char *arg = (char *) data;
203 	switch_event_t *event;
204 
205 	if (!zstr(arg) && *arg == '^' && *(arg+1) == '^') {
206 		arg += 2;
207 		delim = *arg++;
208 	}
209 
210 	if(delim != '\0') {
211 		switch_channel_t *channel = switch_core_session_get_channel(session);
212 		if (arg) {
213 			char *array[256] = {0};
214 			int i, argc;
215 
216 			arg = switch_core_session_strdup(session, arg);
217 			argc = switch_split(arg, delim, array);
218 
219 			for(i = 0; i < argc; i++) {
220 				base_set(session, array[i], urldecode, SWITCH_STACK_BOTTOM);
221 			}
222 		}
223 		if (switch_event_create(&event, SWITCH_EVENT_CHANNEL_DATA) == SWITCH_STATUS_SUCCESS) {
224 			switch_channel_event_set_data(channel, event);
225 			switch_event_fire(&event);
226 		}
227 	} else {
228 		switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "multiset with empty args\n");
229 	}
230 }
231 
SWITCH_STANDARD_APP(multiset_function)232 SWITCH_STANDARD_APP(multiset_function)
233 {
234 	kz_multiset(session, data, 0);
235 }
236 
SWITCH_STANDARD_APP(multiset_encoded_function)237 SWITCH_STANDARD_APP(multiset_encoded_function)
238 {
239 	kz_multiset(session, data, 1);
240 }
241 
kz_uuid_multiset(switch_core_session_t * session,const char * data,int urldecode)242 void kz_uuid_multiset(switch_core_session_t *session, const char* data, int urldecode)
243 {
244 	char delim = ' ';
245 	char *arg0 = (char *) data;
246 	char *arg = strchr(arg0, ' ');
247 	switch_event_t *event;
248 
249 
250 	if(arg == NULL) {
251 		switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "uuid_multiset with invalid args\n");
252 		return;
253 	}
254 	*arg = '\0';
255 	arg++;
256 
257 	if(zstr(arg0)) {
258 		switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "uuid_multiset with invalid uuid\n");
259 		return;
260 	}
261 
262 
263 	if (!zstr(arg) && *arg == '^' && *(arg+1) == '^') {
264 		arg += 2;
265 		delim = *arg++;
266 	}
267 
268 	if(delim != '\0') {
269 		switch_core_session_t *uuid_session = NULL;
270 		if ((uuid_session = switch_core_session_locate(arg0)) != NULL) {
271 			switch_channel_t *uuid_channel = switch_core_session_get_channel(uuid_session);
272 			if (arg) {
273 				char *array[256] = {0};
274 				int i, argc;
275 
276 				arg = switch_core_session_strdup(session, arg);
277 				argc = switch_split(arg, delim, array);
278 
279 				for(i = 0; i < argc; i++) {
280 					base_set(uuid_session, array[i], urldecode, SWITCH_STACK_BOTTOM);
281 				}
282 			}
283 			if (switch_event_create(&event, SWITCH_EVENT_CHANNEL_DATA) == SWITCH_STATUS_SUCCESS) {
284 				switch_channel_event_set_data(uuid_channel, event);
285 				switch_event_fire(&event);
286 			}
287 			switch_core_session_rwunlock(uuid_session);
288 		} else {
289 			base_set(session, data, urldecode, SWITCH_STACK_BOTTOM);
290 		}
291 	} else {
292 		switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "multiset with empty args\n");
293 	}
294 }
295 
SWITCH_STANDARD_APP(uuid_multiset_function)296 SWITCH_STANDARD_APP(uuid_multiset_function)
297 {
298 	kz_uuid_multiset(session, data, 0);
299 }
300 
SWITCH_STANDARD_APP(uuid_multiset_encoded_function)301 SWITCH_STANDARD_APP(uuid_multiset_encoded_function)
302 {
303 	kz_uuid_multiset(session, data, 1);
304 }
305 
kz_set(switch_core_session_t * session,const char * data,int urldecode)306 void kz_set(switch_core_session_t *session, const char* data, int urldecode) {
307 	switch_channel_t *channel = switch_core_session_get_channel(session);
308 	switch_event_t *event;
309 
310 	base_set(session, data, urldecode, SWITCH_STACK_BOTTOM);
311 
312 	if (switch_event_create(&event, SWITCH_EVENT_CHANNEL_DATA) == SWITCH_STATUS_SUCCESS) {
313 		switch_channel_event_set_data(channel, event);
314 		switch_event_fire(&event);
315 	}
316 }
317 
SWITCH_STANDARD_APP(set_function)318 SWITCH_STANDARD_APP(set_function)
319 {
320 	kz_set(session, data, 0);
321 }
322 
SWITCH_STANDARD_APP(set_encoded_function)323 SWITCH_STANDARD_APP(set_encoded_function)
324 {
325 	kz_set(session, data, 1);
326 }
327 
SWITCH_STANDARD_APP(unset_function)328 SWITCH_STANDARD_APP(unset_function) {
329 	switch_channel_t *channel = switch_core_session_get_channel(session);
330 	switch_event_t *event;
331 
332 	if (zstr(data)) {
333 		switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "No variable name specified.\n");
334 	} else {
335 		switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "UNSET [%s]\n", (char *) data);
336 		switch_channel_set_variable(switch_core_session_get_channel(session), data, NULL);
337 	}
338 
339 	if (switch_event_create(&event, SWITCH_EVENT_CHANNEL_DATA) == SWITCH_STATUS_SUCCESS) {
340 		switch_channel_event_set_data(channel, event);
341 		switch_event_fire(&event);
342 	}
343 }
344 
SWITCH_STANDARD_APP(multiunset_function)345 SWITCH_STANDARD_APP(multiunset_function) {
346 	char delim = ' ';
347 	char *arg = (char *) data;
348 
349 	if (!zstr(arg) && *arg == '^' && *(arg+1) == '^') {
350 		arg += 2;
351 		delim = *arg++;
352 	}
353 
354 	if(delim != '\0') {
355 		if (arg) {
356 			char *array[256] = {0};
357 			int i, argc;
358 
359 			arg = switch_core_session_strdup(session, arg);
360 			argc = switch_split(arg, delim, array);
361 
362 			for(i = 0; i < argc; i++) {
363 				switch_channel_set_variable(switch_core_session_get_channel(session), array[i], NULL);
364 			}
365 
366 		} else {
367 			switch_channel_set_variable(switch_core_session_get_channel(session), arg, NULL);
368 		}
369 	} else {
370 		switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "multiunset with empty args\n");
371 	}
372 }
373 
374 
kz_export(switch_core_session_t * session,const char * data,int urldecode)375 void kz_export(switch_core_session_t *session, const char* data, int urldecode)
376 {
377     char delim = ' ';
378     char *arg = (char *) data;
379 
380     if (!zstr(arg) && *arg == '^' && *(arg+1) == '^') {
381             arg += 2;
382             delim = *arg++;
383     }
384 
385     if(delim != '\0') {
386 		if (arg) {
387 				char *array[256] = {0};
388 				int i, argc;
389 
390 				arg = switch_core_session_strdup(session, arg);
391 				argc = switch_split(arg, delim, array);
392 
393 				for(i = 0; i < argc; i++) {
394 						base_export(session, array[i], urldecode, SWITCH_STACK_BOTTOM);
395 				}
396 		} else {
397 				base_export(session, data, urldecode, SWITCH_STACK_BOTTOM);
398 		}
399     } else {
400 		switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "export with empty args\n");
401     }
402 }
403 
SWITCH_STANDARD_APP(export_function)404 SWITCH_STANDARD_APP(export_function)
405 {
406 	kz_export(session, data, 0);
407 }
408 
SWITCH_STANDARD_APP(export_encoded_function)409 SWITCH_STANDARD_APP(export_encoded_function)
410 {
411 	kz_export(session, data, 1);
412 }
413 
414 // copied from mod_dptools with allow SWITCH_STATUS_BREAK
SWITCH_STANDARD_APP(kz_endless_playback_function)415 SWITCH_STANDARD_APP(kz_endless_playback_function)
416 {
417 	switch_channel_t *channel = switch_core_session_get_channel(session);
418 	switch_status_t status = SWITCH_STATUS_SUCCESS;
419 	const char *file = data;
420 
421 	while (switch_channel_ready(channel)) {
422 		status = switch_ivr_play_file(session, NULL, file, NULL);
423 
424 		if (status != SWITCH_STATUS_SUCCESS) {
425 			break;
426 		}
427 	}
428 
429 	switch (status) {
430 	case SWITCH_STATUS_SUCCESS:
431 		switch_channel_set_variable(channel, SWITCH_CURRENT_APPLICATION_RESPONSE_VARIABLE, "FILE PLAYED");
432 		break;
433 	case SWITCH_STATUS_BREAK:
434 		switch_channel_set_variable(channel, SWITCH_CURRENT_APPLICATION_RESPONSE_VARIABLE, "PLAYBACK_INTERRUPTED");
435 		break;
436 	case SWITCH_STATUS_NOTFOUND:
437 		switch_channel_set_variable(channel, SWITCH_CURRENT_APPLICATION_RESPONSE_VARIABLE, "FILE NOT FOUND");
438 		break;
439 	default:
440 		switch_channel_set_variable(channel, SWITCH_CURRENT_APPLICATION_RESPONSE_VARIABLE, "PLAYBACK ERROR");
441 		break;
442 	}
443 
444 }
445 
SWITCH_STANDARD_APP(kz_moh_function)446 SWITCH_STANDARD_APP(kz_moh_function)
447 {
448 	switch_channel_t *channel = switch_core_session_get_channel(session);
449 	switch_status_t status = SWITCH_STATUS_SUCCESS;
450 	switch_file_handle_t fh = { 0 };
451 	const char *var_samples = switch_channel_get_variable_dup(channel, "moh_playback_samples", SWITCH_FALSE, -1);
452 	unsigned int samples =  0;
453 	char * my_data = NULL;
454 
455 	if (var_samples) {
456 		fh.samples = samples = atoi(var_samples);
457 		switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG1, "SETTING SAMPLES %d\n", samples);
458 	}
459 
460 	switch_channel_set_variable(channel, SWITCH_PLAYBACK_TERMINATOR_USED, "");
461 
462 	/*
463 	 * hack for proper position
464 	 */
465 	if (!strncmp(data, "http_cache://", 13) && session) {
466 		switch_channel_t *channel = switch_core_session_get_channel(session);
467 		char * resolve = switch_mprintf("${http_get({prefetch=true}%s)}", data+13);
468 		my_data = switch_channel_expand_variables_check(channel, resolve, NULL, NULL, 0);
469 	} else {
470 		my_data = strdup(data);
471 	}
472 
473 	status = switch_ivr_play_file(session, &fh, my_data, NULL);
474 //	status = switch_ivr_play_file(session, &fh, data, NULL);
475 
476 	switch_assert(!(fh.flags & SWITCH_FILE_OPEN));
477 
478 	switch (status) {
479 	case SWITCH_STATUS_SUCCESS:
480 		switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG1, "MOH PLAYED SUCCESS\n");
481 		switch_channel_set_variable(channel, SWITCH_CURRENT_APPLICATION_RESPONSE_VARIABLE, "MOH FILE PLAYED");
482 		switch_channel_set_variable(channel, "moh_playback_samples", "0");
483 		break;
484 	case SWITCH_STATUS_BREAK:
485 		switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG1, "MOH PLAYED BREAK\n");
486 		switch_channel_set_variable(channel, SWITCH_CURRENT_APPLICATION_RESPONSE_VARIABLE, "MOH FILE PLAYED");
487 		if ((var_samples = switch_channel_get_variable_dup(channel, "playback_samples", SWITCH_FALSE, -1)) != NULL) {
488 			samples += atoi(var_samples);
489 			if (samples >= fh.samples) {
490 				samples = 0;
491 			}
492 			switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG1, "SETTING MOH SAMPLES %d\n", samples);
493 			switch_channel_set_variable_printf(channel, "moh_playback_samples", "%d", samples);
494 		}
495 		break;
496 	case SWITCH_STATUS_NOTFOUND:
497 		switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG1, "MOH PLAYED NOT FOUND\n");
498 		switch_channel_set_variable(channel, SWITCH_CURRENT_APPLICATION_RESPONSE_VARIABLE, "MOH FILE NOT FOUND");
499 		break;
500 	default:
501 		switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "MOH PLAYED DEFAULT\n");
502 		switch_channel_set_variable(channel, SWITCH_CURRENT_APPLICATION_RESPONSE_VARIABLE, "MOH PLAYBACK ERROR");
503 		break;
504 	}
505 
506 	switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG1, "MOH duration %" SWITCH_INT64_T_FMT "\n", fh.duration);
507 	switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG1, "MOH offset_pos %d\n", fh.offset_pos);
508 	switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG1, "MOH pos %" SWITCH_INT64_T_FMT "\n", fh.pos);
509 	switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG1, "MOH sample_count %" SWITCH_SIZE_T_FMT "\n", fh.sample_count);
510 	switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG1, "MOH samples %d\n", fh.samples);
511 
512 	switch_safe_free(my_data);
513 }
514 
SWITCH_STANDARD_APP(noop_function)515 SWITCH_STANDARD_APP(noop_function)
516 {
517 	switch_channel_t *channel = switch_core_session_get_channel(session);
518 	char uuid_str[SWITCH_UUID_FORMATTED_LENGTH + 1];
519 	const char *response = uuid_str;
520 
521 	if (zstr(data)) {
522 		switch_uuid_str(uuid_str, sizeof(uuid_str));
523 	} else {
524 		response = data;
525 	}
526 
527 	switch_channel_set_variable(channel, SWITCH_CURRENT_APPLICATION_RESPONSE_VARIABLE, response);
528 }
529 
SWITCH_STANDARD_APP(kz_restore_caller_id_function)530 SWITCH_STANDARD_APP(kz_restore_caller_id_function)
531 {
532 	switch_channel_t *channel = switch_core_session_get_channel(session);
533 	switch_caller_profile_t *cp = switch_channel_get_caller_profile(channel);
534 	cp->caller_id_name = cp->orig_caller_id_name;
535 	cp->caller_id_number = cp->orig_caller_id_number;
536 }
537 
SWITCH_STANDARD_APP(kz_audio_bridge_function)538 SWITCH_STANDARD_APP(kz_audio_bridge_function)
539 {
540 	switch_channel_t *caller_channel = switch_core_session_get_channel(session);
541 	switch_core_session_t *peer_session = NULL;
542 	switch_call_cause_t cause = SWITCH_CAUSE_NORMAL_CLEARING;
543 	switch_status_t status = SWITCH_STATUS_FALSE;
544 
545 	if (zstr(data)) {
546 		return;
547 	}
548 
549 	status = switch_ivr_originate(session, &peer_session, &cause, data, 0, NULL, NULL, NULL, NULL, NULL, SOF_NONE, NULL, NULL);
550 
551 	if (status != SWITCH_STATUS_SUCCESS) {
552 		switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_INFO, "Originate Failed.  Cause: %s\n", switch_channel_cause2str(cause));
553 
554 		switch_channel_set_variable(caller_channel, "originate_failed_cause", switch_channel_cause2str(cause));
555 		switch_channel_set_variable(caller_channel, SWITCH_CURRENT_APPLICATION_RESPONSE_VARIABLE, switch_channel_cause2str(cause));
556 		switch_channel_handle_cause(caller_channel, cause);
557 
558 		return;
559 	} else {
560 		const char* uuid = switch_core_session_get_uuid(session);
561 		const char* peer_uuid = switch_core_session_get_uuid(peer_session);
562 
563 
564 		switch_channel_t *peer_channel = switch_core_session_get_channel(peer_session);
565 		if (switch_true(switch_channel_get_variable(caller_channel, SWITCH_BYPASS_MEDIA_AFTER_BRIDGE_VARIABLE)) ||
566 			switch_true(switch_channel_get_variable(peer_channel, SWITCH_BYPASS_MEDIA_AFTER_BRIDGE_VARIABLE))) {
567 			switch_channel_set_flag(caller_channel, CF_BYPASS_MEDIA_AFTER_BRIDGE);
568 		}
569 
570 		while(1) {
571 			const char *xfer_uuid;
572 			switch_channel_state_t a_state , a_running_state;
573 			switch_channel_state_t b_state , b_running_state;
574 			status = switch_ivr_multi_threaded_bridge(session, peer_session, NULL, NULL, NULL);
575 
576 			switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "BRIDGE RESULT %i\n", status);
577 			if(status  != 0) {
578 				break;
579 			}
580 
581 			a_state = switch_channel_get_state(caller_channel);
582 			a_running_state = switch_channel_get_running_state(caller_channel);
583 
584 			switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "A STATE %s  %s =>  %s , %s\n", switch_channel_state_name(a_running_state), switch_channel_state_name(a_state), uuid, peer_uuid);
585 
586 			if(a_state >= CS_HANGUP) {
587 				switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "A HANGUP =  %s , %s\n", uuid, peer_uuid);
588 				break;
589 			}
590 
591 			b_state = switch_channel_get_state(peer_channel);
592 			b_running_state = switch_channel_get_running_state(peer_channel);
593 
594 			switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "B STATE %s  %s =>  %s , %s\n", switch_channel_state_name(b_running_state), switch_channel_state_name(b_state), uuid, peer_uuid);
595 
596 			if(b_state >= CS_HANGUP) {
597 				switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "B HANGUP = %s , %s\n", uuid, peer_uuid);
598 				switch_channel_set_variable(caller_channel, SWITCH_CURRENT_APPLICATION_RESPONSE_VARIABLE, switch_channel_cause2str(switch_channel_get_cause(peer_channel)));
599 				break;
600 			}
601 
602 			if(!(xfer_uuid=switch_channel_get_variable(caller_channel, "att_xfer_peer_uuid"))) {
603 				if(!(xfer_uuid=switch_channel_get_variable(peer_channel, "att_xfer_peer_uuid"))) {
604 					switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "XFER UUID NULL\n");
605 					break;
606 				}
607 			}
608 
609 			switch_channel_set_variable(caller_channel, "att_xfer_peer_uuid", NULL);
610 			switch_channel_set_variable(peer_channel, "att_xfer_peer_uuid", NULL);
611 
612 			switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "WAIT 1\n");
613 
614 			switch_channel_clear_flag(peer_channel, CF_UUID_BRIDGE_ORIGINATOR);
615 			switch_channel_set_state(peer_channel, CS_RESET);
616 			switch_channel_wait_for_state(peer_channel, NULL, CS_RESET);
617 			switch_channel_clear_state_handler(peer_channel, NULL);
618 
619 			switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "WAIT 3\n");
620 
621 			switch_channel_set_flag(caller_channel, CF_UUID_BRIDGE_ORIGINATOR);
622 			switch_channel_clear_flag(caller_channel, CF_TRANSFER);
623 			switch_channel_clear_flag(caller_channel, CF_REDIRECT);
624 			switch_channel_set_flag(peer_channel, CF_UUID_BRIDGE_ORIGINATOR);
625 			switch_channel_clear_flag(peer_channel, CF_TRANSFER);
626 			switch_channel_clear_flag(peer_channel, CF_REDIRECT);
627 
628 			if(!switch_channel_media_up(caller_channel)) {
629 				switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "A MEDIA DOWN HANGUP = %s, %s , %s\n", xfer_uuid, uuid, peer_uuid);
630 			}
631 			if(!switch_channel_media_up(peer_channel)) {
632 				switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "B MEDIA DOWN HANGUP = %s, %s , %s\n", xfer_uuid, uuid, peer_uuid);
633 			}
634 			switch_channel_set_state(caller_channel, CS_EXECUTE);
635 			switch_channel_set_state(peer_channel, CS_EXECUTE);
636 
637 
638 			switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "XFER LOOP %s %s , %s\n", xfer_uuid, uuid, peer_uuid);
639 
640 		}
641 
642 		if (peer_session) {
643 			switch_core_session_rwunlock(peer_session);
644 		}
645 	}
646 }
647 
SWITCH_STANDARD_APP(kz_audio_bridge_uuid_function)648 SWITCH_STANDARD_APP(kz_audio_bridge_uuid_function)
649 {
650 	switch_core_session_t *peer_session = NULL;
651 	const char * peer_uuid = NULL;
652 
653 	if (zstr(data)) {
654 		return;
655 	}
656 
657 	peer_uuid = switch_core_session_strdup(session, data);
658 	if (peer_uuid && (peer_session = switch_core_session_locate(peer_uuid))) {
659 		switch_ivr_multi_threaded_bridge(session, peer_session, NULL, NULL, NULL);
660 	}
661 
662 	if (peer_session) {
663 		switch_core_session_rwunlock(peer_session);
664 	}
665 }
666 
667 
668 struct kz_att_keys {
669 	const char *attxfer_cancel_key;
670 	const char *attxfer_hangup_key;
671 	const char *attxfer_conf_key;
672 };
673 
kz_att_xfer_on_dtmf(switch_core_session_t * session,void * input,switch_input_type_t itype,void * buf,unsigned int buflen)674 static switch_status_t kz_att_xfer_on_dtmf(switch_core_session_t *session, void *input, switch_input_type_t itype, void *buf, unsigned int buflen)
675 {
676 	switch_core_session_t *peer_session = (switch_core_session_t *) buf;
677 	if (!buf || !peer_session) {
678 		return SWITCH_STATUS_SUCCESS;
679 	}
680 
681 	switch (itype) {
682 	case SWITCH_INPUT_TYPE_DTMF:
683 		{
684 			switch_dtmf_t *dtmf = (switch_dtmf_t *) input;
685 			switch_channel_t *channel = switch_core_session_get_channel(session);
686 			switch_channel_t *peer_channel = switch_core_session_get_channel(peer_session);
687 			struct kz_att_keys *keys = switch_channel_get_private(channel, "__kz_keys");
688 
689 			if (dtmf->digit == *keys->attxfer_hangup_key) {
690 				switch_channel_hangup(channel, SWITCH_CAUSE_ATTENDED_TRANSFER);
691 				return SWITCH_STATUS_FALSE;
692 			}
693 
694 			if (dtmf->digit == *keys->attxfer_cancel_key) {
695 				switch_channel_hangup(peer_channel, SWITCH_CAUSE_NORMAL_CLEARING);
696 				return SWITCH_STATUS_FALSE;
697 			}
698 
699 			if (dtmf->digit == *keys->attxfer_conf_key) {
700 				switch_caller_extension_t *extension = NULL;
701 				const char *app = "three_way";
702 				const char *app_arg = switch_core_session_get_uuid(session);
703 				const char *holding = switch_channel_get_variable(channel, SWITCH_SOFT_HOLDING_UUID_VARIABLE);
704 				switch_core_session_t *b_session;
705 
706 				if (holding && (b_session = switch_core_session_locate(holding))) {
707 					switch_channel_t *b_channel = switch_core_session_get_channel(b_session);
708 					if (!switch_channel_ready(b_channel)) {
709 						app = "intercept";
710 					}
711 					switch_core_session_rwunlock(b_session);
712 				}
713 
714 				if ((extension = switch_caller_extension_new(peer_session, app, app_arg)) == 0) {
715 					switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_CRIT, "Memory Error!\n");
716 					abort();
717 				}
718 
719 				switch_caller_extension_add_application(peer_session, extension, app, app_arg);
720 				switch_channel_set_caller_extension(peer_channel, extension);
721 				switch_channel_set_state(peer_channel, CS_RESET);
722 				switch_channel_wait_for_state(peer_channel, channel, CS_RESET);
723 				switch_channel_set_state(peer_channel, CS_EXECUTE);
724 				switch_channel_set_variable(channel, SWITCH_HANGUP_AFTER_BRIDGE_VARIABLE, NULL);
725 				return SWITCH_STATUS_FALSE;
726 			}
727 
728 		}
729 		break;
730 	default:
731 		break;
732 	}
733 
734 	return SWITCH_STATUS_SUCCESS;
735 }
736 
kz_att_xfer_tmp_hanguphook(switch_core_session_t * session)737 static switch_status_t kz_att_xfer_tmp_hanguphook(switch_core_session_t *session)
738 {
739 	switch_channel_t *channel = switch_core_session_get_channel(session);
740 	switch_channel_state_t state = switch_channel_get_state(channel);
741 
742 	if (state == CS_HANGUP || state == CS_ROUTING) {
743 		const char *bond = switch_channel_get_variable(channel, SWITCH_SOFT_HOLDING_UUID_VARIABLE);
744 
745 		if (!zstr(bond)) {
746 			switch_core_session_t *b_session;
747 
748 			if ((b_session = switch_core_session_locate(bond))) {
749 				switch_channel_t *b_channel = switch_core_session_get_channel(b_session);
750 				if (switch_channel_up(b_channel)) {
751 					switch_channel_set_flag(b_channel, CF_REDIRECT);
752 				}
753 				switch_core_session_rwunlock(b_session);
754 			}
755 		}
756 
757 		switch_core_event_hook_remove_state_change(session, kz_att_xfer_tmp_hanguphook);
758 	}
759 
760 	return SWITCH_STATUS_SUCCESS;
761 }
762 
kz_att_xfer_hanguphook(switch_core_session_t * session)763 static switch_status_t kz_att_xfer_hanguphook(switch_core_session_t *session)
764 {
765 	switch_channel_t *channel = switch_core_session_get_channel(session);
766 	switch_channel_state_t state = switch_channel_get_state(channel);
767 	const char *id = NULL;
768 	const char *peer_uuid = NULL;
769 
770 	if (state == CS_HANGUP || state == CS_ROUTING) {
771 		if ((id = switch_channel_get_variable(channel, "xfer_uuids"))) {
772 			switch_stream_handle_t stream = { 0 };
773 			SWITCH_STANDARD_STREAM(stream);
774 			if ((peer_uuid = switch_channel_get_variable(channel, "xfer_peer_uuid"))) {
775 				switch_core_session_t *peer_session = NULL;
776 				if ((peer_session = switch_core_session_locate(peer_uuid)) != NULL ) {
777 					switch_ivr_transfer_recordings(session, peer_session);
778 					switch_core_session_rwunlock(peer_session);
779 				}
780 			}
781 			switch_api_execute("uuid_bridge", id, NULL, &stream);
782 			switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "\nHangup Command uuid_bridge(%s):\n%s\n", id,
783 							  switch_str_nil((char *) stream.data));
784 			switch_safe_free(stream.data);
785 		}
786 
787 		switch_core_event_hook_remove_state_change(session, kz_att_xfer_hanguphook);
788 	}
789 	return SWITCH_STATUS_SUCCESS;
790 }
791 
792 
kz_att_xfer_set_result(switch_channel_t * channel,switch_status_t status)793 static void kz_att_xfer_set_result(switch_channel_t *channel, switch_status_t status)
794 {
795 	switch_channel_set_variable(channel, SWITCH_ATT_XFER_RESULT_VARIABLE, status == SWITCH_STATUS_SUCCESS ? "success" : "failure");
796 }
797 
798 struct kz_att_obj {
799 	switch_core_session_t *session;
800 	const char *data;
801 	int running;
802 };
803 
kz_att_thread_run(switch_thread_t * thread,void * obj)804 void *SWITCH_THREAD_FUNC kz_att_thread_run(switch_thread_t *thread, void *obj)
805 {
806 	struct kz_att_obj *att = (struct kz_att_obj *) obj;
807 	struct kz_att_keys *keys = NULL;
808 	switch_core_session_t *session = att->session;
809 	switch_core_session_t *peer_session = NULL;
810 	const char *data = att->data;
811 	switch_call_cause_t cause = SWITCH_CAUSE_NORMAL_CLEARING;
812 	switch_channel_t *channel = switch_core_session_get_channel(session), *peer_channel = NULL;
813 	const char *bond = NULL;
814 	switch_bool_t follow_recording = switch_true(switch_channel_get_variable(channel, "recording_follow_attxfer"));
815 	const char *attxfer_cancel_key = NULL, *attxfer_hangup_key = NULL, *attxfer_conf_key = NULL;
816 	int br = 0;
817 	switch_event_t *event = NULL;
818 	switch_core_session_t *b_session = NULL;
819 	switch_channel_t *b_channel = NULL;
820 
821 	att->running = 1;
822 
823 	if (switch_core_session_read_lock(session) != SWITCH_STATUS_SUCCESS) {
824 		return NULL;
825 	}
826 
827 	bond = switch_channel_get_partner_uuid(channel);
828 	if ((b_session = switch_core_session_locate(bond)) == NULL) {
829 		switch_core_session_rwunlock(session);
830 		return NULL;
831 	}
832 	switch_channel_set_variable(channel, SWITCH_SOFT_HOLDING_UUID_VARIABLE, bond);
833 	switch_core_event_hook_add_state_change(session, kz_att_xfer_tmp_hanguphook);
834 
835 	if (switch_ivr_originate(session, &peer_session, &cause, data, 0, NULL, NULL, NULL, NULL, NULL, SOF_NONE, NULL, NULL)
836 		!= SWITCH_STATUS_SUCCESS || !peer_session) {
837 		switch_channel_set_variable(channel, SWITCH_SIGNAL_BOND_VARIABLE, bond);
838 		goto end;
839 	}
840 
841 	peer_channel = switch_core_session_get_channel(peer_session);
842 	switch_channel_set_flag(peer_channel, CF_INNER_BRIDGE);
843 	switch_channel_set_flag(channel, CF_INNER_BRIDGE);
844 
845 	if (!(attxfer_cancel_key = switch_channel_get_variable(channel, "attxfer_cancel_key"))) {
846 		if (!(attxfer_cancel_key = switch_channel_get_variable(peer_channel, "attxfer_cancel_key"))) {
847 			attxfer_cancel_key = "#";
848 		}
849 	}
850 
851 	if (!(attxfer_hangup_key = switch_channel_get_variable(channel, "attxfer_hangup_key"))) {
852 		if (!(attxfer_hangup_key = switch_channel_get_variable(peer_channel, "attxfer_hangup_key"))) {
853 			attxfer_hangup_key = "*";
854 		}
855 	}
856 
857 	if (!(attxfer_conf_key = switch_channel_get_variable(channel, "attxfer_conf_key"))) {
858 		if (!(attxfer_conf_key = switch_channel_get_variable(peer_channel, "attxfer_conf_key"))) {
859 			attxfer_conf_key = "0";
860 		}
861 	}
862 
863 	keys = switch_core_session_alloc(session, sizeof(*keys));
864 	keys->attxfer_cancel_key = switch_core_session_strdup(session, attxfer_cancel_key);
865 	keys->attxfer_hangup_key = switch_core_session_strdup(session, attxfer_hangup_key);
866 	keys->attxfer_conf_key = switch_core_session_strdup(session, attxfer_conf_key);
867 	switch_channel_set_private(channel, "__kz_keys", keys);
868 
869 	switch_channel_set_variable(channel, "att_xfer_peer_uuid", switch_core_session_get_uuid(peer_session));
870 
871 	switch_ivr_multi_threaded_bridge(session, peer_session, kz_att_xfer_on_dtmf, peer_session, NULL);
872 
873 	switch_channel_clear_flag(peer_channel, CF_INNER_BRIDGE);
874 	switch_channel_clear_flag(channel, CF_INNER_BRIDGE);
875 
876 	if (switch_channel_down(peer_channel)) {
877 		switch_core_session_rwunlock(peer_session);
878 		switch_channel_set_variable(channel, SWITCH_SIGNAL_BOND_VARIABLE, bond);
879 		goto end;
880 	}
881 
882 	/*
883 	 * we're emiting the transferee event so that callctl can update
884 	 */
885 	b_channel = switch_core_session_get_channel(b_session);
886 	if (switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, "sofia::transferee") == SWITCH_STATUS_SUCCESS) {
887 		switch_channel_event_set_data(b_channel, event);
888 		switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "att_xfer_replaced_call_id", switch_core_session_get_uuid(peer_session));
889 		switch_event_fire(&event);
890 	}
891 
892 	if (!switch_channel_ready(channel)) {
893 		switch_status_t status;
894 
895 		if (follow_recording) {
896 			switch_ivr_transfer_recordings(session, peer_session);
897 		}
898 		status = switch_ivr_uuid_bridge(switch_core_session_get_uuid(peer_session), bond);
899 		kz_att_xfer_set_result(peer_channel, status);
900 		br++;
901 	} else {
902 		// switch_channel_set_variable_printf(b_channel, "xfer_uuids", "%s %s", switch_core_session_get_uuid(peer_session), switch_core_session_get_uuid(session));
903 		switch_channel_set_variable_printf(channel, "xfer_uuids", "%s %s", switch_core_session_get_uuid(peer_session), bond);
904 		switch_channel_set_variable(channel, "xfer_peer_uuid", switch_core_session_get_uuid(peer_session));
905 
906 		switch_core_event_hook_add_state_change(session, kz_att_xfer_hanguphook);
907 		// switch_core_event_hook_add_state_change(b_session, kz_att_xfer_hanguphook);
908 	}
909 
910 /*
911  * this was commented so that the existing bridge
912  * doesn't end
913  *
914 		if (!br) {
915 			switch_status_t status = switch_ivr_uuid_bridge(switch_core_session_get_uuid(session), bond);
916 			att_xfer_set_result(channel, status);
917 		}
918 */
919 
920 	switch_core_session_rwunlock(peer_session);
921 
922   end:
923 
924 	switch_core_event_hook_remove_state_change(session, kz_att_xfer_tmp_hanguphook);
925 
926 	switch_channel_set_variable(channel, SWITCH_SOFT_HOLDING_UUID_VARIABLE, NULL);
927 	switch_channel_clear_flag(channel, CF_XFER_ZOMBIE);
928 
929 	switch_core_session_rwunlock(b_session);
930 	switch_core_session_rwunlock(session);
931 	att->running = 0;
932 
933 	return NULL;
934 }
935 
SWITCH_STANDARD_APP(kz_att_xfer_function)936 SWITCH_STANDARD_APP(kz_att_xfer_function)
937 {
938 	switch_thread_t *thread;
939 	switch_threadattr_t *thd_attr = NULL;
940 	switch_memory_pool_t *pool = switch_core_session_get_pool(session);
941 	struct kz_att_obj *att;
942 	switch_channel_t *channel = switch_core_session_get_channel(session);
943 
944 	switch_threadattr_create(&thd_attr, pool);
945 	switch_threadattr_detach_set(thd_attr, 1);
946 	switch_threadattr_stacksize_set(thd_attr, SWITCH_THREAD_STACKSIZE);
947 	switch_threadattr_detach_set(thd_attr, 1);
948 
949 	att = switch_core_session_alloc(session, sizeof(*att));
950 	att->running = -1;
951 	att->session = session;
952 	att->data = switch_core_session_strdup(session, data);
953 	switch_thread_create(&thread, thd_attr, kz_att_thread_run, att, pool);
954 
955 	while(att->running && switch_channel_up(channel)) {
956 		switch_yield(100000);
957 	}
958 }
959 
add_kz_dptools(switch_loadable_module_interface_t ** module_interface)960 void add_kz_dptools(switch_loadable_module_interface_t **module_interface) {
961 	switch_application_interface_t *app_interface = NULL;
962 	SWITCH_ADD_APP(app_interface, "kz_set", SET_SHORT_DESC, SET_LONG_DESC, set_function, SET_SYNTAX, SAF_SUPPORT_NOMEDIA | SAF_ROUTING_EXEC | SAF_ZOMBIE_EXEC);
963 	SWITCH_ADD_APP(app_interface, "kz_set_encoded", SET_SHORT_DESC, SET_LONG_DESC, set_encoded_function, SET_SYNTAX, SAF_SUPPORT_NOMEDIA | SAF_ROUTING_EXEC | SAF_ZOMBIE_EXEC);
964 	SWITCH_ADD_APP(app_interface, "kz_multiset", MULTISET_SHORT_DESC, MULTISET_LONG_DESC, multiset_function, MULTISET_SYNTAX, SAF_SUPPORT_NOMEDIA | SAF_ROUTING_EXEC | SAF_ZOMBIE_EXEC);
965 	SWITCH_ADD_APP(app_interface, "kz_multiset_encoded", MULTISET_SHORT_DESC, MULTISET_LONG_DESC, multiset_encoded_function, MULTISET_SYNTAX, SAF_SUPPORT_NOMEDIA | SAF_ROUTING_EXEC | SAF_ZOMBIE_EXEC);
966 	SWITCH_ADD_APP(app_interface, "kz_unset", UNSET_SHORT_DESC, UNSET_LONG_DESC, unset_function, UNSET_SYNTAX, SAF_SUPPORT_NOMEDIA | SAF_ROUTING_EXEC | SAF_ZOMBIE_EXEC);
967 	SWITCH_ADD_APP(app_interface, "kz_multiunset", MULTISET_SHORT_DESC, MULTISET_LONG_DESC, multiunset_function, MULTIUNSET_SYNTAX, SAF_SUPPORT_NOMEDIA | SAF_ROUTING_EXEC | SAF_ZOMBIE_EXEC);
968 	SWITCH_ADD_APP(app_interface, "kz_export", EXPORT_SHORT_DESC, EXPORT_LONG_DESC, export_function, EXPORT_SYNTAX, SAF_SUPPORT_NOMEDIA | SAF_ROUTING_EXEC | SAF_ZOMBIE_EXEC);
969 	SWITCH_ADD_APP(app_interface, "kz_export_encoded", EXPORT_SHORT_DESC, EXPORT_LONG_DESC, export_encoded_function, EXPORT_SYNTAX, SAF_SUPPORT_NOMEDIA | SAF_ROUTING_EXEC | SAF_ZOMBIE_EXEC);
970 	SWITCH_ADD_APP(app_interface, "kz_prefix_unset", PREFIX_UNSET_SHORT_DESC, PREFIX_UNSET_LONG_DESC, prefix_unset_function, PREFIX_UNSET_SYNTAX, SAF_SUPPORT_NOMEDIA | SAF_ROUTING_EXEC | SAF_ZOMBIE_EXEC);
971 	SWITCH_ADD_APP(app_interface, "kz_uuid_multiset", UUID_MULTISET_SHORT_DESC, UUID_MULTISET_LONG_DESC, uuid_multiset_function, UUID_MULTISET_SYNTAX, SAF_SUPPORT_NOMEDIA | SAF_ROUTING_EXEC | SAF_ZOMBIE_EXEC);
972 	SWITCH_ADD_APP(app_interface, "kz_uuid_multiset_encoded", UUID_MULTISET_SHORT_DESC, UUID_MULTISET_LONG_DESC, uuid_multiset_encoded_function, UUID_MULTISET_SYNTAX, SAF_SUPPORT_NOMEDIA | SAF_ROUTING_EXEC | SAF_ZOMBIE_EXEC);
973 	SWITCH_ADD_APP(app_interface, "kz_endless_playback", KZ_ENDLESS_PLAYBACK_SHORT_DESC, KZ_ENDLESS_PLAYBACK_LONG_DESC, kz_endless_playback_function, KZ_ENDLESS_PLAYBACK_SYNTAX, SAF_NONE);
974 	SWITCH_ADD_APP(app_interface, "kz_restore_caller_id", NOOP_SHORT_DESC, NOOP_LONG_DESC, kz_restore_caller_id_function, NOOP_SYNTAX, SAF_NONE);
975 	SWITCH_ADD_APP(app_interface, "noop", NOOP_SHORT_DESC, NOOP_LONG_DESC, noop_function, NOOP_SYNTAX, SAF_NONE);
976 	SWITCH_ADD_APP(app_interface, "kz_bridge", "Bridge Audio", "Bridge the audio between two sessions", kz_audio_bridge_function, "<channel_url>", SAF_SUPPORT_NOMEDIA|SAF_SUPPORT_TEXT_ONLY);
977 	SWITCH_ADD_APP(app_interface, "kz_bridge_uuid", "Bridge Audio", "Bridge the audio between two sessions", kz_audio_bridge_uuid_function, "<channel_url>", SAF_SUPPORT_NOMEDIA|SAF_SUPPORT_TEXT_ONLY);
978 	SWITCH_ADD_APP(app_interface, "kz_att_xfer", "Attended Transfer", "Attended Transfer", kz_att_xfer_function, "<channel_url>", SAF_NONE);
979 	SWITCH_ADD_APP(app_interface, "kz_moh", "Kazoo MOH Playback", "Kazoo MOH Playback", kz_moh_function, "", SAF_NONE);
980 }
981