Main Page | Modules | Class Hierarchy | Alphabetical List | Data Structures | Directories | File List | Data Fields | Globals | Related Pages

IVR Menu Library
[IVR Library]


Detailed Description

IVR menu functions


Typedefs

typedef switch_ivr_action_t switch_ivr_menu_action_function_t (struct switch_ivr_menu *, char *, char *, size_t, void *)
typedef switch_ivr_menu switch_ivr_menu_t
typedef switch_ivr_menu_action switch_ivr_menu_action_t
typedef switch_ivr_menu_xml_ctx switch_ivr_menu_xml_ctx_t

Enumerations

enum  switch_ivr_menu_flags { SWITCH_IVR_MENU_FLAG_FALLTOMAIN = (1 << 0), SWITCH_IVR_MENU_FLAG_FREEPOOL = (1 << 1), SWITCH_IVR_MENU_FLAG_STACK = (1 << 2) }
enum  switch_ivr_action_t {
  SWITCH_IVR_ACTION_DIE, SWITCH_IVR_ACTION_EXECMENU, SWITCH_IVR_ACTION_EXECAPP, SWITCH_IVR_ACTION_PLAYSOUND,
  SWITCH_IVR_ACTION_BACK, SWITCH_IVR_ACTION_TOMAIN, SWITCH_IVR_ACTION_NOOP
}

Functions

switch_status_t switch_ivr_menu_init (switch_ivr_menu_t **new_menu, switch_ivr_menu_t *main, const char *name, const char *greeting_sound, const char *short_greeting_sound, const char *invalid_sound, const char *exit_sound, const char *confirm_macro, const char *confirm_key, int confirm_attempts, int inter_timeout, int digit_len, int timeout, int max_failures, int max_timeouts, switch_memory_pool_t *pool)
 Create a new menu object.
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)
 switch_ivr_menu_bind_action: Bind a keystroke to an action.
switch_status_t switch_ivr_menu_bind_function (switch_ivr_menu_t *menu, switch_ivr_menu_action_function_t *function, const char *arg, const char *bind)
 Bind a keystroke to a callback function.
switch_status_t switch_ivr_menu_execute (switch_core_session_t *session, switch_ivr_menu_t *stack, char *name, void *obj)
 Execute a menu.
switch_status_t switch_ivr_menu_stack_free (switch_ivr_menu_t *stack)
 free a stack of menu objects.
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)
 Build a menu stack from an xml source.
switch_status_t switch_ivr_menu_str2action (const char *action_name, switch_ivr_action_t *action)
switch_status_t switch_ivr_menu_stack_xml_add_custom (switch_ivr_menu_xml_ctx_t *xml_menu_ctx, const char *name, switch_ivr_menu_action_function_t *function)
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 switch_ivr_phrase_macro (switch_core_session_t *session, const char *macro_name, const char *data, const char *lang, switch_input_args_t *args)
void switch_ivr_delay_echo (switch_core_session_t *session, uint32_t delay_ms)
switch_status_t switch_ivr_find_bridged_uuid (const char *uuid, char *b_uuid, switch_size_t blen)
void switch_ivr_intercept_session (switch_core_session_t *session, const char *uuid, switch_bool_t bleg)
void switch_ivr_park_session (switch_core_session_t *session)
switch_status_t switch_ivr_wait_for_answer (switch_core_session_t *session, switch_core_session_t *peer_session)
switch_status_t switch_ivr_read (switch_core_session_t *session, uint32_t min_digits, uint32_t max_digits, const char *prompt_audio_file, const char *var_name, char *digit_buffer, switch_size_t digit_buffer_length, uint32_t timeout, const char *valid_terminators)
switch_status_t switch_ivr_bind_dtmf_meta_session (switch_core_session_t *session, uint32_t key, switch_bind_flag_t bind_flags, const char *app)
switch_status_t switch_ivr_unbind_dtmf_meta_session (switch_core_session_t *session)
switch_status_t switch_ivr_soft_hold (switch_core_session_t *session, const char *unhold_key, const char *moh_a, const char *moh_b)
switch_status_t switch_ivr_say (switch_core_session_t *session, const char *tosay, const char *module_name, const char *say_type, const char *say_method, switch_input_args_t *args)
switch_say_method_t switch_ivr_get_say_method_by_name (const char *name)
switch_say_type_t switch_ivr_get_say_type_by_name (const char *name)
switch_status_t switch_ivr_set_user (switch_core_session_t *session, const char *data)


Typedef Documentation

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_action switch_ivr_menu_action_t
 

typedef struct switch_ivr_menu switch_ivr_menu_t
 

typedef struct switch_ivr_menu_xml_ctx switch_ivr_menu_xml_ctx_t
 


Enumeration Type Documentation

enum switch_ivr_action_t
 

