refinements and additions to switch_ivr_menu from Neal Horman.
git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@3527 d0543943-73ff-0310-b7d9-9358b9ac24b2
This commit is contained in:
parent
ad63096f5c
commit
84c625d98f
|
@ -482,15 +482,16 @@ typedef enum {
|
|||
typedef enum {
|
||||
SWITCH_IVR_ACTION_DIE, /* Exit the menu. */
|
||||
SWITCH_IVR_ACTION_EXECMENU, /* Goto another menu in the stack. */
|
||||
SWITCH_IVR_ACTION_EXECAPP, /* Execute an application. */
|
||||
SWITCH_IVR_ACTION_EXECAPP, /* Execute an application. */
|
||||
SWITCH_IVR_ACTION_PLAYSOUND, /* Play a sound. */
|
||||
SWITCH_IVR_ACTION_SAYTEXT, /* say text. */
|
||||
SWITCH_IVR_ACTION_SAYTEXT, /* say text. */
|
||||
SWITCH_IVR_ACTION_BACK, /* Go back 1 menu. */
|
||||
SWITCH_IVR_ACTION_TOMAIN, /* Go back to the top level menu. */
|
||||
SWITCH_IVR_ACTION_TOMAIN, /* Go back to the top level menu. */
|
||||
SWITCH_IVR_ACTION_TRANSFER, /* Transfer caller to another ext. */
|
||||
SWITCH_IVR_ACTION_NOOP, /* No operation */
|
||||
} switch_ivr_action_t;
|
||||
struct switch_ivr_menu;
|
||||
typedef switch_ivr_action_t switch_ivr_menu_action_function_t(struct switch_ivr_menu *, char *, size_t, void *);
|
||||
typedef switch_ivr_action_t switch_ivr_menu_action_function_t(struct switch_ivr_menu *, char *, char *, size_t, void *);
|
||||
typedef struct switch_ivr_menu switch_ivr_menu_t;
|
||||
typedef struct switch_ivr_menu_action switch_ivr_menu_action_t;
|
||||
/******************************************************************************************************/
|
||||
|
@ -502,11 +503,13 @@ typedef struct switch_ivr_menu_action switch_ivr_menu_action_t;
|
|||
*\param name A pointer to the name of this menu.
|
||||
*\param greeting_sound Optional pointer to a main sound (press 1 for this 2 for that).
|
||||
*\param short_greeting_sound Optional pointer to a shorter main sound for subsequent loops.
|
||||
*\param exit_sound Optional pointer to a sound to play upon exiting the menu
|
||||
*\param invalid_sound Optional pointer to a sound to play after invalid input.
|
||||
*\param tts_engine Text To Speech engine name
|
||||
*\param tts_voice Text To Speech engine voice name
|
||||
*\param timeout A number of milliseconds to pause before looping.
|
||||
*\param max_failures Maximum number of failures to withstand before hangingup This resets everytime you enter the menu.
|
||||
*\param timer_name A pointer to a timer name
|
||||
*\param pool memory pool (NULL to create one)
|
||||
*\return SWITCH_STATUS_SUCCESS if the menu was created
|
||||
*/
|
||||
|
@ -515,11 +518,13 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_menu_init(switch_ivr_menu_t **new_men
|
|||
char *name,
|
||||
char *greeting_sound,
|
||||
char *short_greeting_sound,
|
||||
char *exit_sound,
|
||||
char *invalid_sound,
|
||||
char *tts_engine,
|
||||
char *tts_voice,
|
||||
int timeout,
|
||||
int max_failures,
|
||||
char *timer_name,
|
||||
switch_memory_pool_t *pool);
|
||||
|
||||
/*!
|
||||
|
@ -537,13 +542,14 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_menu_bind_action(switch_ivr_menu_t *m
|
|||
*\brief Bind a keystroke to a callback function.
|
||||
*\param menu The menu obj you wish to bind to.
|
||||
*\param function The function to call [int proto(struct switch_ivr_menu *, char *, size_t, void *)]
|
||||
*\param arg Optional (sometimes necessary) string arguement.
|
||||
*\param bind KeyStrokes to bind the action to.
|
||||
*\note The function is passed a buffer to fill in with any required argument data.
|
||||
*\note The function is also passed an optional void pointer to an object set upon menu execution. (think threads)
|
||||
*\note The function returns an switch_ivr_action_t enum of what you want to do. and looks to your buffer for args.
|
||||
*\return SWUTCH_STATUS_SUCCESS if the function was binded
|
||||
*/
|
||||
SWITCH_DECLARE(switch_status_t) switch_ivr_menu_bind_function(switch_ivr_menu_t *menu, switch_ivr_menu_action_function_t *function, char *bind);
|
||||
SWITCH_DECLARE(switch_status_t) switch_ivr_menu_bind_function(switch_ivr_menu_t *menu, switch_ivr_menu_action_function_t *function, char *arg, char *bind);
|
||||
|
||||
|
||||
/*!
|
||||
|
@ -561,20 +567,42 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_menu_execute(switch_core_session_t *s
|
|||
*\param stack The top level menu you wish to destroy.
|
||||
*\return SWITCH_STATUS_SUCCESS if the object was a top level menu and it was freed
|
||||
*/
|
||||
SWITCH_DECLARE(switch_status_t) switch_ivr_menu_free_stack(switch_ivr_menu_t *stack);
|
||||
SWITCH_DECLARE(switch_status_t) switch_ivr_menu_stack_free(switch_ivr_menu_t *stack);
|
||||
|
||||
struct switch_ivr_menu_xml_ctx;
|
||||
typedef struct switch_ivr_menu_xml_ctx switch_ivr_menu_xml_ctx_t;
|
||||
/*!
|
||||
*\brief build a menu stack from an xml source
|
||||
*\brief Build a menu stack from an xml source
|
||||
*\param xml_menu_ctx The XML menu parser context previously created by switch_ivr_menu_stack_xml_init
|
||||
*\param menu_stack The menu stack object that will be created for you
|
||||
*\param xml_menus The xml Menus source
|
||||
*\param xml_menu The xml Menu source of the menu to be created
|
||||
*\param timer_name The name of a timer that should be used - in almost all cases this should be NULL
|
||||
*\return SWITCH_STATUS_SUCCESS if all is well
|
||||
*/
|
||||
SWITCH_DECLARE(switch_status_t) switch_ivr_menu_stack_xml_build(switch_ivr_menu_xml_ctx_t *xml_menu_ctx,
|
||||
switch_ivr_menu_t **menu_stack,
|
||||
switch_xml_t xml_menus,
|
||||
switch_xml_t xml_menu,
|
||||
char *timer_name);
|
||||
|
||||
/*!
|
||||
*\param xml_menu_ctx The XML menu parser context previously created by switch_ivr_menu_stack_xml_init
|
||||
*\param name The xml tag name to add to the parser engine
|
||||
*\param function The menu function callback that will be executed when menu digits are bound to this name
|
||||
*\return SWITCH_STATUS_SUCCESS if all is well
|
||||
*/
|
||||
SWITCH_DECLARE(switch_status_t) switch_ivr_menu_stack_xml_add_custom(switch_ivr_menu_xml_ctx_t *xml_menu_ctx,
|
||||
char *name,
|
||||
switch_ivr_menu_action_function_t *function);
|
||||
|
||||
/*!
|
||||
*\param xml_menu_ctx A pointer of a XML menu parser context to be created
|
||||
*\param pool memory pool (NULL to create one)
|
||||
*\return SWITCH_STATUS_SUCCESS if all is well
|
||||
*/
|
||||
SWITCH_DECLARE(switch_status_t) switch_ivr_build_xml_menu_stack(switch_ivr_menu_t **menu_stack,
|
||||
switch_xml_t xml_menus,
|
||||
switch_xml_t xml_menu,
|
||||
switch_memory_pool_t *pool);
|
||||
SWITCH_DECLARE(switch_status_t) switch_ivr_menu_stack_xml_init(switch_ivr_menu_xml_ctx_t **xml_menu_ctx, switch_memory_pool_t *pool);
|
||||
|
||||
/** @} */
|
||||
|
||||
SWITCH_END_EXTERN_C
|
||||
|
|
525
src/switch_ivr.c
525
src/switch_ivr.c
|
@ -28,7 +28,7 @@
|
|||
* Neal Horman <neal at wanlink dot com>
|
||||
* Matt Klein <mklein@nmedia.net>
|
||||
*
|
||||
* switch_ivr_api.c -- IVR Library
|
||||
* switch_ivr.c -- IVR Library
|
||||
*
|
||||
*/
|
||||
#include <switch.h>
|
||||
|
@ -187,7 +187,7 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_collect_digits_callback(switch_core_s
|
|||
uint32_t elapsed;
|
||||
|
||||
channel = switch_core_session_get_channel(session);
|
||||
assert(channel != NULL);
|
||||
assert(channel != NULL);
|
||||
|
||||
if (!input_callback) {
|
||||
return SWITCH_STATUS_GENERR;
|
||||
|
@ -253,18 +253,19 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_collect_digits_count(switch_core_sess
|
|||
{
|
||||
uint32_t i = 0, x = (uint32_t) strlen(buf);
|
||||
switch_channel_t *channel;
|
||||
switch_status_t status = SWITCH_STATUS_SUCCESS;
|
||||
switch_status_t status = SWITCH_STATUS_FALSE;
|
||||
switch_time_t started = 0;
|
||||
uint32_t elapsed;
|
||||
|
||||
channel = switch_core_session_get_channel(session);
|
||||
assert(channel != NULL);
|
||||
assert(channel != NULL);
|
||||
|
||||
*terminator = '\0';
|
||||
if (terminator != NULL)
|
||||
*terminator = '\0';
|
||||
|
||||
if (terminators) {
|
||||
if (!switch_strlen_zero(terminators)) {
|
||||
for (i = 0 ; i < x; i++) {
|
||||
if (strchr(terminators, buf[i])) {
|
||||
if (strchr(terminators, buf[i]) && terminator != NULL) {
|
||||
*terminator = buf[i];
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
@ -293,10 +294,11 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_collect_digits_count(switch_core_sess
|
|||
|
||||
if (switch_channel_has_dtmf(channel)) {
|
||||
char dtmf[128];
|
||||
|
||||
switch_channel_dequeue_dtmf(channel, dtmf, sizeof(dtmf));
|
||||
for(i =0 ; i < (uint32_t) strlen(dtmf); i++) {
|
||||
|
||||
if (strchr(terminators, dtmf[i])) {
|
||||
if (!switch_strlen_zero(terminators) && strchr(terminators, dtmf[i]) && terminator != NULL) {
|
||||
*terminator = dtmf[i];
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
@ -3469,6 +3471,8 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_transfer_variable(switch_core_session
|
|||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
/******************************************************************************************************/
|
||||
|
||||
struct switch_ivr_digit_stream_parser {
|
||||
int pool_auto_created;
|
||||
switch_memory_pool_t *pool;
|
||||
|
@ -3476,6 +3480,9 @@ struct switch_ivr_digit_stream_parser {
|
|||
char *digits;
|
||||
char terminator;
|
||||
switch_size_t maxlen;
|
||||
switch_size_t minlen;
|
||||
unsigned int digit_timeout_ms;
|
||||
switch_time_t last_digit_time;
|
||||
};
|
||||
|
||||
SWITCH_DECLARE(switch_status_t) switch_ivr_digit_stream_parser_new(switch_memory_pool_t *pool, switch_ivr_digit_stream_parser_t **parser)
|
||||
|
@ -3487,6 +3494,7 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_digit_stream_parser_new(switch_memory
|
|||
// if the caller didn't provide a pool, make one
|
||||
if (pool == NULL) {
|
||||
switch_core_new_memory_pool(&pool);
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "created a memory pool\n");
|
||||
if (pool != NULL) {
|
||||
pool_auto_created = 1;
|
||||
}
|
||||
|
@ -3502,12 +3510,13 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_digit_stream_parser_new(switch_memory
|
|||
memset(*parser,0,sizeof(switch_ivr_digit_stream_parser_t));
|
||||
(*parser)->pool_auto_created = pool_auto_created;
|
||||
(*parser)->pool = pool;
|
||||
(*parser)->digit_timeout_ms = 1000;
|
||||
switch_core_hash_init(&(*parser)->hash,(*parser)->pool);
|
||||
|
||||
status = SWITCH_STATUS_SUCCESS;
|
||||
} else {
|
||||
status = SWITCH_STATUS_MEMERR;
|
||||
// clean up the pool if we created it
|
||||
// if we can't create a parser object,clean up the pool if we created it
|
||||
if (pool != NULL && pool_auto_created) {
|
||||
switch_core_destroy_memory_pool(&pool);
|
||||
}
|
||||
|
@ -3540,11 +3549,29 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_digit_stream_parser_set_event(switch_
|
|||
{ switch_status_t status = SWITCH_STATUS_FALSE;
|
||||
|
||||
if (parser != NULL && digits != NULL && *digits && parser->hash != NULL) {
|
||||
switch_size_t len;
|
||||
|
||||
status = switch_core_hash_insert_dup(parser->hash,digits,data);
|
||||
if (status == SWITCH_STATUS_SUCCESS && parser->terminator == '\0' && (len = strlen(digits)) > parser->maxlen) {
|
||||
parser->maxlen = len;
|
||||
if (status == SWITCH_STATUS_SUCCESS) {
|
||||
switch_size_t len = strlen(digits);
|
||||
|
||||
// if we don't have a terminator, then we have to try and
|
||||
// figure out when a digit set is completed, therefore we
|
||||
// keep track of the min and max digit lengths
|
||||
if (parser->terminator == '\0') {
|
||||
if (len > parser->maxlen) {
|
||||
parser->maxlen = len;
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "max len %u\n",parser->maxlen);
|
||||
}
|
||||
if (parser->minlen == 0 || len < parser->minlen) {
|
||||
parser->minlen = len;
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "min len %u\n",parser->minlen);
|
||||
}
|
||||
} else {
|
||||
// since we have a terminator, reset min and max
|
||||
parser->minlen = 0;
|
||||
parser->maxlen = 0;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
if (status != SWITCH_STATUS_SUCCESS) {
|
||||
|
@ -3571,28 +3598,40 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_digit_stream_parser_del_event(switch_
|
|||
SWITCH_DECLARE(void *) switch_ivr_digit_stream_parser_feed(switch_ivr_digit_stream_parser_t *parser, char digit)
|
||||
{ void *result = NULL;
|
||||
|
||||
if (parser != NULL && digit != '\0') {
|
||||
size_t len = (parser->digits != NULL ? strlen(parser->digits) : 0);
|
||||
if (parser != NULL) {
|
||||
switch_size_t len = (parser->digits != NULL ? strlen(parser->digits) : 0);
|
||||
|
||||
// if it's not a terminator digit, add it to the collected digits
|
||||
if (digit != parser->terminator) {
|
||||
// if collected digits length >= the max length of the keys
|
||||
// in the hash table, then left shift the digit string
|
||||
if ( len > 1 && parser->maxlen != 0 && len >= parser->maxlen) {
|
||||
char *src = parser->digits + 1;
|
||||
char *dst = parser->digits;
|
||||
// handle new digit arrivals
|
||||
if(digit != '\0') {
|
||||
|
||||
while (*src) {
|
||||
*(dst++) = *(src++);
|
||||
// if it's not a terminator digit, add it to the collected digits
|
||||
if (digit != parser->terminator) {
|
||||
// if collected digits length >= the max length of the keys
|
||||
// in the hash table, then left shift the digit string
|
||||
if (len > 0 && parser->maxlen != 0 && len >= parser->maxlen) {
|
||||
char *src = parser->digits + 1;
|
||||
char *dst = parser->digits;
|
||||
|
||||
while (*src) {
|
||||
*(dst++) = *(src++);
|
||||
}
|
||||
*dst = digit;
|
||||
} else {
|
||||
parser->digits = realloc(parser->digits,len+2);
|
||||
*(parser->digits+(len++)) = digit;
|
||||
*(parser->digits+len) = '\0';
|
||||
parser->last_digit_time = switch_time_now() / 1000;
|
||||
}
|
||||
*dst = digit;
|
||||
} else {
|
||||
parser->digits = realloc(parser->digits,len+2);
|
||||
*(parser->digits+(len++)) = digit;
|
||||
*(parser->digits+len) = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
// don't allow collected digit string testing if there are varying sized keys until timeout
|
||||
if ( parser->maxlen - parser->minlen > 0
|
||||
&& (switch_time_now() / 1000) - parser->last_digit_time < parser->digit_timeout_ms
|
||||
) {
|
||||
len = 0;
|
||||
}
|
||||
|
||||
// if we have digits to test
|
||||
if (len) {
|
||||
result = switch_core_hash_find(parser->hash,parser->digits);
|
||||
|
@ -3603,7 +3642,7 @@ SWITCH_DECLARE(void *) switch_ivr_digit_stream_parser_feed(switch_ivr_digit_stre
|
|||
parser->digits = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
@ -3625,6 +3664,8 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_digit_stream_parser_set_terminator(sw
|
|||
|
||||
if (parser != NULL) {
|
||||
parser->terminator = digit;
|
||||
// since we have a terminator, reset min and max
|
||||
parser->minlen = 0;
|
||||
parser->maxlen = 0;
|
||||
status = SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
@ -3632,6 +3673,8 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_digit_stream_parser_set_terminator(sw
|
|||
return status;
|
||||
}
|
||||
|
||||
/******************************************************************************************************/
|
||||
|
||||
struct switch_ivr_menu_action;
|
||||
|
||||
struct switch_ivr_menu {
|
||||
|
@ -3639,10 +3682,12 @@ struct switch_ivr_menu {
|
|||
char *greeting_sound;
|
||||
char *short_greeting_sound;
|
||||
char *invalid_sound;
|
||||
char *exit_sound;
|
||||
char *tts_engine;
|
||||
char *tts_voice;
|
||||
char *buf;
|
||||
char *ptr;
|
||||
char *timer_name;
|
||||
int max_failures;
|
||||
int timeout;
|
||||
uint32_t inlen;
|
||||
|
@ -3652,7 +3697,6 @@ struct switch_ivr_menu {
|
|||
switch_memory_pool_t *pool;
|
||||
};
|
||||
|
||||
|
||||
struct switch_ivr_menu_action {
|
||||
switch_ivr_menu_action_function_t *function;
|
||||
switch_ivr_action_t ivr_action;
|
||||
|
@ -3661,7 +3705,7 @@ struct switch_ivr_menu_action {
|
|||
struct switch_ivr_menu_action *next;
|
||||
};
|
||||
|
||||
static switch_ivr_menu_t *switch_ivr_find_menu(switch_ivr_menu_t *stack, char *name) {
|
||||
static switch_ivr_menu_t *switch_ivr_menu_find(switch_ivr_menu_t *stack, char *name) {
|
||||
switch_ivr_menu_t *ret;
|
||||
for(ret = stack; ret ; ret = ret->next) {
|
||||
if (!name || !strcmp(ret->name, name))
|
||||
|
@ -3670,8 +3714,7 @@ static switch_ivr_menu_t *switch_ivr_find_menu(switch_ivr_menu_t *stack, char *n
|
|||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static void switch_ivr_menu_stack(switch_ivr_menu_t **top, switch_ivr_menu_t *bottom)
|
||||
static void switch_ivr_menu_stack_add(switch_ivr_menu_t **top, switch_ivr_menu_t *bottom)
|
||||
{
|
||||
switch_ivr_menu_t *ptr;
|
||||
|
||||
|
@ -3691,10 +3734,12 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_menu_init(switch_ivr_menu_t **new_men
|
|||
char *greeting_sound,
|
||||
char *short_greeting_sound,
|
||||
char *invalid_sound,
|
||||
char *exit_sound,
|
||||
char *tts_engine,
|
||||
char *tts_voice,
|
||||
int timeout,
|
||||
int max_failures,
|
||||
char *timer_name,
|
||||
switch_memory_pool_t *pool)
|
||||
{
|
||||
switch_ivr_menu_t *menu;
|
||||
|
@ -3718,30 +3763,38 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_menu_init(switch_ivr_menu_t **new_men
|
|||
|
||||
menu->pool = pool;
|
||||
|
||||
if (name) {
|
||||
if (!switch_strlen_zero(name)) {
|
||||
menu->name = switch_core_strdup(menu->pool, name);
|
||||
}
|
||||
|
||||
if (greeting_sound) {
|
||||
if (!switch_strlen_zero(greeting_sound)) {
|
||||
menu->greeting_sound = switch_core_strdup(menu->pool, greeting_sound);
|
||||
}
|
||||
|
||||
if (short_greeting_sound) {
|
||||
if (!switch_strlen_zero(short_greeting_sound)) {
|
||||
menu->short_greeting_sound = switch_core_strdup(menu->pool, short_greeting_sound);
|
||||
}
|
||||
|
||||
if (invalid_sound) {
|
||||
if (!switch_strlen_zero(invalid_sound)) {
|
||||
menu->invalid_sound = switch_core_strdup(menu->pool, invalid_sound);
|
||||
}
|
||||
|
||||
if (tts_engine) {
|
||||
if (!switch_strlen_zero(exit_sound)) {
|
||||
menu->exit_sound = switch_core_strdup(menu->pool, exit_sound);
|
||||
}
|
||||
|
||||
if (!switch_strlen_zero(tts_engine)) {
|
||||
menu->tts_engine = switch_core_strdup(menu->pool, tts_engine);
|
||||
}
|
||||
|
||||
if (tts_voice) {
|
||||
if (!switch_strlen_zero(tts_voice)) {
|
||||
menu->tts_voice = switch_core_strdup(menu->pool, tts_voice);
|
||||
}
|
||||
|
||||
if (!switch_strlen_zero(timer_name)) {
|
||||
menu->timer_name = switch_core_strdup(menu->pool, timer_name);
|
||||
}
|
||||
|
||||
menu->max_failures = max_failures;
|
||||
|
||||
menu->timeout = timeout;
|
||||
|
@ -3757,7 +3810,7 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_menu_init(switch_ivr_menu_t **new_men
|
|||
}
|
||||
|
||||
if (main) {
|
||||
switch_ivr_menu_stack(&main, menu);
|
||||
switch_ivr_menu_stack_add(&main, menu);
|
||||
} else {
|
||||
menu->flags |= SWITCH_IVR_MENU_FLAG_STACK;
|
||||
}
|
||||
|
@ -3767,11 +3820,11 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_menu_init(switch_ivr_menu_t **new_men
|
|||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
SWITCH_DECLARE(switch_status_t) switch_ivr_menu_bind_action(switch_ivr_menu_t *menu, switch_ivr_action_t ivr_action, char *arg, char *bind)
|
||||
{
|
||||
switch_ivr_menu_action_t *action;
|
||||
uint32_t len;
|
||||
|
||||
if ((action = switch_core_alloc(menu->pool, sizeof(*action)))) {
|
||||
action->bind = switch_core_strdup(menu->pool, bind);
|
||||
action->next = menu->actions;
|
||||
|
@ -3788,16 +3841,20 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_menu_bind_action(switch_ivr_menu_t *m
|
|||
return SWITCH_STATUS_MEMERR;
|
||||
}
|
||||
|
||||
|
||||
SWITCH_DECLARE(switch_status_t) switch_ivr_menu_bind_function(switch_ivr_menu_t *menu, switch_ivr_menu_action_function_t *function, char *bind)
|
||||
SWITCH_DECLARE(switch_status_t) switch_ivr_menu_bind_function(switch_ivr_menu_t *menu, switch_ivr_menu_action_function_t *function, char *arg, char *bind)
|
||||
{
|
||||
switch_ivr_menu_action_t *action;
|
||||
|
||||
uint32_t len;
|
||||
|
||||
if ((action = switch_core_alloc(menu->pool, sizeof(*action)))) {
|
||||
action->bind = bind;
|
||||
action->function = function;
|
||||
action->next = menu->actions;
|
||||
action->arg = switch_core_strdup(menu->pool, arg);
|
||||
len = (uint32_t)strlen(action->bind);
|
||||
if (len > menu->inlen) {
|
||||
menu->inlen = len;
|
||||
}
|
||||
action->function = function;
|
||||
menu->actions = action;
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
@ -3805,63 +3862,66 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_menu_bind_function(switch_ivr_menu_t
|
|||
return SWITCH_STATUS_MEMERR;
|
||||
}
|
||||
|
||||
SWITCH_DECLARE(switch_status_t) switch_ivr_menu_free_stack(switch_ivr_menu_t *stack)
|
||||
SWITCH_DECLARE(switch_status_t) switch_ivr_menu_stack_free(switch_ivr_menu_t *stack)
|
||||
{
|
||||
switch_memory_pool_t *pool;
|
||||
switch_status_t status = SWITCH_STATUS_FALSE;
|
||||
|
||||
if (!switch_test_flag(stack, SWITCH_IVR_MENU_FLAG_STACK) || switch_test_flag(stack, SWITCH_IVR_MENU_FLAG_FREEPOOL)) {
|
||||
return SWITCH_STATUS_FALSE;
|
||||
}
|
||||
|
||||
pool = stack->pool;
|
||||
switch_core_destroy_memory_pool(&pool);
|
||||
pool = NULL;
|
||||
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
|
||||
}
|
||||
|
||||
static switch_status_t play_or_say(switch_core_session_t *session, switch_ivr_menu_t *menu, char *sound, uint32_t need)
|
||||
{
|
||||
char terminator;
|
||||
uint32_t len;
|
||||
char *ptr;
|
||||
switch_status_t status = SWITCH_STATUS_SUCCESS;
|
||||
|
||||
memset(menu->buf, 0, menu->inlen);
|
||||
menu->ptr = menu->buf;
|
||||
|
||||
if (!need) {
|
||||
len = 1;
|
||||
ptr = NULL;
|
||||
} else {
|
||||
len = menu->inlen + 1;
|
||||
ptr = menu->ptr;
|
||||
}
|
||||
|
||||
if (*sound == '/' || *sound == '\\') {
|
||||
switch_ivr_play_file(session, NULL, sound, NULL, NULL, ptr, len);
|
||||
} else {
|
||||
if (menu->tts_engine && menu->tts_voice) {
|
||||
switch_ivr_speak_text(session, menu->tts_engine, menu->tts_voice, NULL, 0, NULL, sound, ptr, len);
|
||||
}
|
||||
}
|
||||
|
||||
if (need) {
|
||||
menu->ptr += strlen(menu->buf);
|
||||
if (strlen(menu->buf) < need) {
|
||||
status = switch_ivr_collect_digits_count(session, menu->ptr, menu->inlen - strlen(menu->buf), need, "#", &terminator, menu->timeout);
|
||||
if (stack != NULL && stack->pool != NULL) {
|
||||
if (switch_test_flag(stack, SWITCH_IVR_MENU_FLAG_STACK) && switch_test_flag(stack, SWITCH_IVR_MENU_FLAG_FREEPOOL)) {
|
||||
switch_memory_pool_t *pool = stack->pool;
|
||||
status = switch_core_destroy_memory_pool(&pool);
|
||||
} else {
|
||||
status = SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static switch_status_t play_or_say(switch_core_session_t *session, switch_ivr_menu_t *menu, char *sound, uint32_t need, char *timer_name)
|
||||
{
|
||||
char terminator;
|
||||
uint32_t len;
|
||||
char *ptr;
|
||||
switch_status_t status = SWITCH_STATUS_FALSE;
|
||||
|
||||
if (session != NULL && menu != NULL && !switch_strlen_zero(sound)) {
|
||||
memset(menu->buf, 0, menu->inlen);
|
||||
menu->ptr = menu->buf;
|
||||
|
||||
if (!need) {
|
||||
len = 1;
|
||||
ptr = NULL;
|
||||
} else {
|
||||
len = menu->inlen + 1;
|
||||
ptr = menu->ptr;
|
||||
}
|
||||
|
||||
if (*sound == '/' || *sound == '\\') {
|
||||
status = switch_ivr_play_file(session, NULL, sound, timer_name, NULL, ptr, need ? 1 : 0);
|
||||
} else {
|
||||
if (menu->tts_engine && menu->tts_voice) {
|
||||
status = switch_ivr_speak_text(session, menu->tts_engine, menu->tts_voice, NULL, 0, NULL, sound, ptr, len);
|
||||
}
|
||||
}
|
||||
|
||||
if (need) {
|
||||
menu->ptr += strlen(menu->buf);
|
||||
if (strlen(menu->buf) < need) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "waiting for %u digits\n",need);
|
||||
status = switch_ivr_collect_digits_count(session, menu->ptr, menu->inlen - strlen(menu->buf), need, "#", &terminator, menu->timeout);
|
||||
}
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "digits '%s'\n",menu->buf);
|
||||
}
|
||||
}
|
||||
|
||||
return status;
|
||||
|
||||
}
|
||||
|
||||
SWITCH_DECLARE(switch_status_t) switch_ivr_menu_execute(switch_core_session_t *session, switch_ivr_menu_t *stack, char *name, void *obj)
|
||||
{
|
||||
int reps = 0, errs = 0, match = 0, running = 1;
|
||||
char *greeting_sound = NULL, *aptr;
|
||||
char *greeting_sound = NULL, *aptr = NULL;
|
||||
char arg[512];
|
||||
switch_ivr_action_t todo = SWITCH_IVR_ACTION_DIE;
|
||||
switch_ivr_menu_action_t *ap;
|
||||
|
@ -3869,18 +3929,22 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_menu_execute(switch_core_session_t *s
|
|||
switch_channel_t *channel;
|
||||
switch_status_t status = SWITCH_STATUS_SUCCESS;
|
||||
|
||||
if (session == NULL || stack == NULL || switch_strlen_zero(name)) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid menu context\n");
|
||||
return SWITCH_STATUS_FALSE;
|
||||
}
|
||||
|
||||
channel = switch_core_session_get_channel(session);
|
||||
assert(channel != NULL);
|
||||
|
||||
|
||||
if (!(menu = switch_ivr_find_menu(stack, name))) {
|
||||
if (!(menu = switch_ivr_menu_find(stack, name))) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid Menu!\n");
|
||||
return -1;
|
||||
return SWITCH_STATUS_FALSE;
|
||||
}
|
||||
|
||||
if (!(menu->buf = malloc(menu->inlen))) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "No Memory!\n");
|
||||
return -1;
|
||||
return SWITCH_STATUS_FALSE;
|
||||
}
|
||||
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Executing IVR menu %s\n", menu->name);
|
||||
|
@ -3901,9 +3965,8 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_menu_execute(switch_core_session_t *s
|
|||
|
||||
memset(arg, 0, sizeof(arg));
|
||||
|
||||
|
||||
play_or_say(session, menu, greeting_sound, menu->inlen);
|
||||
|
||||
memset(menu->buf, 0, menu->inlen);
|
||||
status = play_or_say(session, menu, greeting_sound, menu->inlen, stack->timer_name);
|
||||
|
||||
if (!switch_strlen_zero(menu->buf)) {
|
||||
for(ap = menu->actions; ap ; ap = ap->next) {
|
||||
|
@ -3913,9 +3976,9 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_menu_execute(switch_core_session_t *s
|
|||
match++;
|
||||
errs = 0;
|
||||
if (ap->function) {
|
||||
todo = ap->function(menu, arg, sizeof(arg), obj);
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "IVR function on menu '%s' matched '%s' param '%s'\n", menu->name, menu->buf, ap->arg);
|
||||
todo = ap->function(menu, ap->arg, arg, sizeof(arg), obj);
|
||||
aptr = arg;
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "IVR function on menu '%s' matched '%s'\n", menu->name, menu->buf);
|
||||
} else {
|
||||
todo = ap->ivr_action;
|
||||
aptr = ap->arg;
|
||||
|
@ -3927,12 +3990,10 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_menu_execute(switch_core_session_t *s
|
|||
status = SWITCH_STATUS_FALSE;
|
||||
break;
|
||||
case SWITCH_IVR_ACTION_PLAYSOUND:
|
||||
status = switch_ivr_play_file(session, NULL, aptr, NULL, NULL, NULL, 0);
|
||||
status = switch_ivr_play_file(session, NULL, aptr, stack->timer_name, NULL, NULL, 0);
|
||||
break;
|
||||
case SWITCH_IVR_ACTION_SAYTEXT:
|
||||
if (menu->tts_engine && menu->tts_voice) {
|
||||
switch_ivr_speak_text(session, menu->tts_engine, menu->tts_voice, NULL, 0, NULL, aptr, NULL, 0);
|
||||
}
|
||||
status = switch_ivr_speak_text(session, menu->tts_engine, menu->tts_voice, NULL, 0, NULL, aptr, NULL, 0);
|
||||
break;
|
||||
case SWITCH_IVR_ACTION_TRANSFER:
|
||||
switch_ivr_session_transfer(session, aptr, NULL, NULL);
|
||||
|
@ -3972,6 +4033,9 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_menu_execute(switch_core_session_t *s
|
|||
switch_set_flag(stack, SWITCH_IVR_MENU_FLAG_FALLTOMAIN);
|
||||
status = SWITCH_STATUS_BREAK;
|
||||
break;
|
||||
case SWITCH_IVR_ACTION_NOOP:
|
||||
status = SWITCH_STATUS_SUCCESS;
|
||||
break;
|
||||
default:
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Invalid TODO!\n");
|
||||
break;
|
||||
|
@ -3980,8 +4044,8 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_menu_execute(switch_core_session_t *s
|
|||
}
|
||||
|
||||
|
||||
if (switch_test_flag(menu, SWITCH_IVR_MENU_FLAG_STACK)) { /* top level */
|
||||
if (switch_test_flag(stack, SWITCH_IVR_MENU_FLAG_FALLTOMAIN)) { /* catch the fallback and recover */
|
||||
if (switch_test_flag(menu, SWITCH_IVR_MENU_FLAG_STACK)) { // top level
|
||||
if (switch_test_flag(stack, SWITCH_IVR_MENU_FLAG_FALLTOMAIN)) { // catch the fallback and recover
|
||||
switch_clear_flag(stack, SWITCH_IVR_MENU_FLAG_FALLTOMAIN);
|
||||
status = SWITCH_STATUS_SUCCESS;
|
||||
running = 1;
|
||||
|
@ -3989,11 +4053,11 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_menu_execute(switch_core_session_t *s
|
|||
}
|
||||
}
|
||||
}
|
||||
if (!match) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "IVR menu %s caught invalid input %s\n", menu->name, menu->buf);
|
||||
if (*menu->buf && !match) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "IVR menu '%s' caught invalid input '%s'\n", menu->name, menu->buf);
|
||||
|
||||
if (menu->invalid_sound) {
|
||||
play_or_say(session, menu, menu->invalid_sound, 0);
|
||||
play_or_say(session, menu, menu->invalid_sound, 0, stack->timer_name);
|
||||
}
|
||||
errs++;
|
||||
|
||||
|
@ -4001,7 +4065,11 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_menu_execute(switch_core_session_t *s
|
|||
status = switch_ivr_sleep(session, 1000);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "exit-sound '%s'\n",menu->exit_sound);
|
||||
if (!switch_strlen_zero(menu->exit_sound)) {
|
||||
status = switch_ivr_play_file(session, NULL, menu->exit_sound, stack->timer_name, NULL, NULL, 0);
|
||||
}
|
||||
|
||||
switch_safe_free(menu->buf);
|
||||
|
@ -4009,90 +4077,211 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_menu_execute(switch_core_session_t *s
|
|||
return status;
|
||||
}
|
||||
|
||||
SWITCH_DECLARE(switch_status_t) switch_ivr_build_xml_menu_stack(switch_ivr_menu_t **menu_stack,
|
||||
switch_xml_t xml_menus,
|
||||
switch_xml_t xml_menu,
|
||||
switch_memory_pool_t *pool)
|
||||
/******************************************************************************************************/
|
||||
|
||||
typedef struct switch_ivr_menu_xml_map {
|
||||
char *name;
|
||||
switch_ivr_action_t action;
|
||||
switch_ivr_menu_action_function_t *function;
|
||||
struct switch_ivr_menu_xml_map *next;
|
||||
} switch_ivr_menu_xml_map_t;
|
||||
|
||||
struct switch_ivr_menu_xml_ctx {
|
||||
switch_memory_pool_t *pool;
|
||||
struct switch_ivr_menu_xml_map *map;
|
||||
int autocreated;
|
||||
};
|
||||
|
||||
static switch_ivr_menu_xml_map_t *switch_ivr_menu_stack_xml_find(switch_ivr_menu_xml_ctx_t *xml_ctx, char *name)
|
||||
{
|
||||
switch_ivr_menu_xml_map_t *map = (xml_ctx != NULL ? xml_ctx->map : NULL);
|
||||
int rc = -1;
|
||||
|
||||
while (map != NULL && (rc = strcasecmp(map->name,name)) != 0) {
|
||||
map = map->next;
|
||||
}
|
||||
|
||||
return (rc == 0 ? map : NULL);
|
||||
}
|
||||
|
||||
static switch_status_t switch_ivr_menu_stack_xml_add(switch_ivr_menu_xml_ctx_t *xml_ctx, char*name, int action, switch_ivr_menu_action_function_t *function)
|
||||
{
|
||||
switch_status_t status = SWITCH_STATUS_FALSE;
|
||||
|
||||
// if this action/function does not exist yet
|
||||
if (xml_ctx != NULL && name != NULL && xml_ctx->pool != NULL && switch_ivr_menu_stack_xml_find(xml_ctx,name) == NULL) {
|
||||
switch_ivr_menu_xml_map_t *map = switch_core_alloc(xml_ctx->pool,sizeof(switch_ivr_menu_xml_map_t));
|
||||
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "switch_ivr_menu_stack_xml_add bindng '%s'\n",name);
|
||||
// and we have memory
|
||||
if (map != NULL) {
|
||||
map->name = switch_core_strdup(xml_ctx->pool,name);
|
||||
map->action = action;
|
||||
map->function = function;
|
||||
|
||||
if (map->name != NULL) {
|
||||
// insert map item at top of list
|
||||
map->next = xml_ctx->map;
|
||||
xml_ctx->map = map;
|
||||
status = SWITCH_STATUS_SUCCESS;
|
||||
} else {
|
||||
status = SWITCH_STATUS_MEMERR;
|
||||
}
|
||||
} else {
|
||||
status = SWITCH_STATUS_MEMERR;
|
||||
}
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
SWITCH_DECLARE(switch_status_t) switch_ivr_menu_stack_xml_init(switch_ivr_menu_xml_ctx_t **xml_menu_ctx, switch_memory_pool_t *pool)
|
||||
{
|
||||
switch_status_t status = SWITCH_STATUS_FALSE;
|
||||
char *menu_name = (char *)switch_xml_attr_soft(xml_menu,"name"); // if the attr doesn't exist, return ""
|
||||
char *greet_long = (char *)switch_xml_attr(xml_menu,"greet-long"); // if the attr doesn't exist, return NULL
|
||||
char *greet_short = (char *)switch_xml_attr(xml_menu,"greet-short"); // if the attr doesn't exist, return NULL
|
||||
char *invalid_sound = (char *)switch_xml_attr(xml_menu,"invalid-sound"); // if the attr doesn't exist, return NULL
|
||||
char *tts_engine = (char *)switch_xml_attr(xml_menu,"tts-engine"); // if the attr doesn't exist, return NULL
|
||||
char *tts_voice = (char *)switch_xml_attr(xml_menu,"tts-voice"); // if the attr doesn't exist, return NULL
|
||||
char *timeout = (char *)switch_xml_attr_soft(xml_menu,"timeout"); // if the attr doesn't exist, return ""
|
||||
char *max_failures = (char *)switch_xml_attr_soft(xml_menu,"max-failures"); // if the attr doesn't exist, return ""
|
||||
switch_ivr_menu_t *menu = NULL;
|
||||
int autocreated = 0;
|
||||
|
||||
status = switch_ivr_menu_init(&menu,
|
||||
*menu_stack,
|
||||
menu_name,
|
||||
greet_long,
|
||||
greet_short,
|
||||
invalid_sound,
|
||||
tts_engine,
|
||||
tts_voice,
|
||||
atoi(timeout)*1000,
|
||||
atoi(max_failures),
|
||||
pool
|
||||
);
|
||||
if (status == SWITCH_STATUS_SUCCESS) {
|
||||
switch_xml_t xml_kvp;
|
||||
struct ivr_action_map {
|
||||
// build a memory pool ?
|
||||
if (pool == NULL) {
|
||||
status = switch_core_new_memory_pool(&pool);
|
||||
autocreated = 1;
|
||||
}
|
||||
|
||||
// allocate the xml context
|
||||
if (xml_menu_ctx != NULL && pool != NULL) {
|
||||
*xml_menu_ctx = switch_core_alloc(pool,sizeof(switch_ivr_menu_xml_ctx_t));
|
||||
if (*xml_menu_ctx != NULL) {
|
||||
(*xml_menu_ctx)->pool = pool;
|
||||
(*xml_menu_ctx)->autocreated = autocreated;
|
||||
(*xml_menu_ctx)->map = NULL;
|
||||
status = SWITCH_STATUS_SUCCESS;
|
||||
} else {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Unable to alloc xml_ctx\n");
|
||||
status = SWITCH_STATUS_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
// build the standard/default xml menu handler mappings
|
||||
if (status == SWITCH_STATUS_SUCCESS && xml_menu_ctx != NULL && *xml_menu_ctx != NULL) {
|
||||
struct iam_s {
|
||||
char *name;
|
||||
switch_ivr_action_t action;
|
||||
} iam [] = {
|
||||
{"exit", SWITCH_IVR_ACTION_DIE},
|
||||
{"menu-exit", SWITCH_IVR_ACTION_DIE},
|
||||
{"menu-sub", SWITCH_IVR_ACTION_EXECMENU},
|
||||
{"exec-api", SWITCH_IVR_ACTION_EXECAPP},
|
||||
{"play-sound", SWITCH_IVR_ACTION_PLAYSOUND},
|
||||
{"say-text", SWITCH_IVR_ACTION_SAYTEXT},
|
||||
{"menu-exec-api", SWITCH_IVR_ACTION_EXECAPP},
|
||||
{"menu-play-sound", SWITCH_IVR_ACTION_PLAYSOUND},
|
||||
{"menu-say-text", SWITCH_IVR_ACTION_SAYTEXT},
|
||||
{"menu-back", SWITCH_IVR_ACTION_BACK},
|
||||
{"menu-top", SWITCH_IVR_ACTION_TOMAIN},
|
||||
{"call-transfer", SWITCH_IVR_ACTION_TRANSFER},
|
||||
{"menu-call-transfer", SWITCH_IVR_ACTION_TRANSFER},
|
||||
};
|
||||
int iam_qty = sizeof(iam)/sizeof(iam[0]);
|
||||
int iam_qty = (sizeof(iam)/sizeof(iam[0]));
|
||||
int i;
|
||||
|
||||
// set the menu stack for the caller
|
||||
if (*menu_stack == NULL) {
|
||||
for(i=0; i<iam_qty && status == SWITCH_STATUS_SUCCESS; i++) {
|
||||
status = switch_ivr_menu_stack_xml_add(*xml_menu_ctx,iam[i].name,iam[i].action,NULL);
|
||||
}
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
SWITCH_DECLARE(switch_status_t) switch_ivr_menu_stack_xml_add_custom(switch_ivr_menu_xml_ctx_t *xml_menu_ctx, char *name, switch_ivr_menu_action_function_t *function)
|
||||
{
|
||||
return switch_ivr_menu_stack_xml_add(xml_menu_ctx, name, -1, function);
|
||||
}
|
||||
|
||||
SWITCH_DECLARE(switch_status_t) switch_ivr_menu_stack_xml_build(switch_ivr_menu_xml_ctx_t *xml_menu_ctx,
|
||||
switch_ivr_menu_t **menu_stack,
|
||||
switch_xml_t xml_menus,
|
||||
switch_xml_t xml_menu,
|
||||
char *timer_name)
|
||||
{
|
||||
switch_status_t status = SWITCH_STATUS_FALSE;
|
||||
|
||||
if (xml_menu_ctx != NULL && menu_stack != NULL && xml_menu != NULL) {
|
||||
char *menu_name = (char *)switch_xml_attr_soft(xml_menu,"name"); // if the attr doesn't exist, return ""
|
||||
char *greet_long = (char *)switch_xml_attr(xml_menu,"greet-long"); // if the attr doesn't exist, return NULL
|
||||
char *greet_short = (char *)switch_xml_attr(xml_menu,"greet-short"); // if the attr doesn't exist, return NULL
|
||||
char *invalid_sound = (char *)switch_xml_attr(xml_menu,"invalid-sound"); // if the attr doesn't exist, return NULL
|
||||
char *exit_sound = (char *)switch_xml_attr(xml_menu,"exit-sound"); // if the attr doesn't exist, return NULL
|
||||
char *tts_engine = (char *)switch_xml_attr(xml_menu,"tts-engine"); // if the attr doesn't exist, return NULL
|
||||
char *tts_voice = (char *)switch_xml_attr(xml_menu,"tts-voice"); // if the attr doesn't exist, return NULL
|
||||
char *timeout = (char *)switch_xml_attr_soft(xml_menu,"timeout"); // if the attr doesn't exist, return ""
|
||||
char *max_failures = (char *)switch_xml_attr_soft(xml_menu,"max-failures"); // if the attr doesn't exist, return ""
|
||||
switch_ivr_menu_t *menu = NULL;
|
||||
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "building menu '%s'\n",menu_name);
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "timer_name '%s'\n",timer_name);
|
||||
status = switch_ivr_menu_init(&menu,
|
||||
*menu_stack,
|
||||
menu_name,
|
||||
greet_long,
|
||||
greet_short,
|
||||
invalid_sound,
|
||||
exit_sound,
|
||||
tts_engine,
|
||||
tts_voice,
|
||||
atoi(timeout)*1000,
|
||||
atoi(max_failures),
|
||||
timer_name,
|
||||
xml_menu_ctx->pool
|
||||
);
|
||||
// set the menu_stack for the caller
|
||||
if (status == SWITCH_STATUS_SUCCESS && *menu_stack == NULL) {
|
||||
*menu_stack = menu;
|
||||
}
|
||||
|
||||
// build menu entries
|
||||
for(xml_kvp = switch_xml_child(xml_menu, "entry"); xml_kvp != NULL && status == SWITCH_STATUS_SUCCESS; xml_kvp = xml_kvp->next) {
|
||||
char *action = (char *)switch_xml_attr(xml_kvp, "action");
|
||||
char *digits = (char *)switch_xml_attr(xml_kvp, "digits");
|
||||
char *param = (char *)switch_xml_attr_soft(xml_kvp, "param");
|
||||
if (status == SWITCH_STATUS_SUCCESS && menu != NULL) {
|
||||
switch_xml_t xml_kvp;
|
||||
|
||||
if (!switch_strlen_zero(action) && !switch_strlen_zero(digits)) {
|
||||
int i,found;
|
||||
// build menu entries
|
||||
for(xml_kvp = switch_xml_child(xml_menu, "entry"); xml_kvp != NULL && status == SWITCH_STATUS_SUCCESS; xml_kvp = xml_kvp->next) {
|
||||
char *action = (char *)switch_xml_attr(xml_kvp, "action");
|
||||
char *digits = (char *)switch_xml_attr(xml_kvp, "digits");
|
||||
char *param = (char *)switch_xml_attr_soft(xml_kvp, "param");
|
||||
|
||||
for(i=0,found=0; i<iam_qty && !found; i++) {
|
||||
found = (strcasecmp(iam[i].name,action) == 0);
|
||||
}
|
||||
if (!switch_strlen_zero(action) && !switch_strlen_zero(digits)) {
|
||||
switch_ivr_menu_xml_map_t *xml_map = xml_menu_ctx->map;
|
||||
int found = 0;
|
||||
|
||||
if (found) {
|
||||
i--;
|
||||
// do we need to build a new sub-menu ?
|
||||
if (iam[i].action == SWITCH_IVR_ACTION_EXECMENU && switch_ivr_find_menu(*menu_stack, param) == NULL) {
|
||||
if ((xml_menu = switch_xml_find_child(xml_menus, "menu", "name", param)) != NULL) {
|
||||
status = switch_ivr_build_xml_menu_stack(menu_stack, xml_menus, xml_menu, pool);
|
||||
// find and appropriate xml handler
|
||||
while(xml_map != NULL && !found) {
|
||||
if (!(found = (strcasecmp(xml_map->name,action) == 0))) {
|
||||
xml_map = xml_map->next;
|
||||
}
|
||||
}
|
||||
// finally bind the menu entry
|
||||
if (status == SWITCH_STATUS_SUCCESS) {
|
||||
status = switch_ivr_menu_bind_action(menu, iam[i].action, param, digits);
|
||||
|
||||
if (found && xml_map != NULL) {
|
||||
// do we need to build a new sub-menu ?
|
||||
if (xml_map->action == SWITCH_IVR_ACTION_EXECMENU && switch_ivr_menu_find(*menu_stack, param) == NULL) {
|
||||
if ((xml_menu = switch_xml_find_child(xml_menus, "menu", "name", param)) != NULL) {
|
||||
status = switch_ivr_menu_stack_xml_build(xml_menu_ctx, menu_stack, xml_menus, xml_menu, timer_name);
|
||||
}
|
||||
}
|
||||
|
||||
// finally bind the menu entry
|
||||
if (status == SWITCH_STATUS_SUCCESS) {
|
||||
if (xml_map->function != NULL) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG,
|
||||
"binding menu caller control '%s'/'%s' to '%s'\n", xml_map->name, param, digits);
|
||||
status = switch_ivr_menu_bind_function(menu, xml_map->function, param, digits);
|
||||
} else {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG,
|
||||
"binding menu action '%s' to '%s'\n", xml_map->name, digits);
|
||||
status = switch_ivr_menu_bind_action(menu, xml_map->action, param, digits);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
status = SWITCH_STATUS_FALSE;
|
||||
}
|
||||
} else {
|
||||
status = SWITCH_STATUS_FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (status != SWITCH_STATUS_SUCCESS) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Unable to build xml menu '%s'\n",menu_name);
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Unable to build xml menu\n");
|
||||
}
|
||||
|
||||
return status;
|
||||
|
|
Loading…
Reference in New Issue