Bug Summary

File:src/switch_ivr_menu.c
Location:line 598, column 11
Description:Value stored to 'status' is never read

Annotated Source Code

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 * Neal Horman <neal at wanlink dot com>
28 *
29 * switch_ivr_menu.c -- IVR Library (menu code)
30 *
31 */
32
33#include <switch.h>
34
35struct switch_ivr_menu_action;
36
37struct switch_ivr_menu {
38 char *name;
39 char *greeting_sound;
40 char *short_greeting_sound;
41 char *invalid_sound;
42 char *exit_sound;
43 char *transfer_sound;
44 char *buf;
45 char *ptr;
46 char *confirm_macro;
47 char *confirm_key;
48 char *tts_engine;
49 char *tts_voice;
50 int confirm_attempts;
51 int digit_len;
52 int max_failures;
53 int max_timeouts;
54 int timeout;
55 int inter_timeout;
56 char *exec_on_max_fail;
57 char *exec_on_max_timeout;
58 switch_size_t inlen;
59 uint32_t flags;
60 struct switch_ivr_menu_action *actions;
61 struct switch_ivr_menu *next;
62 switch_memory_pool_t *pool;
63 int stack_count;
64 char *pin;
65 char *prompt_pin_file;
66 char *bad_pin_file;
67};
68
69struct switch_ivr_menu_action {
70 switch_ivr_menu_action_function_t *function;
71 switch_ivr_action_t ivr_action;
72 char *arg;
73 char *bind;
74 int re;
75 struct switch_ivr_menu_action *next;
76};
77
78static switch_ivr_menu_t *switch_ivr_menu_find(switch_ivr_menu_t *stack, const char *name)
79{
80 switch_ivr_menu_t *ret;
81 for (ret = stack; ret; ret = ret->next) {
82 if (!name || !strcmp(ret->name, name)__extension__ ({ size_t __s1_len, __s2_len; (__builtin_constant_p
(ret->name) && __builtin_constant_p (name) &&
(__s1_len = __builtin_strlen (ret->name), __s2_len = __builtin_strlen
(name), (!((size_t)(const void *)((ret->name) + 1) - (size_t
)(const void *)(ret->name) == 1) || __s1_len >= 4) &&
(!((size_t)(const void *)((name) + 1) - (size_t)(const void *
)(name) == 1) || __s2_len >= 4)) ? __builtin_strcmp (ret->
name, name) : (__builtin_constant_p (ret->name) &&
((size_t)(const void *)((ret->name) + 1) - (size_t)(const
void *)(ret->name) == 1) && (__s1_len = __builtin_strlen
(ret->name), __s1_len < 4) ? (__builtin_constant_p (name
) && ((size_t)(const void *)((name) + 1) - (size_t)(const
void *)(name) == 1) ? __builtin_strcmp (ret->name, name) :
(__extension__ ({ const unsigned char *__s2 = (const unsigned
char *) (const char *) (name); int __result = (((const unsigned
char *) (const char *) (ret->name))[0] - __s2[0]); if (__s1_len
> 0 && __result == 0) { __result = (((const unsigned
char *) (const char *) (ret->name))[1] - __s2[1]); if (__s1_len
> 1 && __result == 0) { __result = (((const unsigned
char *) (const char *) (ret->name))[2] - __s2[2]); if (__s1_len
> 2 && __result == 0) __result = (((const unsigned
char *) (const char *) (ret->name))[3] - __s2[3]); } } __result
; }))) : (__builtin_constant_p (name) && ((size_t)(const
void *)((name) + 1) - (size_t)(const void *)(name) == 1) &&
(__s2_len = __builtin_strlen (name), __s2_len < 4) ? (__builtin_constant_p
(ret->name) && ((size_t)(const void *)((ret->name
) + 1) - (size_t)(const void *)(ret->name) == 1) ? __builtin_strcmp
(ret->name, name) : (- (__extension__ ({ const unsigned char
*__s2 = (const unsigned char *) (const char *) (ret->name
); int __result = (((const unsigned char *) (const char *) (name
))[0] - __s2[0]); if (__s2_len > 0 && __result == 0
) { __result = (((const unsigned char *) (const char *) (name
))[1] - __s2[1]); if (__s2_len > 1 && __result == 0
) { __result = (((const unsigned char *) (const char *) (name
))[2] - __s2[2]); if (__s2_len > 2 && __result == 0
) __result = (((const unsigned char *) (const char *) (name))
[3] - __s2[3]); } } __result; })))) : __builtin_strcmp (ret->
name, name)))); })
)
83 break;
84 }
85 return ret;
86}
87
88static void switch_ivr_menu_stack_add(switch_ivr_menu_t ** top, switch_ivr_menu_t *bottom)
89{
90 switch_ivr_menu_t *ptr;
91
92 for (ptr = *top; ptr && ptr->next; ptr = ptr->next);
93
94 if (ptr) {
95 ptr->next = bottom;
96 } else {
97 *top = bottom;
98 }
99
100}
101
102SWITCH_DECLARE(switch_status_t)__attribute__((visibility("default"))) switch_status_t switch_ivr_menu_init(switch_ivr_menu_t ** new_menu,
103 switch_ivr_menu_t *main,
104 const char *name,
105 const char *greeting_sound,
106 const char *short_greeting_sound,
107 const char *invalid_sound,
108 const char *exit_sound,
109 const char *transfer_sound,
110 const char *confirm_macro,
111 const char *confirm_key,
112 const char *tts_engine,
113 const char *tts_voice,
114 int confirm_attempts,
115 int inter_timeout,
116 int digit_len, int timeout, int max_failures, int max_timeouts, switch_memory_pool_t *pool)
117{
118 switch_ivr_menu_t *menu;
119 uint8_t newpool = 0;
120
121 if (!pool) {
122 if (switch_core_new_memory_pool(&pool)switch_core_perform_new_memory_pool(&pool, "src/switch_ivr_menu.c"
, (const char *)__func__, 122)
!= SWITCH_STATUS_SUCCESS) {
123 switch_log_printf(SWITCH_CHANNEL_LOGSWITCH_CHANNEL_ID_LOG, "src/switch_ivr_menu.c", (const char *
)__func__, 123, ((void*)0)
, SWITCH_LOG_CRIT, "OH OH no pool\n");
124 return SWITCH_STATUS_MEMERR;
125 }
126 newpool = 1;
127 }
128
129 if (!(menu = switch_core_alloc(pool, sizeof(*menu))switch_core_perform_alloc(pool, sizeof(*menu), "src/switch_ivr_menu.c"
, (const char *)__func__, 129)
)) {
130 if (newpool) {
131 switch_core_destroy_memory_pool(&pool)switch_core_perform_destroy_memory_pool(&pool, "src/switch_ivr_menu.c"
, (const char *)__func__, 131)
;
132 switch_log_printf(SWITCH_CHANNEL_LOGSWITCH_CHANNEL_ID_LOG, "src/switch_ivr_menu.c", (const char *
)__func__, 132, ((void*)0)
, SWITCH_LOG_CRIT, "Memory Error!\n");
133 return SWITCH_STATUS_MEMERR;
134 }
135 }
136
137 menu->pool = pool;
138
139 if (!confirm_attempts) {
140 confirm_attempts = 3;
141 }
142
143 if (!inter_timeout) {
144 inter_timeout = timeout / 2;
145 }
146
147 if (!zstr(name)_zstr(name)) {
148 menu->name = switch_core_strdup(menu->pool, name)switch_core_perform_strdup(menu->pool, name, "src/switch_ivr_menu.c"
, (const char *)__func__, 148)
;
149 }
150
151 if (!zstr(greeting_sound)_zstr(greeting_sound)) {
152 menu->greeting_sound = switch_core_strdup(menu->pool, greeting_sound)switch_core_perform_strdup(menu->pool, greeting_sound, "src/switch_ivr_menu.c"
, (const char *)__func__, 152)
;
153 }
154
155 if (!zstr(short_greeting_sound)_zstr(short_greeting_sound)) {
156 menu->short_greeting_sound = switch_core_strdup(menu->pool, short_greeting_sound)switch_core_perform_strdup(menu->pool, short_greeting_sound
, "src/switch_ivr_menu.c", (const char *)__func__, 156)
;
157 }
158
159 if (!zstr(invalid_sound)_zstr(invalid_sound)) {
160 menu->invalid_sound = switch_core_strdup(menu->pool, invalid_sound)switch_core_perform_strdup(menu->pool, invalid_sound, "src/switch_ivr_menu.c"
, (const char *)__func__, 160)
;
161 }
162
163 if (!zstr(transfer_sound)_zstr(transfer_sound)) {
164 menu->transfer_sound = switch_core_strdup(menu->pool, transfer_sound)switch_core_perform_strdup(menu->pool, transfer_sound, "src/switch_ivr_menu.c"
, (const char *)__func__, 164)
;
165 }
166
167 if (!zstr(exit_sound)_zstr(exit_sound)) {
168 menu->exit_sound = switch_core_strdup(menu->pool, exit_sound)switch_core_perform_strdup(menu->pool, exit_sound, "src/switch_ivr_menu.c"
, (const char *)__func__, 168)
;
169 }
170
171 if (!zstr(confirm_key)_zstr(confirm_key)) {
172 menu->confirm_key = switch_core_strdup(menu->pool, confirm_key)switch_core_perform_strdup(menu->pool, confirm_key, "src/switch_ivr_menu.c"
, (const char *)__func__, 172)
;
173 }
174
175 if (!zstr(confirm_macro)_zstr(confirm_macro)) {
176 menu->confirm_macro = switch_core_strdup(menu->pool, confirm_macro)switch_core_perform_strdup(menu->pool, confirm_macro, "src/switch_ivr_menu.c"
, (const char *)__func__, 176)
;
177 }
178
179 if (!zstr(tts_engine)_zstr(tts_engine)) {
180 menu->tts_engine = switch_core_strdup(menu->pool, tts_engine)switch_core_perform_strdup(menu->pool, tts_engine, "src/switch_ivr_menu.c"
, (const char *)__func__, 180)
;
181 }
182
183 if (!zstr(tts_voice)_zstr(tts_voice)) {
184 menu->tts_voice = switch_core_strdup(menu->pool, tts_voice)switch_core_perform_strdup(menu->pool, tts_voice, "src/switch_ivr_menu.c"
, (const char *)__func__, 184)
;
185 }
186
187 menu->confirm_attempts = confirm_attempts;
188
189 menu->inlen = digit_len;
190
191 if (max_failures > 0) {
192 menu->max_failures = max_failures;
193 } else {
194 menu->max_failures = 3;
195 }
196
197 if (max_timeouts > 0) {
198 menu->max_timeouts = max_timeouts;
199 } else {
200 menu->max_timeouts = 3;
201 }
202
203 menu->timeout = timeout;
204
205 menu->inter_timeout = inter_timeout;
206
207 menu->actions = NULL((void*)0);
208
209 if (newpool) {
210 switch_set_flag(menu, SWITCH_IVR_MENU_FLAG_FREEPOOL)(menu)->flags |= (SWITCH_IVR_MENU_FLAG_FREEPOOL);
211 }
212
213 if (menu->timeout <= 0) {
214 menu->timeout = 10000;
215 }
216
217 if (main) {
218 switch_ivr_menu_stack_add(&main, menu);
219 } else {
220 switch_set_flag(menu, SWITCH_IVR_MENU_FLAG_STACK)(menu)->flags |= (SWITCH_IVR_MENU_FLAG_STACK);
221 }
222
223 menu->buf = switch_core_alloc(menu->pool, 1024)switch_core_perform_alloc(menu->pool, 1024, "src/switch_ivr_menu.c"
, (const char *)__func__, 223)
;
224
225 *new_menu = menu;
226
227 return SWITCH_STATUS_SUCCESS;
228}
229
230SWITCH_DECLARE(switch_status_t)__attribute__((visibility("default"))) switch_status_t switch_ivr_menu_bind_action(switch_ivr_menu_t *menu, switch_ivr_action_t ivr_action, const char *arg, const char *bind)
231{
232 switch_ivr_menu_action_t *action, *ap;
233 uint32_t len;
234
235 if ((action = switch_core_alloc(menu->pool, sizeof(*action))switch_core_perform_alloc(menu->pool, sizeof(*action), "src/switch_ivr_menu.c"
, (const char *)__func__, 235)
)) {
236 action->bind = switch_core_strdup(menu->pool, bind)switch_core_perform_strdup(menu->pool, bind, "src/switch_ivr_menu.c"
, (const char *)__func__, 236)
;
237 action->arg = switch_core_strdup(menu->pool, arg)switch_core_perform_strdup(menu->pool, arg, "src/switch_ivr_menu.c"
, (const char *)__func__, 237)
;
238 if (*action->bind == '/') {
239 action->re = 1;
240 } else {
241 len = (uint32_t) strlen(action->bind);
242 if (len > menu->inlen) {
243 menu->inlen = len;
244 }
245 }
246 action->ivr_action = ivr_action;
247
248 if (menu->actions) {
249 for(ap = menu->actions; ap && ap->next; ap = ap->next);
250 ap->next = action;
251 } else {
252 menu->actions = action;
253 }
254
255 return SWITCH_STATUS_SUCCESS;
256 }
257
258 return SWITCH_STATUS_MEMERR;
259}
260
261SWITCH_DECLARE(switch_status_t)__attribute__((visibility("default"))) switch_status_t switch_ivr_menu_bind_function(switch_ivr_menu_t *menu,
262 switch_ivr_menu_action_function_t *function, const char *arg, const char *bind)
263{
264 switch_ivr_menu_action_t *action, *ap;
265 uint32_t len;
266
267 if ((action = switch_core_alloc(menu->pool, sizeof(*action))switch_core_perform_alloc(menu->pool, sizeof(*action), "src/switch_ivr_menu.c"
, (const char *)__func__, 267)
)) {
268 action->bind = switch_core_strdup(menu->pool, bind)switch_core_perform_strdup(menu->pool, bind, "src/switch_ivr_menu.c"
, (const char *)__func__, 268)
;
269 action->arg = switch_core_strdup(menu->pool, arg)switch_core_perform_strdup(menu->pool, arg, "src/switch_ivr_menu.c"
, (const char *)__func__, 269)
;
270
271 if (*action->bind == '/') {
272 action->re = 1;
273 } else {
274 len = (uint32_t) strlen(action->bind);
275 if (len > menu->inlen) {
276 menu->inlen = len;
277 }
278 }
279
280 action->function = function;
281
282 if (menu->actions) {
283 for(ap = menu->actions; ap && ap->next; ap = ap->next);
284 ap->next = action;
285 } else {
286 menu->actions = action;
287 }
288
289 return SWITCH_STATUS_SUCCESS;
290 }
291
292 return SWITCH_STATUS_MEMERR;
293}
294
295SWITCH_DECLARE(switch_status_t)__attribute__((visibility("default"))) switch_status_t switch_ivr_menu_stack_free(switch_ivr_menu_t *stack)
296{
297 switch_status_t status = SWITCH_STATUS_FALSE;
298
299 if (stack != NULL((void*)0) && stack->pool != NULL((void*)0)) {
300 if (switch_test_flag(stack, SWITCH_IVR_MENU_FLAG_STACK)((stack)->flags & SWITCH_IVR_MENU_FLAG_STACK)
301 && switch_test_flag(stack, SWITCH_IVR_MENU_FLAG_FREEPOOL)((stack)->flags & SWITCH_IVR_MENU_FLAG_FREEPOOL)) {
302 switch_memory_pool_t *pool = stack->pool;
303 status = switch_core_destroy_memory_pool(&pool)switch_core_perform_destroy_memory_pool(&pool, "src/switch_ivr_menu.c"
, (const char *)__func__, 303)
;
304 } else {
305 status = SWITCH_STATUS_SUCCESS;
306 }
307 }
308
309 return status;
310}
311
312static switch_status_t play_and_collect(switch_core_session_t *session, switch_ivr_menu_t *menu, char *sound, switch_size_t need)
313{
314 char terminator;
315 uint32_t len;
316 char *ptr;
317 switch_status_t status = SWITCH_STATUS_FALSE;
318 switch_input_args_t args = { 0 };
319 switch_channel_t *channel;
320 char *sound_expanded = sound;
321 switch_size_t menu_buf_len = 0;
322 const char *terminator_str = "#";
323
324 if (!session || !menu || zstr(sound)_zstr(sound)) {
325 return status;
326 }
327
328 if ((channel = switch_core_session_get_channel(session))) {
329 const char *tmp;
330 sound_expanded = switch_channel_expand_variables(channel, sound)switch_channel_expand_variables_check(channel, sound, ((void*
)0), ((void*)0), 0)
;
331 if ((tmp = switch_channel_get_variable(channel, "ivr_menu_terminator")switch_channel_get_variable_dup(channel, "ivr_menu_terminator"
, SWITCH_TRUE, -1)
) && !zstr(tmp)_zstr(tmp)) {
332 terminator_str = tmp;
333 }
334 }
335
336 memset(menu->buf, 0, menu->inlen + 1);
337 menu->ptr = menu->buf;
338
339 if (!need) {
340 len = 1;
341 ptr = NULL((void*)0);
342 } else {
343 len = (uint32_t) menu->inlen + 1;
344 ptr = menu->ptr;
345 }
346 args.buf = ptr;
347 args.buflen = len;
348
349 status = switch_ivr_play_file(session, NULL((void*)0), sound_expanded, &args);
350
351 if (sound_expanded != sound) {
352 switch_safe_free(sound_expanded)if (sound_expanded) {free(sound_expanded);sound_expanded=((void
*)0);}
;
353 }
354
355 if (!need) {
356 return status;
357 }
358
359 menu_buf_len = strlen(menu->buf);
360
361 menu->ptr += menu_buf_len;
362 if (menu_buf_len < need) {
363 switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session)SWITCH_CHANNEL_ID_SESSION, "src/switch_ivr_menu.c", (const char
*)__func__, 363, (const char*)(session)
, SWITCH_LOG_DEBUG, "waiting for %u/%u digits t/o %d\n",
364 (uint32_t) (menu->inlen - strlen(menu->buf)), (uint32_t) need, menu->inter_timeout);
365 status = switch_ivr_collect_digits_count(session, menu->ptr, menu->inlen - strlen(menu->buf),
366 need, terminator_str, &terminator, menu_buf_len ? menu->inter_timeout : menu->timeout,
367 menu->inter_timeout, menu->timeout);
368 }
369
370 if (menu->confirm_macro && status == SWITCH_STATUS_SUCCESS && *menu->buf != '\0') {
371 switch_input_args_t confirm_args = { 0 }, *ap = NULL((void*)0);
372 char buf[10] = "";
373 char terminator_key;
374 int att = menu->confirm_attempts;
375
376 while (att) {
377 confirm_args.buf = buf;
378 confirm_args.buflen = sizeof(buf);
379 memset(buf, 0, confirm_args.buflen);
380
381 if (menu->confirm_key) {
382 ap = &confirm_args;
383 }
384
385 switch_ivr_phrase_macro(session, menu->confirm_macro, menu->buf, NULL, ap)switch_ivr_phrase_macro_event(session, menu->confirm_macro
, menu->buf, ((void*)0), ((void*)0), ap)
;
386
387 if (menu->confirm_key && *buf == '\0') {
388 switch_ivr_collect_digits_count(session, buf, sizeof(buf), 1, terminator_str, &terminator_key, menu->timeout, 0, 0);
389 }
390
391 if (menu->confirm_key && *buf != '\0') {
392 if (*menu->confirm_key == *buf) {
393 switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session)SWITCH_CHANNEL_ID_SESSION, "src/switch_ivr_menu.c", (const char
*)__func__, 393, (const char*)(session)
, SWITCH_LOG_DEBUG,
394 "approving digits '%s' via confirm key %s\n", menu->buf, menu->confirm_key);
395 break;
396 } else {
397 att = 0;
398 break;
399 }
400 }
401 att--;
402 }
403 if (!att) {
404 switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session)SWITCH_CHANNEL_ID_SESSION, "src/switch_ivr_menu.c", (const char
*)__func__, 404, (const char*)(session)
, SWITCH_LOG_DEBUG, "rejecting digits '%s' via confirm key %s\n", menu->buf,
405 menu->confirm_key);
406 *menu->buf = '\0';
407 }
408 }
409
410 switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session)SWITCH_CHANNEL_ID_SESSION, "src/switch_ivr_menu.c", (const char
*)__func__, 410, (const char*)(session)
, SWITCH_LOG_DEBUG, "digits '%s'\n", menu->buf);
411
412 return status;
413}
414
415static void exec_app(switch_core_session_t *session, char *app_str)
416{
417 switch_channel_t *channel = switch_core_session_get_channel(session);
418 char *app = switch_core_session_strdup(session, app_str)switch_core_perform_session_strdup(session, app_str, "src/switch_ivr_menu.c"
, (const char *)__func__, 418)
;
419 char *data = strchr(app, ' ')(__extension__ (__builtin_constant_p (' ') && !__builtin_constant_p
(app) && (' ') == '\0' ? (char *) __rawmemchr (app, ' '
) : __builtin_strchr (app, ' ')))
;
420 char *expanded = NULL((void*)0);
421
422 if (data) {
423 *data++ = '\0';
424 }
425
426 expanded = switch_channel_expand_variables(channel, data)switch_channel_expand_variables_check(channel, data, ((void*)
0), ((void*)0), 0)
;
427
428 switch_core_session_execute_application(session, app, expanded)switch_core_session_execute_application_get_flags(session, app
, expanded, ((void*)0))
;
429
430 if (expanded && expanded != data) {
431 free(expanded);
432 }
433
434}
435
436SWITCH_DECLARE(switch_status_t)__attribute__((visibility("default"))) switch_status_t switch_ivr_menu_execute(switch_core_session_t *session, switch_ivr_menu_t *stack, char *name, void *obj)
437{
438 int reps = 0, errs = 0, timeouts = 0, match = 0, running = 1;
439 char *greeting_sound = NULL((void*)0), *aptr = NULL((void*)0);
440 char arg[512];
441 switch_ivr_action_t todo = SWITCH_IVR_ACTION_DIE;
442 switch_ivr_menu_action_t *ap;
443 switch_ivr_menu_t *menu;
444 switch_channel_t *channel;
445 switch_status_t status = SWITCH_STATUS_SUCCESS;
446
447 if (++stack->stack_count > 12) {
448 switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session)SWITCH_CHANNEL_ID_SESSION, "src/switch_ivr_menu.c", (const char
*)__func__, 448, (const char*)(session)
, SWITCH_LOG_ERROR, "Too many levels of recursion.\n");
449 switch_goto_status(SWITCH_STATUS_FALSE, end)status = SWITCH_STATUS_FALSE; goto end;
450 }
451
452 if (!session || !stack || zstr(name)_zstr(name)) {
453 switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session)SWITCH_CHANNEL_ID_SESSION, "src/switch_ivr_menu.c", (const char
*)__func__, 453, (const char*)(session)
, SWITCH_LOG_ERROR, "Invalid menu context\n");
454 switch_goto_status(SWITCH_STATUS_FALSE, end)status = SWITCH_STATUS_FALSE; goto end;
455 }
456
457 channel = switch_core_session_get_channel(session);
458
459 if (!(menu = switch_ivr_menu_find(stack, name))) {
460 switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session)SWITCH_CHANNEL_ID_SESSION, "src/switch_ivr_menu.c", (const char
*)__func__, 460, (const char*)(session)
, SWITCH_LOG_ERROR, "Invalid Menu!\n");
461 switch_goto_status(SWITCH_STATUS_FALSE, end)status = SWITCH_STATUS_FALSE; goto end;
462 }
463
464 if (!zstr(menu->tts_engine)_zstr(menu->tts_engine) && !zstr(menu->tts_voice)_zstr(menu->tts_voice)) {
465 switch_channel_set_variable(channel, "tts_engine", menu->tts_engine)switch_channel_set_variable_var_check(channel, "tts_engine", menu
->tts_engine, SWITCH_TRUE)
;
466 switch_channel_set_variable(channel, "tts_voice", menu->tts_voice)switch_channel_set_variable_var_check(channel, "tts_voice", menu
->tts_voice, SWITCH_TRUE)
;
467 }
468
469 switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session)SWITCH_CHANNEL_ID_SESSION, "src/switch_ivr_menu.c", (const char
*)__func__, 469, (const char*)(session)
, SWITCH_LOG_DEBUG, "Executing IVR menu %s\n", menu->name);
470 switch_channel_set_variable(channel, "ivr_menu_status", "success")switch_channel_set_variable_var_check(channel, "ivr_menu_status"
, "success", SWITCH_TRUE)
;
471
472 if (!zstr(menu->pin)_zstr(menu->pin)) {
473 char digit_buffer[128] = "";
474 char *digits_regex = switch_core_session_sprintf(session, "^%s$", menu->pin);
475
476 if (switch_play_and_get_digits(session, (uint32_t)strlen(menu->pin), (uint32_t)strlen(menu->pin), 3, 3000, "#",
477 menu->prompt_pin_file, menu->bad_pin_file, NULL((void*)0), digit_buffer, sizeof(digit_buffer),
478 digits_regex, 10000, NULL((void*)0)) != SWITCH_STATUS_SUCCESS) {
479 switch_goto_status(SWITCH_STATUS_FALSE, end)status = SWITCH_STATUS_FALSE; goto end;
480 }
481 }
482
483
484 for (reps = 0; running && status == SWITCH_STATUS_SUCCESS; reps++) {
485 if (!switch_channel_ready(channel)switch_channel_test_ready(channel, SWITCH_TRUE, SWITCH_FALSE)) {
486 break;
487 }
488 if (errs == menu->max_failures) {
489 switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session)SWITCH_CHANNEL_ID_SESSION, "src/switch_ivr_menu.c", (const char
*)__func__, 489, (const char*)(session)
, SWITCH_LOG_DEBUG, "Maximum failures\n");
490 switch_channel_set_variable(channel, "ivr_menu_status", "failure")switch_channel_set_variable_var_check(channel, "ivr_menu_status"
, "failure", SWITCH_TRUE)
;
491 if (!zstr(menu->exec_on_max_fail)_zstr(menu->exec_on_max_fail)) {
492 exec_app(session, menu->exec_on_max_fail);
493 }
494 break;
495 }
496 if (timeouts == menu->max_timeouts) {
497 switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session)SWITCH_CHANNEL_ID_SESSION, "src/switch_ivr_menu.c", (const char
*)__func__, 497, (const char*)(session)
, SWITCH_LOG_DEBUG, "Maximum timeouts\n");
498 switch_channel_set_variable(channel, "ivr_menu_status", "timeout")switch_channel_set_variable_var_check(channel, "ivr_menu_status"
, "timeout", SWITCH_TRUE)
;
499 if (!zstr(menu->exec_on_max_timeout)_zstr(menu->exec_on_max_timeout)) {
500 exec_app(session, menu->exec_on_max_timeout);
501 }
502 break;
503 }
504
505 if (reps > 0 && menu->short_greeting_sound) {
506 greeting_sound = menu->short_greeting_sound;
507 } else {
508 greeting_sound = menu->greeting_sound;
509 }
510
511 match = 0;
512 aptr = NULL((void*)0);
513
514 memset(arg, 0, sizeof(arg));
515
516 memset(menu->buf, 0, menu->inlen + 1);
517
518 if (play_and_collect(session, menu, greeting_sound, menu->inlen) == SWITCH_STATUS_TIMEOUT && *menu->buf == '\0') {
519 timeouts++;
520 continue;
521 }
522
523 if (*menu->buf != '\0') {
524
525 for (ap = menu->actions; ap; ap = ap->next) {
526 int ok = 0;
527 char substituted[1024];
528 char *use_arg = ap->arg;
529
530 if (!zstr(menu->tts_engine)_zstr(menu->tts_engine) && !zstr(menu->tts_voice)_zstr(menu->tts_voice)) {
531 switch_channel_set_variable(channel, "tts_engine", menu->tts_engine)switch_channel_set_variable_var_check(channel, "tts_engine", menu
->tts_engine, SWITCH_TRUE)
;
532 switch_channel_set_variable(channel, "tts_voice", menu->tts_voice)switch_channel_set_variable_var_check(channel, "tts_voice", menu
->tts_voice, SWITCH_TRUE)
;
533 }
534
535 if (ap->re) {
536 switch_regex_t *re = NULL((void*)0);
537 int ovector[30];
538
539 if ((ok = switch_regex_perform(menu->buf, ap->bind, &re, ovector, sizeof(ovector) / sizeof(ovector[0])))) {
540 switch_perform_substitution(re, ok, ap->arg, menu->buf, substituted, sizeof(substituted), ovector);
541 use_arg = substituted;
542 }
543 switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session)SWITCH_CHANNEL_ID_SESSION, "src/switch_ivr_menu.c", (const char
*)__func__, 543, (const char*)(session)
, SWITCH_LOG_DEBUG, "action regex [%s] [%s] [%d]\n", menu->buf, ap->bind, ok);
544
545 switch_regex_safe_free(re)if (re) { switch_regex_free(re); re = ((void*)0); };
546 } else {
547 ok = !strcmp(menu->buf, ap->bind)__extension__ ({ size_t __s1_len, __s2_len; (__builtin_constant_p
(menu->buf) && __builtin_constant_p (ap->bind)
&& (__s1_len = __builtin_strlen (menu->buf), __s2_len
= __builtin_strlen (ap->bind), (!((size_t)(const void *)(
(menu->buf) + 1) - (size_t)(const void *)(menu->buf) ==
1) || __s1_len >= 4) && (!((size_t)(const void *)
((ap->bind) + 1) - (size_t)(const void *)(ap->bind) == 1
) || __s2_len >= 4)) ? __builtin_strcmp (menu->buf, ap->
bind) : (__builtin_constant_p (menu->buf) && ((size_t
)(const void *)((menu->buf) + 1) - (size_t)(const void *)(
menu->buf) == 1) && (__s1_len = __builtin_strlen (
menu->buf), __s1_len < 4) ? (__builtin_constant_p (ap->
bind) && ((size_t)(const void *)((ap->bind) + 1) -
(size_t)(const void *)(ap->bind) == 1) ? __builtin_strcmp
(menu->buf, ap->bind) : (__extension__ ({ const unsigned
char *__s2 = (const unsigned char *) (const char *) (ap->
bind); int __result = (((const unsigned char *) (const char *
) (menu->buf))[0] - __s2[0]); if (__s1_len > 0 &&
__result == 0) { __result = (((const unsigned char *) (const
char *) (menu->buf))[1] - __s2[1]); if (__s1_len > 1 &&
__result == 0) { __result = (((const unsigned char *) (const
char *) (menu->buf))[2] - __s2[2]); if (__s1_len > 2 &&
__result == 0) __result = (((const unsigned char *) (const char
*) (menu->buf))[3] - __s2[3]); } } __result; }))) : (__builtin_constant_p
(ap->bind) && ((size_t)(const void *)((ap->bind
) + 1) - (size_t)(const void *)(ap->bind) == 1) &&
(__s2_len = __builtin_strlen (ap->bind), __s2_len < 4)
? (__builtin_constant_p (menu->buf) && ((size_t)(
const void *)((menu->buf) + 1) - (size_t)(const void *)(menu
->buf) == 1) ? __builtin_strcmp (menu->buf, ap->bind
) : (- (__extension__ ({ const unsigned char *__s2 = (const unsigned
char *) (const char *) (menu->buf); int __result = (((const
unsigned char *) (const char *) (ap->bind))[0] - __s2[0])
; if (__s2_len > 0 && __result == 0) { __result = (
((const unsigned char *) (const char *) (ap->bind))[1] - __s2
[1]); if (__s2_len > 1 && __result == 0) { __result
= (((const unsigned char *) (const char *) (ap->bind))[2]
- __s2[2]); if (__s2_len > 2 && __result == 0) __result
= (((const unsigned char *) (const char *) (ap->bind))[3]
- __s2[3]); } } __result; })))) : __builtin_strcmp (menu->
buf, ap->bind)))); })
;
548 }
549
550 if (ok) {
551 match++;
552 errs = 0;
553 if (ap->function) {
554 switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session)SWITCH_CHANNEL_ID_SESSION, "src/switch_ivr_menu.c", (const char
*)__func__, 554, (const char*)(session)
, SWITCH_LOG_DEBUG,
555 "IVR function on menu '%s' matched '%s' param '%s'\n", menu->name, menu->buf, use_arg);
556 todo = ap->function(menu, use_arg, arg, sizeof(arg), obj);
557 aptr = arg;
558 } else {
559 todo = ap->ivr_action;
560 aptr = use_arg;
561 switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session)SWITCH_CHANNEL_ID_SESSION, "src/switch_ivr_menu.c", (const char
*)__func__, 561, (const char*)(session)
, SWITCH_LOG_DEBUG,
562 "IVR action on menu '%s' matched '%s' param '%s'\n", menu->name, menu->buf, aptr);
563 }
564
565 switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session)SWITCH_CHANNEL_ID_SESSION, "src/switch_ivr_menu.c", (const char
*)__func__, 565, (const char*)(session)
, SWITCH_LOG_DEBUG, "switch_ivr_menu_execute todo=[%d]\n", todo);
566
567 switch (todo) {
568 case SWITCH_IVR_ACTION_DIE:
569 status = SWITCH_STATUS_FALSE;
570 break;
571 case SWITCH_IVR_ACTION_PLAYSOUND:
572 status = switch_ivr_play_file(session, NULL((void*)0), aptr, NULL((void*)0));
573 break;
574 case SWITCH_IVR_ACTION_EXECMENU:
575 if (!strcmp(aptr, menu->name)__extension__ ({ size_t __s1_len, __s2_len; (__builtin_constant_p
(aptr) && __builtin_constant_p (menu->name) &&
(__s1_len = __builtin_strlen (aptr), __s2_len = __builtin_strlen
(menu->name), (!((size_t)(const void *)((aptr) + 1) - (size_t
)(const void *)(aptr) == 1) || __s1_len >= 4) && (
!((size_t)(const void *)((menu->name) + 1) - (size_t)(const
void *)(menu->name) == 1) || __s2_len >= 4)) ? __builtin_strcmp
(aptr, menu->name) : (__builtin_constant_p (aptr) &&
((size_t)(const void *)((aptr) + 1) - (size_t)(const void *)
(aptr) == 1) && (__s1_len = __builtin_strlen (aptr), __s1_len
< 4) ? (__builtin_constant_p (menu->name) && (
(size_t)(const void *)((menu->name) + 1) - (size_t)(const void
*)(menu->name) == 1) ? __builtin_strcmp (aptr, menu->name
) : (__extension__ ({ const unsigned char *__s2 = (const unsigned
char *) (const char *) (menu->name); int __result = (((const
unsigned char *) (const char *) (aptr))[0] - __s2[0]); if (__s1_len
> 0 && __result == 0) { __result = (((const unsigned
char *) (const char *) (aptr))[1] - __s2[1]); if (__s1_len >
1 && __result == 0) { __result = (((const unsigned char
*) (const char *) (aptr))[2] - __s2[2]); if (__s1_len > 2
&& __result == 0) __result = (((const unsigned char *
) (const char *) (aptr))[3] - __s2[3]); } } __result; }))) : (
__builtin_constant_p (menu->name) && ((size_t)(const
void *)((menu->name) + 1) - (size_t)(const void *)(menu->
name) == 1) && (__s2_len = __builtin_strlen (menu->
name), __s2_len < 4) ? (__builtin_constant_p (aptr) &&
((size_t)(const void *)((aptr) + 1) - (size_t)(const void *)
(aptr) == 1) ? __builtin_strcmp (aptr, menu->name) : (- (__extension__
({ const unsigned char *__s2 = (const unsigned char *) (const
char *) (aptr); int __result = (((const unsigned char *) (const
char *) (menu->name))[0] - __s2[0]); if (__s2_len > 0 &&
__result == 0) { __result = (((const unsigned char *) (const
char *) (menu->name))[1] - __s2[1]); if (__s2_len > 1 &&
__result == 0) { __result = (((const unsigned char *) (const
char *) (menu->name))[2] - __s2[2]); if (__s2_len > 2 &&
__result == 0) __result = (((const unsigned char *) (const char
*) (menu->name))[3] - __s2[3]); } } __result; })))) : __builtin_strcmp
(aptr, menu->name)))); })
) {
576 status = SWITCH_STATUS_SUCCESS;
577 } else {
578 reps = -1;
579 status = switch_ivr_menu_execute(session, stack, aptr, obj);
580 }
581 break;
582 case SWITCH_IVR_ACTION_EXECAPP:
583 {
584 switch_application_interface_t *application_interface;
585 char *app_name;
586 char *app_arg = NULL((void*)0);
587
588 status = SWITCH_STATUS_FALSE;
589
590 if (!zstr(aptr)_zstr(aptr)) {
591 app_name = switch_core_session_strdup(session, aptr)switch_core_perform_session_strdup(session, aptr, "src/switch_ivr_menu.c"
, (const char *)__func__, 591)
;
592 if ((app_arg = strchr(app_name, ' ')(__extension__ (__builtin_constant_p (' ') && !__builtin_constant_p
(app_name) && (' ') == '\0' ? (char *) __rawmemchr (
app_name, ' ') : __builtin_strchr (app_name, ' ')))
)) {
593 *app_arg++ = '\0';
594 }
595
596 if ((application_interface = switch_loadable_module_get_application_interface(app_name))) {
597 if (!zstr(menu->transfer_sound)_zstr(menu->transfer_sound) && !strcmp(app_name, "transfer")__extension__ ({ size_t __s1_len, __s2_len; (__builtin_constant_p
(app_name) && __builtin_constant_p ("transfer") &&
(__s1_len = __builtin_strlen (app_name), __s2_len = __builtin_strlen
("transfer"), (!((size_t)(const void *)((app_name) + 1) - (size_t
)(const void *)(app_name) == 1) || __s1_len >= 4) &&
(!((size_t)(const void *)(("transfer") + 1) - (size_t)(const
void *)("transfer") == 1) || __s2_len >= 4)) ? __builtin_strcmp
(app_name, "transfer") : (__builtin_constant_p (app_name) &&
((size_t)(const void *)((app_name) + 1) - (size_t)(const void
*)(app_name) == 1) && (__s1_len = __builtin_strlen (
app_name), __s1_len < 4) ? (__builtin_constant_p ("transfer"
) && ((size_t)(const void *)(("transfer") + 1) - (size_t
)(const void *)("transfer") == 1) ? __builtin_strcmp (app_name
, "transfer") : (__extension__ ({ const unsigned char *__s2 =
(const unsigned char *) (const char *) ("transfer"); int __result
= (((const unsigned char *) (const char *) (app_name))[0] - __s2
[0]); if (__s1_len > 0 && __result == 0) { __result
= (((const unsigned char *) (const char *) (app_name))[1] - __s2
[1]); if (__s1_len > 1 && __result == 0) { __result
= (((const unsigned char *) (const char *) (app_name))[2] - __s2
[2]); if (__s1_len > 2 && __result == 0) __result =
(((const unsigned char *) (const char *) (app_name))[3] - __s2
[3]); } } __result; }))) : (__builtin_constant_p ("transfer")
&& ((size_t)(const void *)(("transfer") + 1) - (size_t
)(const void *)("transfer") == 1) && (__s2_len = __builtin_strlen
("transfer"), __s2_len < 4) ? (__builtin_constant_p (app_name
) && ((size_t)(const void *)((app_name) + 1) - (size_t
)(const void *)(app_name) == 1) ? __builtin_strcmp (app_name,
"transfer") : (- (__extension__ ({ const unsigned char *__s2
= (const unsigned char *) (const char *) (app_name); int __result
= (((const unsigned char *) (const char *) ("transfer"))[0] -
__s2[0]); if (__s2_len > 0 && __result == 0) { __result
= (((const unsigned char *) (const char *) ("transfer"))[1] -
__s2[1]); if (__s2_len > 1 && __result == 0) { __result
= (((const unsigned char *) (const char *) ("transfer"))[2] -
__s2[2]); if (__s2_len > 2 && __result == 0) __result
= (((const unsigned char *) (const char *) ("transfer"))[3] -
__s2[3]); } } __result; })))) : __builtin_strcmp (app_name, "transfer"
)))); })
) {
598 status = play_and_collect(session, menu, menu->transfer_sound, 0);
Value stored to 'status' is never read
599 }
600
601 switch_core_session_exec(session, application_interface, app_arg);
602 UNPROTECT_INTERFACE(application_interface)if (application_interface) {switch_mutex_lock(application_interface
->reflock); switch_thread_rwlock_unlock(application_interface
->rwlock); switch_thread_rwlock_unlock(application_interface
->parent->rwlock); application_interface->refs--; application_interface
->parent->refs--; switch_mutex_unlock(application_interface
->reflock);}
;
603 status = SWITCH_STATUS_SUCCESS;
604 }
605 }
606 }
607 break;
608 case SWITCH_IVR_ACTION_BACK:
609 running = 0;
610 status = SWITCH_STATUS_SUCCESS;
611 break;
612 case SWITCH_IVR_ACTION_TOMAIN:
613 switch_set_flag(stack, SWITCH_IVR_MENU_FLAG_FALLTOMAIN)(stack)->flags |= (SWITCH_IVR_MENU_FLAG_FALLTOMAIN);
614 status = SWITCH_STATUS_BREAK;
615 break;
616 case SWITCH_IVR_ACTION_NOOP:
617 status = SWITCH_STATUS_SUCCESS;
618 break;
619 default:
620 switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session)SWITCH_CHANNEL_ID_SESSION, "src/switch_ivr_menu.c", (const char
*)__func__, 620, (const char*)(session)
, SWITCH_LOG_WARNING, "Invalid TODO!\n");
621 break;
622 }
623 }
624 }
625
626 if (switch_test_flag(menu, SWITCH_IVR_MENU_FLAG_STACK)((menu)->flags & SWITCH_IVR_MENU_FLAG_STACK)) { /* top level */
627 if (switch_test_flag(stack, SWITCH_IVR_MENU_FLAG_FALLTOMAIN)((stack)->flags & SWITCH_IVR_MENU_FLAG_FALLTOMAIN)) { /* catch the fallback and recover */
628 switch_clear_flag(stack, SWITCH_IVR_MENU_FLAG_FALLTOMAIN)(stack)->flags &= ~(SWITCH_IVR_MENU_FLAG_FALLTOMAIN);
629 status = SWITCH_STATUS_SUCCESS;
630 running = 1;
631 continue;
632 }
633 }
634 }
635 if (!match) {
636 if (*menu->buf) {
637 switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session)SWITCH_CHANNEL_ID_SESSION, "src/switch_ivr_menu.c", (const char
*)__func__, 637, (const char*)(session)
, SWITCH_LOG_DEBUG, "IVR menu '%s' caught invalid input '%s'\n", menu->name,
638 menu->buf);
639 if (menu->invalid_sound) {
640 play_and_collect(session, menu, menu->invalid_sound, 0);
641 }
642 } else {
643 switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session)SWITCH_CHANNEL_ID_SESSION, "src/switch_ivr_menu.c", (const char
*)__func__, 643, (const char*)(session)
, SWITCH_LOG_DEBUG, "IVR menu '%s' no input detected\n", menu->name);
644 }
645 errs++;
646
647 /* breaks are ok too */
648 if (SWITCH_STATUS_IS_BREAK(status)(status == SWITCH_STATUS_BREAK || status == 730035 || status ==
35 || status == SWITCH_STATUS_INTR)
) {
649 status = SWITCH_STATUS_SUCCESS;
650 }
651 }
652 }
653
654 if (stack->stack_count == 1) {
655 switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session)SWITCH_CHANNEL_ID_SESSION, "src/switch_ivr_menu.c", (const char
*)__func__, 655, (const char*)(session)
, SWITCH_LOG_DEBUG, "exit-sound '%s'\n", menu->exit_sound);
656 if (!zstr(menu->exit_sound)_zstr(menu->exit_sound)) {
657 status = play_and_collect(session, menu, menu->exit_sound, 0);
658 }
659 }
660
661 end:
662
663 stack->stack_count--;
664
665 return status;
666}
667
668/******************************************************************************************************/
669
670typedef struct switch_ivr_menu_xml_map {
671 char *name;
672 switch_ivr_action_t action;
673 switch_ivr_menu_action_function_t *function;
674 struct switch_ivr_menu_xml_map *next;
675} switch_ivr_menu_xml_map_t;
676
677struct switch_ivr_menu_xml_ctx {
678 switch_memory_pool_t *pool;
679 struct switch_ivr_menu_xml_map *map;
680 int autocreated;
681};
682
683static switch_ivr_menu_xml_map_t *switch_ivr_menu_stack_xml_find(switch_ivr_menu_xml_ctx_t *xml_ctx, const char *name)
684{
685 switch_ivr_menu_xml_map_t *map = (xml_ctx != NULL((void*)0) ? xml_ctx->map : NULL((void*)0));
686 int rc = -1;
687
688 while (map != NULL((void*)0) && (rc = strcasecmp(map->name, name)) != 0) {
689 map = map->next;
690 }
691
692 return (rc == 0 ? map : NULL((void*)0));
693}
694
695static switch_status_t switch_ivr_menu_stack_xml_add(switch_ivr_menu_xml_ctx_t *xml_ctx, const char *name, int action,
696 switch_ivr_menu_action_function_t *function)
697{
698 switch_status_t status = SWITCH_STATUS_FALSE;
699
700 /* if this action/function does not exist yet */
701 if (xml_ctx != NULL((void*)0) && name != NULL((void*)0) && xml_ctx->pool != NULL((void*)0) && switch_ivr_menu_stack_xml_find(xml_ctx, name) == NULL((void*)0)) {
702 switch_ivr_menu_xml_map_t *map = switch_core_alloc(xml_ctx->pool, sizeof(switch_ivr_menu_xml_map_t))switch_core_perform_alloc(xml_ctx->pool, sizeof(switch_ivr_menu_xml_map_t
), "src/switch_ivr_menu.c", (const char *)__func__, 702)
;
703
704 if (map != NULL((void*)0)) {
705 map->name = switch_core_strdup(xml_ctx->pool, name)switch_core_perform_strdup(xml_ctx->pool, name, "src/switch_ivr_menu.c"
, (const char *)__func__, 705)
;
706 map->action = action;
707 map->function = function;
708
709 if (map->name != NULL((void*)0)) {
710 /* insert map item at top of list */
711 map->next = xml_ctx->map;
712 xml_ctx->map = map;
713 status = SWITCH_STATUS_SUCCESS;
714 } else {
715 status = SWITCH_STATUS_MEMERR;
716 }
717 } else {
718 status = SWITCH_STATUS_MEMERR;
719 }
720
721 switch_log_printf(SWITCH_CHANNEL_LOGSWITCH_CHANNEL_ID_LOG, "src/switch_ivr_menu.c", (const char *
)__func__, 721, ((void*)0)
, SWITCH_LOG_DEBUG, "switch_ivr_menu_stack_xml_add binding '%s'\n", name);
722 } else {
723 switch_log_printf(SWITCH_CHANNEL_LOGSWITCH_CHANNEL_ID_LOG, "src/switch_ivr_menu.c", (const char *
)__func__, 723, ((void*)0)
, SWITCH_LOG_ERROR, "Unable to add binding %s\n", name);
724 }
725
726 return status;
727}
728
729static struct iam_s {
730 const char *name;
731 switch_ivr_action_t action;
732} iam[] = {
733 {
734 "menu-exit", SWITCH_IVR_ACTION_DIE}, {
735 "menu-sub", SWITCH_IVR_ACTION_EXECMENU}, {
736 "menu-exec-app", SWITCH_IVR_ACTION_EXECAPP}, {
737 "menu-play-sound", SWITCH_IVR_ACTION_PLAYSOUND}, {
738 "menu-back", SWITCH_IVR_ACTION_BACK}, {
739 "menu-top", SWITCH_IVR_ACTION_TOMAIN}, {
740 NULL((void*)0), 0}
741};
742
743SWITCH_DECLARE(switch_status_t)__attribute__((visibility("default"))) switch_status_t switch_ivr_menu_str2action(const char *action_name, switch_ivr_action_t *action)
744{
745 int i;
746
747 if (!zstr(action_name)_zstr(action_name)) {
748 for (i = 0;; i++) {
749 if (!iam[i].name) {
750 break;
751 }
752
753 if (!strcasecmp(iam[i].name, action_name)) {
754 *action = iam[i].action;
755 return SWITCH_STATUS_SUCCESS;
756 }
757 }
758 }
759
760 return SWITCH_STATUS_FALSE;
761}
762
763static switch_bool_t is_valid_action(const char *action)
764{
765 int i;
766
767 if (!zstr(action)_zstr(action)) {
768 for (i = 0;; i++) {
769 if (!iam[i].name) {
770 break;
771 }
772
773 if (!strcmp(iam[i].name, action)__extension__ ({ size_t __s1_len, __s2_len; (__builtin_constant_p
(iam[i].name) && __builtin_constant_p (action) &&
(__s1_len = __builtin_strlen (iam[i].name), __s2_len = __builtin_strlen
(action), (!((size_t)(const void *)((iam[i].name) + 1) - (size_t
)(const void *)(iam[i].name) == 1) || __s1_len >= 4) &&
(!((size_t)(const void *)((action) + 1) - (size_t)(const void
*)(action) == 1) || __s2_len >= 4)) ? __builtin_strcmp (iam
[i].name, action) : (__builtin_constant_p (iam[i].name) &&
((size_t)(const void *)((iam[i].name) + 1) - (size_t)(const void
*)(iam[i].name) == 1) && (__s1_len = __builtin_strlen
(iam[i].name), __s1_len < 4) ? (__builtin_constant_p (action
) && ((size_t)(const void *)((action) + 1) - (size_t)
(const void *)(action) == 1) ? __builtin_strcmp (iam[i].name,
action) : (__extension__ ({ const unsigned char *__s2 = (const
unsigned char *) (const char *) (action); int __result = (((
const unsigned char *) (const char *) (iam[i].name))[0] - __s2
[0]); if (__s1_len > 0 && __result == 0) { __result
= (((const unsigned char *) (const char *) (iam[i].name))[1]
- __s2[1]); if (__s1_len > 1 && __result == 0) { __result
= (((const unsigned char *) (const char *) (iam[i].name))[2]
- __s2[2]); if (__s1_len > 2 && __result == 0) __result
= (((const unsigned char *) (const char *) (iam[i].name))[3]
- __s2[3]); } } __result; }))) : (__builtin_constant_p (action
) && ((size_t)(const void *)((action) + 1) - (size_t)
(const void *)(action) == 1) && (__s2_len = __builtin_strlen
(action), __s2_len < 4) ? (__builtin_constant_p (iam[i].name
) && ((size_t)(const void *)((iam[i].name) + 1) - (size_t
)(const void *)(iam[i].name) == 1) ? __builtin_strcmp (iam[i]
.name, action) : (- (__extension__ ({ const unsigned char *__s2
= (const unsigned char *) (const char *) (iam[i].name); int __result
= (((const unsigned char *) (const char *) (action))[0] - __s2
[0]); if (__s2_len > 0 && __result == 0) { __result
= (((const unsigned char *) (const char *) (action))[1] - __s2
[1]); if (__s2_len > 1 && __result == 0) { __result
= (((const unsigned char *) (const char *) (action))[2] - __s2
[2]); if (__s2_len > 2 && __result == 0) __result =
(((const unsigned char *) (const char *) (action))[3] - __s2
[3]); } } __result; })))) : __builtin_strcmp (iam[i].name, action
)))); })
) {
774 return SWITCH_TRUE;
775 }
776 }
777 }
778
779 switch_log_printf(SWITCH_CHANNEL_LOGSWITCH_CHANNEL_ID_LOG, "src/switch_ivr_menu.c", (const char *
)__func__, 779, ((void*)0)
, SWITCH_LOG_WARNING, "Invalid Action [%s]\n", switch_str_nil(action)(action ? action : ""));
780 return SWITCH_FALSE;
781}
782
783SWITCH_DECLARE(switch_status_t)__attribute__((visibility("default"))) switch_status_t switch_ivr_menu_stack_xml_init(switch_ivr_menu_xml_ctx_t ** xml_menu_ctx, switch_memory_pool_t *pool)
784{
785 switch_status_t status = SWITCH_STATUS_FALSE;
786 int autocreated = 0;
787
788 /* build a memory pool ? */
789 if (pool == NULL((void*)0)) {
790 status = switch_core_new_memory_pool(&pool)switch_core_perform_new_memory_pool(&pool, "src/switch_ivr_menu.c"
, (const char *)__func__, 790)
;
791 autocreated = 1;
792 }
793 /* allocate the xml context */
794 if (xml_menu_ctx != NULL((void*)0) && pool != NULL((void*)0)) {
795 *xml_menu_ctx = switch_core_alloc(pool, sizeof(switch_ivr_menu_xml_ctx_t))switch_core_perform_alloc(pool, sizeof(switch_ivr_menu_xml_ctx_t
), "src/switch_ivr_menu.c", (const char *)__func__, 795)
;
796 if (*xml_menu_ctx != NULL((void*)0)) {
797 (*xml_menu_ctx)->pool = pool;
798 (*xml_menu_ctx)->autocreated = autocreated;
799 (*xml_menu_ctx)->map = NULL((void*)0);
800 status = SWITCH_STATUS_SUCCESS;
801 } else {
802 switch_log_printf(SWITCH_CHANNEL_LOGSWITCH_CHANNEL_ID_LOG, "src/switch_ivr_menu.c", (const char *
)__func__, 802, ((void*)0)
, SWITCH_LOG_ERROR, "Unable to alloc xml_ctx\n");
803 status = SWITCH_STATUS_FALSE;
804 }
805 }
806 /* build the standard/default xml menu handler mappings */
807 if (status == SWITCH_STATUS_SUCCESS && xml_menu_ctx != NULL((void*)0) && *xml_menu_ctx != NULL((void*)0)) {
808 int i;
809
810 for (i = 0; iam[i].name && status == SWITCH_STATUS_SUCCESS; i++) {
811 status = switch_ivr_menu_stack_xml_add(*xml_menu_ctx, iam[i].name, iam[i].action, NULL((void*)0));
812 }
813 }
814
815 return status;
816}
817
818SWITCH_DECLARE(switch_status_t)__attribute__((visibility("default"))) switch_status_t switch_ivr_menu_stack_xml_add_custom(switch_ivr_menu_xml_ctx_t *xml_menu_ctx,
819 const char *name, switch_ivr_menu_action_function_t *function)
820{
821 return switch_ivr_menu_stack_xml_add(xml_menu_ctx, name, -1, function);
822}
823
824SWITCH_DECLARE(switch_status_t)__attribute__((visibility("default"))) switch_status_t switch_ivr_menu_stack_xml_build(switch_ivr_menu_xml_ctx_t *xml_menu_ctx,
825 switch_ivr_menu_t ** menu_stack, switch_xml_t xml_menus, switch_xml_t xml_menu)
826{
827 switch_status_t status = SWITCH_STATUS_FALSE;
828
829 if (xml_menu_ctx != NULL((void*)0) && menu_stack != NULL((void*)0) && xml_menu != NULL((void*)0)) {
830 const char *menu_name = switch_xml_attr_soft(xml_menu, "name"); /* if the attr doesn't exist, return "" */
831 const char *greet_long = switch_xml_attr(xml_menu, "greet-long"); /* if the attr doesn't exist, return NULL */
832 const char *greet_short = switch_xml_attr(xml_menu, "greet-short"); /* if the attr doesn't exist, return NULL */
833 const char *invalid_sound = switch_xml_attr(xml_menu, "invalid-sound"); /* if the attr doesn't exist, return NULL */
834 const char *exit_sound = switch_xml_attr(xml_menu, "exit-sound"); /* if the attr doesn't exist, return NULL */
835 const char *transfer_sound = switch_xml_attr(xml_menu, "transfer-sound"); /* if the attr doesn't exist, return NULL */
836 const char *timeout = switch_xml_attr_soft(xml_menu, "timeout"); /* if the attr doesn't exist, return "" */
837 const char *max_failures = switch_xml_attr_soft(xml_menu, "max-failures"); /* if the attr doesn't exist, return "" */
838 const char *max_timeouts = switch_xml_attr_soft(xml_menu, "max-timeouts");
839 const char *exec_on_max_fail = switch_xml_attr(xml_menu, "exec-on-max-failures");
840 const char *exec_on_max_timeout = switch_xml_attr(xml_menu, "exec-on-max-timeouts");
841 const char *confirm_macro = switch_xml_attr(xml_menu, "confirm-macro");
842 const char *confirm_key = switch_xml_attr(xml_menu, "confirm-key");
843 const char *tts_engine = switch_xml_attr(xml_menu, "tts-engine");
844 const char *tts_voice = switch_xml_attr(xml_menu, "tts-voice");
845 const char *confirm_attempts = switch_xml_attr_soft(xml_menu, "confirm-attempts");
846 const char *digit_len = switch_xml_attr_soft(xml_menu, "digit-len");
847 const char *inter_timeout = switch_xml_attr_soft(xml_menu, "inter-digit-timeout");
848 const char *pin = switch_xml_attr_soft(xml_menu, "pin");
849 const char *prompt_pin_file = switch_xml_attr_soft(xml_menu, "pin-file");
850 const char *bad_pin_file = switch_xml_attr_soft(xml_menu, "bad-pin-file");
851
852 switch_ivr_menu_t *menu = NULL((void*)0);
853
854 if (zstr(max_timeouts)_zstr(max_timeouts)) {
855 max_timeouts = max_failures;
856 }
857
858 switch_log_printf(SWITCH_CHANNEL_LOGSWITCH_CHANNEL_ID_LOG, "src/switch_ivr_menu.c", (const char *
)__func__, 858, ((void*)0)
, SWITCH_LOG_DEBUG, "building menu '%s'\n", menu_name);
859
860 status = switch_ivr_menu_init(&menu,
861 *menu_stack,
862 menu_name,
863 greet_long,
864 greet_short,
865 invalid_sound,
866 exit_sound,
867 transfer_sound,
868 confirm_macro,
869 confirm_key,
870 tts_engine,
871 tts_voice,
872 atoi(confirm_attempts),
873 atoi(inter_timeout),
874 atoi(digit_len),
875 atoi(timeout),
876 strlen(max_failures) ? atoi(max_failures) : 0, strlen(max_timeouts) ? atoi(max_timeouts) : 0, xml_menu_ctx->pool);
877
878
879 if (!zstr(exec_on_max_fail)_zstr(exec_on_max_fail)) {
880 menu->exec_on_max_fail = switch_core_strdup(menu->pool, exec_on_max_fail)switch_core_perform_strdup(menu->pool, exec_on_max_fail, "src/switch_ivr_menu.c"
, (const char *)__func__, 880)
;
881 }
882
883 if (!zstr(exec_on_max_timeout)_zstr(exec_on_max_timeout)) {
884 menu->exec_on_max_timeout = switch_core_strdup(menu->pool, exec_on_max_timeout)switch_core_perform_strdup(menu->pool, exec_on_max_timeout
, "src/switch_ivr_menu.c", (const char *)__func__, 884)
;
885 }
886
887 if (!zstr(pin)_zstr(pin)) {
888 if (zstr(prompt_pin_file)_zstr(prompt_pin_file)) {
889 prompt_pin_file = "ivr/ivr-please_enter_pin_followed_by_pound.wav";
890 }
891 if (zstr(bad_pin_file)_zstr(bad_pin_file)) {
892 bad_pin_file = "conference/conf-bad-pin.wav";
893 }
894 menu->pin = switch_core_strdup(menu->pool, pin)switch_core_perform_strdup(menu->pool, pin, "src/switch_ivr_menu.c"
, (const char *)__func__, 894)
;
895 menu->prompt_pin_file = switch_core_strdup(menu->pool, prompt_pin_file)switch_core_perform_strdup(menu->pool, prompt_pin_file, "src/switch_ivr_menu.c"
, (const char *)__func__, 895)
;
896 menu->bad_pin_file = switch_core_strdup(menu->pool, bad_pin_file)switch_core_perform_strdup(menu->pool, bad_pin_file, "src/switch_ivr_menu.c"
, (const char *)__func__, 896)
;
897 }
898
899 /* set the menu_stack for the caller */
900 if (status == SWITCH_STATUS_SUCCESS && *menu_stack == NULL((void*)0)) {
901 *menu_stack = menu;
902
903 if (xml_menu_ctx->autocreated) {
904 switch_set_flag(menu, SWITCH_IVR_MENU_FLAG_FREEPOOL)(menu)->flags |= (SWITCH_IVR_MENU_FLAG_FREEPOOL);
905 }
906 }
907
908 if (status == SWITCH_STATUS_SUCCESS && menu != NULL((void*)0)) {
909 switch_xml_t xml_kvp;
910
911 /* build menu entries */
912 for (xml_kvp = switch_xml_child(xml_menu, "entry"); xml_kvp != NULL((void*)0) && status == SWITCH_STATUS_SUCCESS; xml_kvp = xml_kvp->next) {
913 const char *action = switch_xml_attr(xml_kvp, "action");
914 const char *digits = switch_xml_attr(xml_kvp, "digits");
915 const char *param = switch_xml_attr_soft(xml_kvp, "param");
916
917 if (is_valid_action(action) && !zstr(digits)_zstr(digits)) {
918 switch_ivr_menu_xml_map_t *xml_map = xml_menu_ctx->map;
919 int found = 0;
920
921 /* find and appropriate xml handler */
922 while (xml_map != NULL((void*)0) && !found) {
923 if (!(found = (strcasecmp(xml_map->name, action) == 0))) {
924 xml_map = xml_map->next;
925 }
926 }
927
928 if (found && xml_map != NULL((void*)0)) {
929 /* do we need to build a new sub-menu ? */
930 if (xml_map->action == SWITCH_IVR_ACTION_EXECMENU && switch_ivr_menu_find(*menu_stack, param) == NULL((void*)0)) {
931 if ((xml_menu = switch_xml_find_child(xml_menus, "menu", "name", param)) != NULL((void*)0)) {
932 status = switch_ivr_menu_stack_xml_build(xml_menu_ctx, menu_stack, xml_menus, xml_menu);
933 }
934 }
935 /* finally bind the menu entry */
936 if (status == SWITCH_STATUS_SUCCESS) {
937 if (xml_map->function != NULL((void*)0)) {
938 switch_log_printf(SWITCH_CHANNEL_LOGSWITCH_CHANNEL_ID_LOG, "src/switch_ivr_menu.c", (const char *
)__func__, 938, ((void*)0)
, SWITCH_LOG_DEBUG,
939 "binding menu caller control '%s'/'%s' to '%s'\n", xml_map->name, param, digits);
940 status = switch_ivr_menu_bind_function(menu, xml_map->function, param, digits);
941 } else {
942 switch_log_printf(SWITCH_CHANNEL_LOGSWITCH_CHANNEL_ID_LOG, "src/switch_ivr_menu.c", (const char *
)__func__, 942, ((void*)0)
, SWITCH_LOG_DEBUG, "binding menu action '%s' to '%s'\n", xml_map->name, digits);
943 status = switch_ivr_menu_bind_action(menu, xml_map->action, param, digits);
944 }
945 }
946 }
947 } else {
948 status = SWITCH_STATUS_FALSE;
949 }
950 }
951 }
952 }
953
954 if (status != SWITCH_STATUS_SUCCESS) {
955 switch_log_printf(SWITCH_CHANNEL_LOGSWITCH_CHANNEL_ID_LOG, "src/switch_ivr_menu.c", (const char *
)__func__, 955, ((void*)0)
, SWITCH_LOG_ERROR, "Unable to build xml menu\n");
956 }
957
958 return status;
959}
960
961/* For Emacs:
962 * Local Variables:
963 * mode:c
964 * indent-tabs-mode:t
965 * tab-width:4
966 * c-basic-offset:4
967 * End:
968 * For VIM:
969 * vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet:
970 */