Enumeration values:
SWITCH_IVR_ACTION_DIE 
SWITCH_IVR_ACTION_EXECMENU 
SWITCH_IVR_ACTION_EXECAPP 
SWITCH_IVR_ACTION_PLAYSOUND 
SWITCH_IVR_ACTION_BACK 
SWITCH_IVR_ACTION_TOMAIN 
SWITCH_IVR_ACTION_NOOP 
00638                       {
00639                  SWITCH_IVR_ACTION_DIE, /* Exit the menu.                  */
00640                  SWITCH_IVR_ACTION_EXECMENU,    /* Goto another menu in the stack. */
00641                  SWITCH_IVR_ACTION_EXECAPP,     /* Execute an application.         */
00642                  SWITCH_IVR_ACTION_PLAYSOUND,   /* Play a sound.                   */
00643                  SWITCH_IVR_ACTION_BACK,        /* Go back 1 menu.                 */
00644                  SWITCH_IVR_ACTION_TOMAIN,      /* Go back to the top level menu.  */
00645                  SWITCH_IVR_ACTION_NOOP /* No operation                    */
00646          } switch_ivr_action_t;

enum switch_ivr_menu_flags
 

Enumeration values:
SWITCH_IVR_MENU_FLAG_FALLTOMAIN 
SWITCH_IVR_MENU_FLAG_FREEPOOL 
SWITCH_IVR_MENU_FLAG_STACK 
00632                       {
00633                  SWITCH_IVR_MENU_FLAG_FALLTOMAIN = (1 << 0),
00634                  SWITCH_IVR_MENU_FLAG_FREEPOOL = (1 << 1),
00635                  SWITCH_IVR_MENU_FLAG_STACK = (1 << 2)
00636          } switch_ivr_menu_flags;


Function Documentation

switch_status_t switch_ivr_bind_dtmf_meta_session switch_core_session_t session,
uint32_t  key,
switch_bind_flag_t  bind_flags,
const char *  app
 

01506 {
01507         switch_channel_t *channel = switch_core_session_get_channel(session);
01508         dtmf_meta_data_t *md = switch_channel_get_private(channel, SWITCH_META_VAR_KEY);
01509 
01510         if (key > 9) {
01511                 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid key %u\n", key);
01512                 return SWITCH_STATUS_FALSE;
01513         }
01514 
01515         if (!md) {
01516                 md = switch_core_session_alloc(session, sizeof(*md));
01517                 switch_channel_set_private(channel, SWITCH_META_VAR_KEY, md);
01518                 switch_core_event_hook_add_send_dtmf(session, meta_on_dtmf);
01519                 switch_core_event_hook_add_recv_dtmf(session, meta_on_dtmf);
01520         }
01521 
01522         if (!switch_strlen_zero(app)) {
01523                 if ((bind_flags & SBF_DIAL_ALEG)) {
01524                         md->sr[SWITCH_DTMF_RECV].up = 1;
01525                         md->sr[SWITCH_DTMF_RECV].map[key].app = switch_core_session_strdup(session, app);
01526                         md->sr[SWITCH_DTMF_RECV].map[key].flags |= SMF_HOLD_BLEG;
01527                         md->sr[SWITCH_DTMF_RECV].map[key].bind_flags = bind_flags;
01528 
01529                         switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Bound A-Leg: %d %s\n", key, app);
01530                 }
01531                 if ((bind_flags & SBF_DIAL_BLEG)) {
01532                         md->sr[SWITCH_DTMF_SEND].up = 1;
01533                         md->sr[SWITCH_DTMF_SEND].map[key].app = switch_core_session_strdup(session, app);
01534                         md->sr[SWITCH_DTMF_SEND].map[key].flags |= SMF_HOLD_BLEG;
01535                         md->sr[SWITCH_DTMF_SEND].map[key].bind_flags = bind_flags;
01536                         switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Bound B-Leg: %d %s\n", key, app);
01537                 }
01538 
01539         } else {
01540                 if ((bind_flags & SBF_DIAL_ALEG)) {
01541                         switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "UnBound A-Leg: %d\n", key);
01542                         md->sr[SWITCH_DTMF_SEND].map[key].app = NULL;
01543                 } else {
01544                         switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "UnBound: B-Leg %d\n", key);
01545                         md->sr[SWITCH_DTMF_SEND].map[key].app = NULL;
01546                 }
01547         }
01548 
01549         return SWITCH_STATUS_SUCCESS;
01550 }

Here is the call graph for this function:

void switch_ivr_delay_echo switch_core_session_t session,
uint32_t  delay_ms
 

01719 {
01720         stfu_instance_t *jb;
01721         int qlen = 0;
01722         switch_codec_t *read_codec;
01723         stfu_frame_t *jb_frame;
01724         switch_frame_t *read_frame, write_frame = { 0 };
01725         switch_status_t status;
01726         switch_channel_t *channel = switch_core_session_get_channel(session);
01727         uint32_t interval, samples;
01728         uint32_t ts = 0;
01729 
01730         if (delay_ms < 1 || delay_ms > 10000) {
01731                 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid delay [%d] must be between 1 and 10000\n", delay_ms);
01732                 return;
01733         }
01734 
01735         read_codec = switch_core_session_get_read_codec(session);
01736         interval = read_codec->implementation->microseconds_per_frame / 1000;
01737         samples = switch_samples_per_frame(read_codec->implementation->samples_per_second, interval);
01738 
01739         qlen = delay_ms / (interval);
01740         switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Setting delay to %dms (%d frames)\n", delay_ms, qlen);
01741         jb = stfu_n_init(qlen);
01742 
01743         write_frame.codec = read_codec;
01744 
01745         while (switch_channel_ready(channel)) {
01746                 status = switch_core_session_read_frame(session, &read_frame, SWITCH_IO_FLAG_NONE, 0);
01747                 if (!SWITCH_READ_ACCEPTABLE(status)) {
01748                         break;
01749                 }
01750 
01751                 stfu_n_eat(jb, ts, read_frame->data, read_frame->datalen);
01752                 ts += interval;
01753 
01754                 if ((jb_frame = stfu_n_read_a_frame(jb))) {
01755                         write_frame.data = jb_frame->data;
01756                         write_frame.datalen = (uint32_t) jb_frame->dlen;
01757                         status = switch_core_session_write_frame(session, &write_frame, SWITCH_IO_FLAG_NONE, 0);
01758                         if (!SWITCH_READ_ACCEPTABLE(status)) {
01759                                 break;
01760                         }
01761                 }
01762         }
01763 
01764         stfu_n_destroy(&jb);
01765 }

Here is the call graph for this function:

switch_status_t switch_ivr_find_bridged_uuid const char *  uuid,
char *  b_uuid,
switch_size_t  blen
 

01070 {
01071         switch_core_session_t *rsession;
01072         switch_status_t status = SWITCH_STATUS_FALSE;
01073 
01074         switch_assert(uuid);
01075 
01076         if ((rsession = switch_core_session_locate(uuid))) {
01077                 switch_channel_t *rchannel = switch_core_session_get_channel(rsession);
01078                 const char *brto;
01079 
01080                 if ((brto = switch_channel_get_variable(rchannel, SWITCH_SIGNAL_BOND_VARIABLE))) {
01081                         switch_copy_string(b_uuid, brto, blen);
01082                         status = SWITCH_STATUS_SUCCESS;
01083                 }
01084                 switch_core_session_rwunlock(rsession);
01085         }
01086 
01087         return status;
01088 
01089 }

Here is the call graph for this function:

switch_say_method_t switch_ivr_get_say_method_by_name const char *  name  ) 
 

00069 {
00070         int x = 0;
00071         for (x = 0; SAY_METHOD_NAMES[x]; x++) {
00072                 if (!strcasecmp(SAY_METHOD_NAMES[x], name)) {
00073                         break;
00074                 }
00075         }
00076 
00077         return (switch_say_method_t) x;
00078 }

switch_say_type_t switch_ivr_get_say_type_by_name const char *  name  ) 
 

00081 {
00082         int x = 0;
00083         for (x = 0; SAY_TYPE_NAMES[x]; x++) {
00084                 if (!strcasecmp(SAY_TYPE_NAMES[x], name)) {
00085                         break;
00086                 }
00087         }
00088 
00089         return (switch_say_type_t) x;
00090 }

void switch_ivr_intercept_session switch_core_session_t session,
const char *  uuid,
switch_bool_t  bleg
 

01092 {
01093         switch_core_session_t *rsession, *bsession = NULL;
01094         switch_channel_t *channel, *rchannel, *bchannel = NULL;
01095         const char *buuid;
01096         char brto[SWITCH_UUID_FORMATTED_LENGTH + 1] = "";
01097 
01098         if (bleg) {
01099                 if (switch_ivr_find_bridged_uuid(uuid, brto, sizeof(brto)) == SWITCH_STATUS_SUCCESS) {
01100                         uuid = switch_core_session_strdup(session, brto);
01101                 } else {
01102                         switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "no uuid bridged to %s\n", uuid);
01103                         return;
01104                 }
01105         }
01106 
01107         if (switch_strlen_zero(uuid) || !(rsession = switch_core_session_locate(uuid))) {
01108                 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "no uuid %s\n", uuid);
01109                 return;
01110         }
01111 
01112         channel = switch_core_session_get_channel(session);
01113         rchannel = switch_core_session_get_channel(rsession);
01114 
01115         switch_channel_pre_answer(channel);
01116 
01117         if ((buuid = switch_channel_get_variable(rchannel, SWITCH_SIGNAL_BOND_VARIABLE))) {
01118                 bsession = switch_core_session_locate(buuid);
01119                 bchannel = switch_core_session_get_channel(bsession);
01120         }
01121 
01122         if (!switch_channel_test_flag(rchannel, CF_ANSWERED)) {
01123                 switch_channel_answer(rchannel);
01124         }
01125 
01126         switch_channel_set_state_flag(rchannel, CF_TRANSFER);
01127         switch_channel_set_state(rchannel, CS_PARK);
01128         
01129         if (bchannel) {
01130                 switch_channel_set_state_flag(bchannel, CF_TRANSFER);
01131                 switch_channel_set_state(bchannel, CS_PARK);
01132         }
01133 
01134         switch_ivr_uuid_bridge(switch_core_session_get_uuid(session), uuid);
01135         switch_core_session_rwunlock(rsession);
01136 
01137         if (bsession) {
01138                 switch_channel_hangup(bchannel, SWITCH_CAUSE_PICKED_OFF);
01139                 switch_core_session_rwunlock(bsession);
01140         }
01141 
01142         
01143 
01144 }

Here is the call graph for this function:

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
 

switch_ivr_menu_bind_action: Bind a keystroke to an action.

Parameters:
menu The menu obj you wish to bind to.
ivr_action switch_ivr_action_t enum of what you want to do.
arg Optional (sometimes necessary) string arguement.
bind KeyStrokes to bind the action to.
Returns:
SWUTCH_STATUS_SUCCESS if the action was binded
00200 {
00201         switch_ivr_menu_action_t *action;
00202         uint32_t len;
00203 
00204         if ((action = switch_core_alloc(menu->pool, sizeof(*action)))) {
00205                 action->bind = switch_core_strdup(menu->pool, bind);
00206                 action->next = menu->actions;
00207                 action->arg = switch_core_strdup(menu->pool, arg);
00208                 if (*action->bind == '/') {
00209                         action->re = 1;
00210                 } else {
00211                         len = (uint32_t) strlen(action->bind);
00212                         if (len > menu->inlen) {
00213                                 menu->inlen = len;
00214                         }
00215                 }
00216                 action->ivr_action = ivr_action;
00217                 menu->actions = action;
00218                 return SWITCH_STATUS_SUCCESS;
00219         }
00220 
00221         return SWITCH_STATUS_MEMERR;
00222 }

switch_status_t switch_ivr_menu_bind_function switch_ivr_menu_t menu,
switch_ivr_menu_action_function_t function,
const char *  arg,
const char *  bind
 

Bind a keystroke to a callback function.

Parameters:
menu The menu obj you wish to bind to.
function The function to call [int proto(struct switch_ivr_menu *, char *, size_t, void *)]
arg Optional (sometimes necessary) string arguement.
bind KeyStrokes to bind the action to.
Note:
The function is passed a buffer to fill in with any required argument data.

The function is also passed an optional void pointer to an object set upon menu execution. (think threads)

The function returns an switch_ivr_action_t enum of what you want to do. and looks to your buffer for args.

Returns:
SWUTCH_STATUS_SUCCESS if the function was binded
00226 {
00227         switch_ivr_menu_action_t *action;
00228         uint32_t len;
00229 
00230         if ((action = switch_core_alloc(menu->pool, sizeof(*action)))) {
00231                 action->bind = switch_core_strdup(menu->pool, bind);
00232                 action->next = menu->actions;
00233                 action->arg = switch_core_strdup(menu->pool, arg);
00234                 if (*action->bind == '/') {
00235                         action->re = 1;
00236                 } else {
00237                         len = (uint32_t) strlen(action->bind);
00238                         if (len > menu->inlen) {
00239                                 menu->inlen = len;
00240                         }
00241                 }
00242                 action->function = function;
00243                 menu->actions = action;
00244                 return SWITCH_STATUS_SUCCESS;
00245         }
00246 
00247         return SWITCH_STATUS_MEMERR;
00248 }

switch_status_t switch_ivr_menu_execute switch_core_session_t session,
switch_ivr_menu_t stack,
char *  name,
void *  obj
 

Execute a menu.

Parameters:
session The session running the menu.
stack The top-level menu object (the first one you created.)
name A pointer to the name of the menu.
obj A void pointer to an object you want to make avaliable to your callback functions that you may have binded with switch_ivr_menu_bind_function.
Returns:
SWITCH_STATUS_SUCCESS if all is well
00351 {
00352         int reps = 0, errs = 0, timeouts = 0, match = 0, running = 1;
00353         char *greeting_sound = NULL, *aptr = NULL;
00354         char arg[512];
00355         switch_ivr_action_t todo = SWITCH_IVR_ACTION_DIE;
00356         switch_ivr_menu_action_t *ap;
00357         switch_ivr_menu_t *menu;
00358         switch_channel_t *channel;
00359         switch_status_t status = SWITCH_STATUS_SUCCESS;
00360 
00361         if (!session || !stack || switch_strlen_zero(name)) {
00362                 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid menu context\n");
00363                 return SWITCH_STATUS_FALSE;
00364         }
00365 
00366         channel = switch_core_session_get_channel(session);
00367 
00368         if (!(menu = switch_ivr_menu_find(stack, name))) {
00369                 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid Menu!\n");
00370                 return SWITCH_STATUS_FALSE;
00371         }
00372 
00373         if (!(menu->buf = malloc(menu->inlen + 1))) {
00374                 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "No Memory!\n");
00375                 return SWITCH_STATUS_FALSE;
00376         }
00377 
00378         switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Executing IVR menu %s\n", menu->name);
00379         switch_channel_set_variable(channel, "ivr_menu_status", "success");
00380 
00381         for (reps = 0; running && status == SWITCH_STATUS_SUCCESS; reps++) {
00382                 if (!switch_channel_ready(channel)) {
00383                         break;
00384                 }
00385                 if (errs == menu->max_failures) {
00386                         switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Maximum failures\n");
00387                         switch_channel_set_variable(channel, "ivr_menu_status", "failure");
00388                         break;
00389                 }
00390                 if (timeouts == menu->max_timeouts) {
00391                         switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Maximum timeouts\n");
00392                         switch_channel_set_variable(channel, "ivr_menu_status", "timeout");
00393                         break;
00394                 }
00395 
00396                 if (reps > 0 && menu->short_greeting_sound) {
00397                         greeting_sound = menu->short_greeting_sound;
00398                 } else {
00399                         greeting_sound = menu->greeting_sound;
00400                 }
00401 
00402                 match = 0;
00403                 aptr = NULL;
00404 
00405                 memset(arg, 0, sizeof(arg));
00406 
00407                 memset(menu->buf, 0, menu->inlen + 1);
00408 
00409                 if (play_and_collect(session, menu, greeting_sound, menu->inlen) == SWITCH_STATUS_TIMEOUT && *menu->buf == '\0') {
00410                         timeouts++;
00411                         continue;
00412                 }
00413 
00414                 if (*menu->buf != '\0') {
00415 
00416                         for (ap = menu->actions; ap; ap = ap->next) {
00417                                 int ok = 0;
00418                                 char substituted[1024];
00419                                 char *use_arg = ap->arg;
00420 
00421                                 if (ap->re) {
00422                                         switch_regex_t *re = NULL;
00423                                         int ovector[30];
00424 
00425                                         if ((ok = switch_regex_perform(menu->buf, ap->bind, &re, ovector, sizeof(ovector) / sizeof(ovector[0])))) {
00426                                                 switch_perform_substitution(re, ok, ap->arg, menu->buf, substituted, sizeof(substituted), ovector);
00427                                                 use_arg = substituted;
00428                                         }
00429                                         switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "action regex [%s] [%s] [%d]\n", menu->buf, ap->bind, ok);
00430 
00431                                         switch_regex_safe_free(re);
00432                                 } else {
00433                                         ok = !strcmp(menu->buf, ap->bind);
00434                                 }
00435 
00436                                 if (ok) {
00437                                         match++;
00438                                         errs = 0;
00439                                         if (ap->function) {
00440                                                 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG,
00441                                                                                   "IVR function on menu '%s' matched '%s' param '%s'\n", menu->name, menu->buf, use_arg);
00442                                                 todo = ap->function(menu, use_arg, arg, sizeof(arg), obj);
00443                                                 aptr = arg;
00444                                         } else {
00445                                                 todo = ap->ivr_action;
00446                                                 aptr = use_arg;
00447                                                 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG,
00448                                                                                   "IVR action on menu '%s' matched '%s' param '%s'\n", menu->name, menu->buf, aptr);
00449                                         }
00450 
00451                                         switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "switch_ivr_menu_execute todo=[%d]\n", todo);
00452 
00453                                         switch (todo) {
00454                                         case SWITCH_IVR_ACTION_DIE:
00455                                                 status = SWITCH_STATUS_FALSE;
00456                                                 break;
00457                                         case SWITCH_IVR_ACTION_PLAYSOUND:
00458                                                 status = switch_ivr_play_file(session, NULL, aptr, NULL);
00459                                                 break;
00460                                         case SWITCH_IVR_ACTION_EXECMENU:
00461                                                 reps = -1;
00462                                                 status = switch_ivr_menu_execute(session, stack, aptr, obj);
00463                                                 break;
00464                                         case SWITCH_IVR_ACTION_EXECAPP:
00465                                                 {
00466                                                         const switch_application_interface_t *application_interface;
00467                                                         char *app_name;
00468                                                         char *app_arg = NULL;
00469 
00470                                                         status = SWITCH_STATUS_FALSE;
00471 
00472                                                         if (!switch_strlen_zero(aptr)) {
00473                                                                 app_name = switch_core_session_strdup(session, aptr);
00474                                                                 if ((app_arg = strchr(app_name, ' '))) {
00475                                                                         *app_arg++ = '\0';
00476                                                                 }
00477 
00478                                                                 if ((application_interface = switch_loadable_module_get_application_interface(app_name))) {
00479                                                                         switch_core_session_exec(session, application_interface, app_arg);
00480                                                                         status = SWITCH_STATUS_SUCCESS;
00481                                                                 }
00482                                                         }
00483                                                 }
00484                                                 break;
00485                                         case SWITCH_IVR_ACTION_BACK:
00486                                                 running = 0;
00487                                                 status = SWITCH_STATUS_SUCCESS;
00488                                                 break;
00489                                         case SWITCH_IVR_ACTION_TOMAIN:
00490                                                 switch_set_flag(stack, SWITCH_IVR_MENU_FLAG_FALLTOMAIN);
00491                                                 status = SWITCH_STATUS_BREAK;
00492                                                 break;
00493                                         case SWITCH_IVR_ACTION_NOOP:
00494                                                 status = SWITCH_STATUS_SUCCESS;
00495                                                 break;
00496                                         default:
00497                                                 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Invalid TODO!\n");
00498                                                 break;
00499                                         }
00500                                 }
00501                         }
00502 
00503                         if (switch_test_flag(menu, SWITCH_IVR_MENU_FLAG_STACK)) {               /* top level */
00504                                 if (switch_test_flag(stack, SWITCH_IVR_MENU_FLAG_FALLTOMAIN)) { /* catch the fallback and recover */
00505                                         switch_clear_flag(stack, SWITCH_IVR_MENU_FLAG_FALLTOMAIN);
00506                                         status = SWITCH_STATUS_SUCCESS;
00507                                         running = 1;
00508                                         continue;
00509                                 }
00510                         }
00511                 }
00512                 if (!match) {
00513                         if (*menu->buf) {
00514                                 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "IVR menu '%s' caught invalid input '%s'\n", menu->name, menu->buf);
00515                                 if (menu->invalid_sound) {
00516                                         play_and_collect(session, menu, menu->invalid_sound, 0);
00517                                 }
00518                         } else {
00519                                 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "IVR menu '%s' no input detected\n", menu->name);
00520                         }
00521                         errs++;
00522                         if (status == SWITCH_STATUS_SUCCESS) {
00523                                 status = switch_ivr_sleep(session, 1000, NULL);
00524                         }
00525                         /* breaks are ok too */
00526                         if (SWITCH_STATUS_IS_BREAK(status)) {
00527                                 status = SWITCH_STATUS_SUCCESS;
00528                         }
00529                 }
00530         }
00531 
00532         switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "exit-sound '%s'\n", menu->exit_sound);
00533         if (!switch_strlen_zero(menu->exit_sound)) {
00534                 status = play_and_collect(session, menu, menu->exit_sound, 0);
00535         }
00536 
00537         switch_safe_free(menu->buf);
00538 
00539         return status;
00540 }

Here is the call graph for this function:

switch_status_t switch_ivr_menu_init switch_ivr_menu_t **  new_menu,
switch_ivr_menu_t main,
const char *  name,
const char *  greeting_sound,
const char *  short_greeting_sound,
const char *  invalid_sound,
const char *  exit_sound,
const char *  confirm_macro,
const char *  confirm_key,
int  confirm_attempts,
int  inter_timeout,
int  digit_len,
int  timeout,
int  max_failures,
int  max_timeouts,
switch_memory_pool_t pool
 

Create a new menu object.

Parameters:
new_menu the pointer to the new menu
main The top level menu, (NULL if this is the top level one).
name A pointer to the name of this menu.
greeting_sound Optional pointer to a main sound (press 1 for this 2 for that).
short_greeting_sound Optional pointer to a shorter main sound for subsequent loops.
invalid_sound Optional pointer to a sound to play after invalid input.
exit_sound Optional pointer to a sound to play upon exiting the menu.
confirm_macro phrase macro name to confirm input
confirm_key the dtmf key required for positive confirmation
confirm_attempts number of times to prompt to confirm input before failure
inter_timeout inter-digit timeout
digit_len max number of digits
timeout A number of milliseconds to pause before looping.
max_failures Maximum number of failures to withstand before hangingup This resets everytime you enter the menu.
pool memory pool (NULL to create one).
Returns:
SWITCH_STATUS_SUCCESS if the menu was created.
00108 {
00109         switch_ivr_menu_t *menu;
00110         uint8_t newpool = 0;
00111 
00112         if (!pool) {
00113                 if (switch_core_new_memory_pool(&pool) != SWITCH_STATUS_SUCCESS) {
00114                         switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "OH OH no pool\n");
00115                         return SWITCH_STATUS_MEMERR;
00116                 }
00117                 newpool = 1;
00118         }
00119 
00120         if (!(menu = switch_core_alloc(pool, sizeof(*menu)))) {
00121                 if (newpool) {
00122                         switch_core_destroy_memory_pool(&pool);
00123                         switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Memory Error!\n");
00124                         return SWITCH_STATUS_MEMERR;
00125                 }
00126         }
00127 
00128         menu->pool = pool;
00129 
00130         if (!confirm_attempts) {
00131                 confirm_attempts = 3;
00132         }
00133 
00134         if (!inter_timeout) {
00135                 inter_timeout = timeout / 2;
00136         }
00137 
00138         if (!switch_strlen_zero(name)) {
00139                 menu->name = switch_core_strdup(menu->pool, name);
00140         }
00141 
00142         if (!switch_strlen_zero(greeting_sound)) {
00143                 menu->greeting_sound = switch_core_strdup(menu->pool, greeting_sound);
00144         }
00145 
00146         if (!switch_strlen_zero(short_greeting_sound)) {
00147                 menu->short_greeting_sound = switch_core_strdup(menu->pool, short_greeting_sound);
00148         }
00149 
00150         if (!switch_strlen_zero(invalid_sound)) {
00151                 menu->invalid_sound = switch_core_strdup(menu->pool, invalid_sound);
00152         }
00153 
00154         if (!switch_strlen_zero(exit_sound)) {
00155                 menu->exit_sound = switch_core_strdup(menu->pool, exit_sound);
00156         }
00157 
00158         if (!switch_strlen_zero(confirm_macro)) {
00159                 menu->confirm_macro = switch_core_strdup(menu->pool, confirm_macro);
00160         }
00161 
00162         if (!switch_strlen_zero(confirm_key)) {
00163                 menu->confirm_key = switch_core_strdup(menu->pool, confirm_key);
00164         }
00165 
00166         menu->confirm_attempts = confirm_attempts;
00167 
00168         menu->inlen = digit_len;
00169 
00170         menu->max_failures = max_failures;
00171 
00172         menu->max_timeouts = max_timeouts;
00173 
00174         menu->timeout = timeout;
00175 
00176         menu->inter_timeout = inter_timeout;
00177 
00178         menu->actions = NULL;
00179 
00180         if (newpool) {
00181                 menu->flags |= SWITCH_IVR_MENU_FLAG_FREEPOOL;
00182         }
00183 
00184         if (menu->timeout <= 0) {
00185                 menu->timeout = 10000;
00186         }
00187 
00188         if (main) {
00189                 switch_ivr_menu_stack_add(&main, menu);
00190         } else {
00191                 menu->flags |= SWITCH_IVR_MENU_FLAG_STACK;
00192         }
00193 
00194         *new_menu = menu;
00195 
00196         return SWITCH_STATUS_SUCCESS;
00197 }

Here is the call graph for this function:

switch_status_t switch_ivr_menu_stack_free switch_ivr_menu_t stack  ) 
 

free a stack of menu objects.

Parameters:
stack The top level menu you wish to destroy.
Returns:
SWITCH_STATUS_SUCCESS if the object was a top level menu and it was freed
00251 {
00252         switch_status_t status = SWITCH_STATUS_FALSE;
00253 
00254         if (stack != NULL && stack->pool != NULL) {
00255                 if (switch_test_flag(stack, SWITCH_IVR_MENU_FLAG_STACK)
00256                         && switch_test_flag(stack, SWITCH_IVR_MENU_FLAG_FREEPOOL)) {
00257                                 switch_memory_pool_t *pool = stack->pool;
00258                                 status = switch_core_destroy_memory_pool(&pool);
00259                 } else {
00260                         status = SWITCH_STATUS_SUCCESS;
00261                 }
00262         }
00263 
00264         return status;
00265 }

switch_status_t switch_ivr_menu_stack_xml_add_custom switch_ivr_menu_xml_ctx_t xml_menu_ctx,
const char *  name,
switch_ivr_menu_action_function_t function
 

Parameters:
xml_menu_ctx The XML menu parser context previously created by switch_ivr_menu_stack_xml_init
name The xml tag name to add to the parser engine
function The menu function callback that will be executed when menu digits are bound to this name
Returns:
SWITCH_STATUS_SUCCESS if all is well
00693 {
00694         return switch_ivr_menu_stack_xml_add(xml_menu_ctx, name, -1, function);
00695 }

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
 

Build a menu stack from an xml source.

Parameters:
xml_menu_ctx The XML menu parser context previously created by switch_ivr_menu_stack_xml_init
menu_stack The menu stack object that will be created for you
xml_menus The xml Menus source
xml_menu The xml Menu source of the menu to be created
Returns:
SWITCH_STATUS_SUCCESS if all is well
00699 {
00700         switch_status_t status = SWITCH_STATUS_FALSE;
00701 
00702         if (xml_menu_ctx != NULL && menu_stack != NULL && xml_menu != NULL) {
00703                 const char *menu_name = switch_xml_attr_soft(xml_menu, "name");             /* if the attr doesn't exist, return "" */
00704                 const char *greet_long = switch_xml_attr(xml_menu, "greet-long");               /* if the attr doesn't exist, return NULL */
00705                 const char *greet_short = switch_xml_attr(xml_menu, "greet-short");             /* if the attr doesn't exist, return NULL */
00706                 const char *invalid_sound = switch_xml_attr(xml_menu, "invalid-sound");     /* if the attr doesn't exist, return NULL */
00707                 const char *exit_sound = switch_xml_attr(xml_menu, "exit-sound");               /* if the attr doesn't exist, return NULL */
00708                 const char *timeout = switch_xml_attr_soft(xml_menu, "timeout");                /* if the attr doesn't exist, return "" */
00709                 const char *max_failures = switch_xml_attr_soft(xml_menu, "max-failures");      /* if the attr doesn't exist, return "" */
00710                 const char *max_timeouts = switch_xml_attr_soft(xml_menu, "max-timeouts");
00711                 const char *confirm_macro= switch_xml_attr(xml_menu, "confirm-macro");
00712                 const char *confirm_key= switch_xml_attr(xml_menu, "confirm-key");
00713                 const char *confirm_attempts = switch_xml_attr_soft(xml_menu, "confirm-attempts");
00714                 const char *digit_len = switch_xml_attr_soft(xml_menu, "digit-len");
00715                 const char *inter_timeout = switch_xml_attr_soft(xml_menu, "inter-digit-timeout");
00716 
00717                 switch_ivr_menu_t *menu = NULL;
00718 
00719                 if (switch_strlen_zero(max_timeouts)) {
00720                         max_timeouts = max_failures;
00721                 }
00722 
00723                 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "building menu '%s'\n", menu_name);
00724 
00725                 status = switch_ivr_menu_init(&menu,
00726                                                                           *menu_stack,
00727                                                                           menu_name,
00728                                                                           greet_long,
00729                                                                           greet_short,
00730                                                                           invalid_sound,
00731                                                                           exit_sound, 
00732                                                                           confirm_macro,
00733                                                                           confirm_key,
00734                                                                           atoi(confirm_attempts),
00735                                                                           atoi(inter_timeout),
00736                                                                           atoi(digit_len),
00737                                                                           atoi(timeout), 
00738                                                                           strlen(max_failures)? atoi(max_failures): 1, 
00739                                                                           strlen(max_timeouts)? atoi(max_timeouts): 1, 
00740                                                                           xml_menu_ctx->pool);
00741                 /* set the menu_stack for the caller */
00742                 if (status == SWITCH_STATUS_SUCCESS && *menu_stack == NULL) {
00743                         *menu_stack = menu;
00744                 }
00745 
00746                 if (status == SWITCH_STATUS_SUCCESS && menu != NULL) {
00747                         switch_xml_t xml_kvp;
00748 
00749                         /* build menu entries */
00750                         for (xml_kvp = switch_xml_child(xml_menu, "entry"); xml_kvp != NULL && status == SWITCH_STATUS_SUCCESS; xml_kvp = xml_kvp->next) {
00751                                 const char *action = switch_xml_attr(xml_kvp, "action");
00752                                 const char *digits = switch_xml_attr(xml_kvp, "digits");
00753                                 const char *param = switch_xml_attr_soft(xml_kvp, "param");
00754 
00755                                 if (is_valid_action(action) && !switch_strlen_zero(digits)) {
00756                                         switch_ivr_menu_xml_map_t *xml_map = xml_menu_ctx->map;
00757                                         int found = 0;
00758 
00759                                         /* find and appropriate xml handler */
00760                                         while (xml_map != NULL && !found) {
00761                                                 if (!(found = (strcasecmp(xml_map->name, action) == 0))) {
00762                                                         xml_map = xml_map->next;
00763                                                 }
00764                                         }
00765 
00766                                         if (found && xml_map != NULL) {
00767                                                 /* do we need to build a new sub-menu ? */
00768                                                 if (xml_map->action == SWITCH_IVR_ACTION_EXECMENU && switch_ivr_menu_find(*menu_stack, param) == NULL) {
00769                                                         if ((xml_menu = switch_xml_find_child(xml_menus, "menu", "name", param)) != NULL) {
00770                                                                 status = switch_ivr_menu_stack_xml_build(xml_menu_ctx, menu_stack, xml_menus, xml_menu);
00771                                                         }
00772                                                 }
00773                                                 /* finally bind the menu entry */
00774                                                 if (status == SWITCH_STATUS_SUCCESS) {
00775                                                         if (xml_map->function != NULL) {
00776                                                                 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG,
00777                                                                                                   "binding menu caller control '%s'/'%s' to '%s'\n", xml_map->name, param, digits);
00778                                                                 status = switch_ivr_menu_bind_function(menu, xml_map->function, param, digits);
00779                                                         } else {
00780                                                                 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "binding menu action '%s' to '%s'\n", xml_map->name, digits);
00781                                                                 status = switch_ivr_menu_bind_action(menu, xml_map->action, param, digits);
00782                                                         }
00783                                                 }
00784                                         }
00785                                 } else {
00786                                         status = SWITCH_STATUS_FALSE;
00787                                 }
00788                         }
00789                 }
00790         }
00791 
00792         if (status != SWITCH_STATUS_SUCCESS) {
00793                 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Unable to build xml menu\n");
00794         }
00795 
00796         return status;
00797 }

Here is the call graph for this function:

switch_status_t switch_ivr_menu_stack_xml_init switch_ivr_menu_xml_ctx_t **  xml_menu_ctx,
switch_memory_pool_t pool
 

Parameters:
xml_menu_ctx A pointer of a XML menu parser context to be created
pool memory pool (NULL to create one)
Returns:
SWITCH_STATUS_SUCCESS if all is well
00657 {
00658         switch_status_t status = SWITCH_STATUS_FALSE;
00659         int autocreated = 0;
00660 
00661         /* build a memory pool ? */
00662         if (pool == NULL) {
00663                 status = switch_core_new_memory_pool(&pool);
00664                 autocreated = 1;
00665         }
00666         /* allocate the xml context */
00667         if (xml_menu_ctx != NULL && pool != NULL) {
00668                 *xml_menu_ctx = switch_core_alloc(pool, sizeof(switch_ivr_menu_xml_ctx_t));
00669                 if (*xml_menu_ctx != NULL) {
00670                         (*xml_menu_ctx)->pool = pool;
00671                         (*xml_menu_ctx)->autocreated = autocreated;
00672                         (*xml_menu_ctx)->map = NULL;
00673                         status = SWITCH_STATUS_SUCCESS;
00674                 } else {
00675                         switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Unable to alloc xml_ctx\n");
00676                         status = SWITCH_STATUS_FALSE;
00677                 }
00678         }
00679         /* build the standard/default xml menu handler mappings */
00680         if (status == SWITCH_STATUS_SUCCESS && xml_menu_ctx != NULL && *xml_menu_ctx != NULL) {
00681                 int i;
00682 
00683                 for (i = 0; iam[i].name && status == SWITCH_STATUS_SUCCESS; i++) {
00684                         status = switch_ivr_menu_stack_xml_add(*xml_menu_ctx, iam[i].name, iam[i].action, NULL);
00685                 }
00686         }
00687 
00688         return status;
00689 }

Here is the call graph for this function:

switch_status_t switch_ivr_menu_str2action const char *  action_name,
switch_ivr_action_t action
 

00617 {
00618         int i;
00619 
00620         if (!switch_strlen_zero(action_name)) {
00621                 for(i = 0;;i++) {
00622                         if (!iam[i].name) {
00623                                 break;
00624                         }
00625 
00626                         if (!strcasecmp(iam[i].name, action_name)) {
00627                                 *action = iam[i].action;
00628                                 return SWITCH_STATUS_SUCCESS;
00629                         }
00630                 }
00631         }
00632 
00633         return SWITCH_STATUS_FALSE;
00634 }

void switch_ivr_park_session switch_core_session_t session