Author: knhor Date: Sat Dec 30 15:04:41 2006 New Revision: 3873 Modified: freeswitch/branches/knhor/trunk/src/mod/applications/mod_conference/mod_conference.c Log: move caller control digit parser from the conference to the caller Modified: freeswitch/branches/knhor/trunk/src/mod/applications/mod_conference/mod_conference.c ============================================================================== --- freeswitch/branches/knhor/trunk/src/mod/applications/mod_conference/mod_conference.c (original) +++ freeswitch/branches/knhor/trunk/src/mod/applications/mod_conference/mod_conference.c Sat Dec 30 15:04:41 2006 @@ -55,7 +55,7 @@ //#define OPTION_IVR_MENU_SUPPORT */ /* define this if you want your xmpp users to be able to admin the conferences via chat */ -//#define ENABLE_CHAT_ADMIN +#define ENABLE_CHAT_ADMIN typedef enum { FILE_STOP_CURRENT, @@ -178,12 +178,12 @@ char *kicked_sound; char *caller_id_name; char *caller_id_number; - switch_ivr_digit_stream_parser_t *dtmf_parser; char *pin; char *pin_sound; char *bad_pin_sound; char *profile_name; char *domain; + char *caller_controls; uint32_t flags; switch_call_cause_t bridge_hangup_cause; switch_mutex_t *flag_mutex; @@ -198,6 +198,7 @@ uint32_t count; int32_t energy_level; uint8_t min; + conf_xml_cfg_t xml_cfg; // switch_hash_t *chat_admin; // switch_hash_t *chat_id; } conference_obj_t; @@ -239,6 +240,7 @@ switch_audio_resampler_t *read_resampler; conference_file_node_t *fnode; conference_relationship_t *relationships; + switch_ivr_digit_stream_parser_t *dtmf_parser; switch_ivr_digit_stream_t *digit_stream; struct conference_member *next; }; @@ -295,7 +297,7 @@ static switch_status_t conference_member_play_file(conference_member_t *member, char *file, uint32_t leadin); static switch_status_t conference_member_say(conference_member_t *member, char *text, uint32_t leadin); static uint32_t conference_member_stop_file(conference_member_t *member, file_stop_t stop); -static conference_obj_t *conference_new(char *name, conf_xml_cfg_t cfg, switch_memory_pool_t *pool); +static conference_obj_t *conference_new(char *name, conf_xml_cfg_t *xml_cfg, switch_memory_pool_t *pool); static switch_status_t chat_send(char *proto, char *from, char *to, char *subject, char *body, char *hint); static void launch_conference_record_thread(conference_obj_t *conference, char *path); @@ -885,8 +887,6 @@ switch_thread_rwlock_unlock(conference->rwlock); switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Write Lock OFF\n"); - switch_ivr_digit_stream_parser_destroy(conference->dtmf_parser); - if (conference->pool) { switch_memory_pool_t *pool = conference->pool; switch_core_destroy_memory_pool(&pool); @@ -1389,6 +1389,256 @@ }; #define CCFNTBL_QTY (sizeof(ccfntbl)/sizeof(ccfntbl[0])) +#ifdef OPTION_IVR_MENU_SUPPORT +static switch_ivr_action_t caller_control_ivr_handler(switch_ivr_menu_t *menu, char *param, char *buf, size_t buflen, void *obj) +{ + switch_ivr_action_t action = SWITCH_IVR_ACTION_NOOP; + + if (!switch_strlen_zero(param)) { + if (obj != NULL) { + int i, found; + char *action_name = strdup(param); + + if (action_name != NULL) { + char *sep = (action_name != NULL ? strchr(action_name, ' ') : NULL); + + /* split the action from any parameters */ + if (sep != NULL) { + *sep = '\0'; + } + + /* find and execute the caller control handler */ + for(i = 0, found = 0; !found && i<CCFNTBL_QTY; i++) { + found = (ccfntbl[i].action != CALLER_CONTROL_MENU && strcasecmp(ccfntbl[i].key, action_name) == 0); + if (found) { + if (obj != NULL) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "invoking caller control menu action '%s'\n", ccfntbl[i].key); + ccfntbl[i].handler((conference_member_t *)obj, (sep != NULL ? sep+1 : NULL)); + if (ccfntbl[i].action == CALLER_CONTROL_HANGUP) { + action = SWITCH_IVR_ACTION_DIE; + } + } + } + } + + free(action_name); + } + + if (!found) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "unknown caller control menu action '%s'\n", param); + } + } else { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "unable to invoke caller control menu action '%s', NULL member!\n", param); + } + } else { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "NULL or empty param!\n"); + } + + return action; +} + +/* + static switch_status_t ivr_menu_callback_play_file(char *file, uint32_t leadin, void *member) + { + switch_status_t status; + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "ivr_menu_callback_play_file\n"); + status = conference_member_play_file((conference_member_t *)member, file, leadin); + if (status != SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "ivr_menu_callback_play_file ERROR\n"); + } + + return status; + } + + static switch_status_t ivr_menu_callback_say(char *file, uint32_t leadin, void *member) + { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "ivr_menu_callback_say\n"); + return conference_member_say((conference_member_t *)member, file, leadin); + } +*/ + +static switch_status_t caller_control_ivr_build(caller_control_menu_ctx_t **ctx, + conference_obj_t *conference, + switch_xml_t menu_group, + char *menu_name) +{ + switch_status_t status = SWITCH_STATUS_FALSE; + switch_xml_t xml_menus; + switch_xml_t xml_menu; + + assert(conference != NULL); + assert(ctx != NULL); + assert(menu_group != NULL); + assert(menu_name != NULL); + assert(xml_menus != NULL); + + xml_menus = switch_xml_child(menu_group, "menus"); + xml_menu = (xml_menus != NULL ? switch_xml_find_child(xml_menus, "menu", "name", menu_name) : NULL); + + + + /* if we found the requested menu in our menu_group */ + if (xml_menu != NULL && xml_menu != NULL) { + *ctx = (caller_control_menu_ctx_t *)switch_core_alloc(conference->pool, sizeof(caller_control_menu_ctx_t)); + + if (*ctx != NULL) { + memset(*ctx, 0, sizeof(caller_control_menu_ctx_t)); + + /* setup an xml parser context, and a menu stack context for the specified menu in our memory pool */ + status = switch_ivr_menu_stack_xml_init(&(*ctx)->xml_ctx, conference->pool); + if (status == SWITCH_STATUS_SUCCESS) { + (*ctx)->name = switch_core_strdup(conference->pool, menu_name); + + /* add our xml menu handler to the xml stack parser */ + status = switch_ivr_menu_stack_xml_add_custom((*ctx)->xml_ctx, "control", &caller_control_ivr_handler); + if (status != SWITCH_STATUS_SUCCESS) + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "unable to add custom xml handler\n"); + + /* parse the xml stack to build the menu stack */ + status = switch_ivr_menu_stack_xml_build((*ctx)->xml_ctx, &(*ctx)->menu_stack, xml_menus, xml_menu, conference->timer_name); + if (status != SWITCH_STATUS_SUCCESS) + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "unable to build xml menu stack\n"); + + /* + // instruct ivr menu to use our file play and tts routines + status = switch_ivr_menu_set_fileplay_callback((*ctx)->menu_stack, &ivr_menu_callback_play_file); + if (status != SWITCH_STATUS_SUCCESS) + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "unable to set file play calback\n"); + status = switch_ivr_menu_set_tts_callback((*ctx)->menu_stack, &ivr_menu_callback_say); + if (status != SWITCH_STATUS_SUCCESS) + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "unable to set tts calback\n"); + */ + } else { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "unable to init xml menu context\n"); + } + if (status != SWITCH_STATUS_SUCCESS) + *ctx = NULL; + } + } else { + if (xml_menus == NULL) + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "caller control menu unable to find xml menus\n"); + if (xml_menu == NULL) + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "caller control menu unable to find xml menu '%s'\n", menu_name); + } + + return status; +} +#endif + +static switch_status_t caller_control_build_default(conference_member_t *member) +{ + switch_status_t status = SWITCH_STATUS_FALSE; + uint32_t i; + caller_control_action_t *action; + + assert(member != NULL); + + for(i = 0, status = SWITCH_STATUS_SUCCESS; status == SWITCH_STATUS_SUCCESS && i<CCFNTBL_QTY; i++) { + if (!switch_strlen_zero(ccfntbl[i].digits)) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Installing default caller control action '%s' bound to '%s'.\n", + ccfntbl[i].key, + ccfntbl[i].digits); + action = (caller_control_action_t *)switch_core_alloc(member->pool, sizeof(caller_control_action_t)); + if (action != NULL) { + action->fndesc = &ccfntbl[i]; + action->data = NULL; + status = switch_ivr_digit_stream_parser_set_event(member->dtmf_parser, ccfntbl[i].digits, action); + } else { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "unable to alloc memory for caller control binding '%s' to '%s'\n", + ccfntbl[i].key, ccfntbl[i].digits); + status = SWITCH_STATUS_MEMERR; + } + } + } + + + return status; +} + +static switch_status_t caller_control_build_custom(conference_member_t *member, switch_xml_t xml_controls, switch_xml_t xml_menus) +{ + switch_status_t status = SWITCH_STATUS_FALSE; + switch_xml_t xml_kvp; + + assert(member != NULL); + assert(xml_controls != NULL); + + /* parse the controls tree for caller control digit strings */ + for (xml_kvp = switch_xml_child(xml_controls, "control"); xml_kvp; xml_kvp = xml_kvp->next) { + char *key = (char *) switch_xml_attr(xml_kvp, "action"); + char *val = (char *) switch_xml_attr(xml_kvp, "digits"); + char *data = (char *)switch_xml_attr_soft(xml_kvp, "data"); + + if (!switch_strlen_zero(key) && !switch_strlen_zero(val)) { + uint32_t i; + + /* scan through all of the valid actions, and if found, */ + /* set the new caller control action digit string, then */ + /* stop scanning the table, and go to the next xml kvp. */ + for(i = 0, status = SWITCH_STATUS_NOOP; i<CCFNTBL_QTY && status == SWITCH_STATUS_NOOP; i++) { + + if (strcasecmp(ccfntbl[i].key, key) == 0) { + status = SWITCH_STATUS_SUCCESS; +#ifdef OPTION_IVR_MENU_SUPPORT + if (xml_menus != NULL && ccfntbl[i].action == CALLER_CONTROL_MENU) { + char *menu_group_name = strdup(data); + char *menu_name = (menu_group_name != NULL ? strchr(menu_group_name, '/') : NULL); + + /* format: "menu_group_name/menu_name" */ + /* separate the menu name from the menu group */ + if (menu_name != NULL) { + *(menu_name++) = '\0'; + } + /* if there is a menu name, build the menu */ + if (menu_name != NULL) { + caller_control_menu_ctx_t *menu_ctx = NULL; + switch_xml_t menu_group = switch_xml_find_child(xml_menus, "group", "name", menu_group_name); + + status = caller_control_ivr_build(&menu_ctx, conference, menu_group, menu_name); + data = (char *)menu_ctx; + } else { + status = SWITCH_STATUS_FALSE; + } + + if (status != SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "unable to build menu '%s' bound to '%s'\n", data, val); + } + + /* clean up */ + if (menu_group_name != NULL) { + free(menu_group_name); + } + } +#endif + + if (status == SWITCH_STATUS_SUCCESS) { + caller_control_action_t *action; + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Installing caller control action '%s' bound to '%s'.\n", key, val); + action = (caller_control_action_t *)switch_core_alloc(member->pool, sizeof(caller_control_action_t)); + if (action != NULL) { + action->fndesc = &ccfntbl[i]; + action->data = (void *)data; + status = switch_ivr_digit_stream_parser_set_event(member->dtmf_parser, val, action); + } else { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "unable to alloc memory for caller control binding '%s' to '%s'\n", ccfntbl[i].key, ccfntbl[i].digits); + status = SWITCH_STATUS_MEMERR; + } + } + } + } + if (status == SWITCH_STATUS_NOOP) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Invalid caller control action name '%s'.\n", key); + } + } else { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Invalid caller control config entry pair action = '%s' digits = '%s'\n", key, val); + } + } + + return status; +} + /* marshall frames from the conference (or file or tts output) to the call leg */ /* NB. this starts the input thread after some initial setup for the call leg */ static void conference_loop_output(conference_member_t *member) @@ -1429,8 +1679,33 @@ /* Start the input thread */ launch_conference_loop_input(member, switch_core_session_get_pool(member->session)); + /* caller control configuration chores */ + if (switch_ivr_digit_stream_parser_new(member->pool, &member->dtmf_parser) == SWITCH_STATUS_SUCCESS) { + switch_status_t status = SWITCH_STATUS_FALSE; + + /* if no controls, or default controls specified, install default */ + if (member->conference->caller_controls == NULL || *member->conference->caller_controls == '\0' || strcasecmp(member->conference->caller_controls, "default") == 0) { + status = caller_control_build_default(member); + } else if (strcasecmp(member->conference->caller_controls, "none") != 0) { + /* try to build caller control if the group has been specified and != "none" */ + switch_xml_t xml_controls = switch_xml_find_child(member->conference->xml_cfg.controls, "group", "name", member->conference->caller_controls); +#ifdef OPTION_IVR_MENU_SUPPORT + status = caller_control_build_custom(member, xml_controls, member->conference->xml_cfg.menus); +#else + status = caller_control_build_custom(member, xml_controls, NULL); +#endif + if (status != SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Unable to install caller controls group '%s'\n", member->conference->caller_controls); + } + } else { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "no caller controls intalled.\n"); + } + } else { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Unable to allocate caller control digit parser.\n"); + } + /* build a digit stream object */ - if (member->conference->dtmf_parser != NULL && switch_ivr_digit_stream_new(member->conference->dtmf_parser, &member->digit_stream) != SWITCH_STATUS_SUCCESS) { + if (member->dtmf_parser != NULL && switch_ivr_digit_stream_new(member->dtmf_parser, &member->digit_stream) != SWITCH_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Warning Will Robinson, there is no digit parser stream object\n"); } @@ -1482,15 +1757,15 @@ if (switch_channel_has_dtmf(channel)) { switch_channel_dequeue_dtmf(channel, dtmf, sizeof(dtmf)); - if (member->conference->dtmf_parser != NULL) { + if (member->dtmf_parser != NULL) { for (digit = dtmf; *digit && caller_action == NULL; digit++) { - caller_action = (caller_control_action_t *)switch_ivr_digit_stream_parser_feed(member->conference->dtmf_parser, member->digit_stream, *digit); + caller_action = (caller_control_action_t *)switch_ivr_digit_stream_parser_feed(member->dtmf_parser, member->digit_stream, *digit); } } /* otherwise, clock the parser so that it can handle digit timeout detection */ - } else if (member->conference->dtmf_parser != NULL) { - caller_action = (caller_control_action_t *)switch_ivr_digit_stream_parser_feed(member->conference->dtmf_parser, member->digit_stream, '\0'); + } else if (member->dtmf_parser != NULL) { + caller_action = (caller_control_action_t *)switch_ivr_digit_stream_parser_feed(member->dtmf_parser, member->digit_stream, '\0'); } /* if a caller action has been detected, handle it */ @@ -1618,6 +1893,10 @@ switch_ivr_digit_stream_destroy(member->digit_stream); } + if (member->dtmf_parser != NULL) { + switch_ivr_digit_stream_parser_destroy(member->dtmf_parser); + } + switch_clear_flag_locked(member, MFLAG_RUNNING); switch_core_timer_destroy(&timer); @@ -2888,18 +3167,17 @@ } /* Create the conference object. */ - new_conference = conference_new(conf_name, xml_cfg, pool); - - /* Release the config registry handle */ - if (xml_cfg.cxml) { - switch_xml_free(xml_cfg.cxml); - } + new_conference = conference_new(conf_name, &xml_cfg, pool); if (!new_conference) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Memory Error!\n"); if (pool != NULL) { switch_core_destroy_memory_pool(&pool); } + /* Release the config registry handle */ + if (xml_cfg.cxml) { + switch_xml_free(xml_cfg.cxml); + } goto done; } @@ -3454,7 +3732,7 @@ } /* Create the conference object. */ - conference = conference_new(conf_name, xml_cfg, pool); + conference = conference_new(conf_name, &xml_cfg, pool); if (!conference) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Memory Error!\n"); @@ -3481,7 +3759,7 @@ freepool = pool; /* couldn't find the conference, create one */ } else { - conference = conference_new(conf_name, xml_cfg, pool); + conference = conference_new(conf_name, &xml_cfg, pool); if (!conference) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Memory Error!\n"); @@ -3568,12 +3846,6 @@ } } - /* Release the config registry handle */ - if (xml_cfg.cxml) { - switch_xml_free(xml_cfg.cxml); - xml_cfg.cxml = NULL; - } - /* if we're using "bridge:" make an outbound call and bridge it in */ if (!switch_strlen_zero(bridgeto) && strcasecmp(bridgeto, "none")) { if (conference_outcall(conference, session, bridgeto, 60, NULL, NULL, NULL) != SWITCH_STATUS_SUCCESS) { @@ -3875,258 +4147,8 @@ /*.chat_interface */ &conference_chat_interface }; -#ifdef OPTION_IVR_MENU_SUPPORT -static switch_ivr_action_t conference_caller_control_menu_handler(switch_ivr_menu_t *menu, char *param, char *buf, size_t buflen, void *obj) -{ - switch_ivr_action_t action = SWITCH_IVR_ACTION_NOOP; - - if (!switch_strlen_zero(param)) { - if (obj != NULL) { - int i, found; - char *action_name = strdup(param); - - if (action_name != NULL) { - char *sep = (action_name != NULL ? strchr(action_name, ' ') : NULL); - - /* split the action from any parameters */ - if (sep != NULL) { - *sep = '\0'; - } - - /* find and execute the caller control handler */ - for(i = 0, found = 0; !found && i<CCFNTBL_QTY; i++) { - found = (ccfntbl[i].action != CALLER_CONTROL_MENU && strcasecmp(ccfntbl[i].key, action_name) == 0); - if (found) { - if (obj != NULL) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "invoking caller control menu action '%s'\n", ccfntbl[i].key); - ccfntbl[i].handler((conference_member_t *)obj, (sep != NULL ? sep+1 : NULL)); - if (ccfntbl[i].action == CALLER_CONTROL_HANGUP) { - action = SWITCH_IVR_ACTION_DIE; - } - } - } - } - - free(action_name); - } - - if (!found) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "unknown caller control menu action '%s'\n", param); - } - } else { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "unable to invoke caller control menu action '%s', NULL member!\n", param); - } - } else { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "NULL or empty param!\n"); - } - - return action; -} - -/* - static switch_status_t ivr_menu_callback_play_file(char *file, uint32_t leadin, void *member) - { - switch_status_t status; - - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "ivr_menu_callback_play_file\n"); - status = conference_member_play_file((conference_member_t *)member, file, leadin); - if (status != SWITCH_STATUS_SUCCESS) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "ivr_menu_callback_play_file ERROR\n"); - } - - return status; - } - - static switch_status_t ivr_menu_callback_say(char *file, uint32_t leadin, void *member) - { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "ivr_menu_callback_say\n"); - return conference_member_say((conference_member_t *)member, file, leadin); - } -*/ - -static switch_status_t conference_caller_control_menu_build(caller_control_menu_ctx_t **ctx, - conference_obj_t *conference, - switch_xml_t menu_group, - char *menu_name) -{ - switch_status_t status = SWITCH_STATUS_FALSE; - switch_xml_t xml_menus; - switch_xml_t xml_menu; - - assert(conference != NULL); - assert(ctx != NULL); - assert(menu_group != NULL); - assert(menu_name != NULL); - assert(xml_menus != NULL); - - xml_menus = switch_xml_child(menu_group, "menus"); - xml_menu = (xml_menus != NULL ? switch_xml_find_child(xml_menus, "menu", "name", menu_name) : NULL); - - - - /* if we found the requested menu in our menu_group */ - if (xml_menu != NULL && xml_menu != NULL) { - *ctx = (caller_control_menu_ctx_t *)switch_core_alloc(conference->pool, sizeof(caller_control_menu_ctx_t)); - - if (*ctx != NULL) { - memset(*ctx, 0, sizeof(caller_control_menu_ctx_t)); - - /* setup an xml parser context, and a menu stack context for the specified menu in our memory pool */ - status = switch_ivr_menu_stack_xml_init(&(*ctx)->xml_ctx, conference->pool); - if (status == SWITCH_STATUS_SUCCESS) { - (*ctx)->name = switch_core_strdup(conference->pool, menu_name); - - /* add our xml menu handler to the xml stack parser */ - status = switch_ivr_menu_stack_xml_add_custom((*ctx)->xml_ctx, "control", &conference_caller_control_menu_handler); - if (status != SWITCH_STATUS_SUCCESS) - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "unable to add custom xml handler\n"); - - /* parse the xml stack to build the menu stack */ - status = switch_ivr_menu_stack_xml_build((*ctx)->xml_ctx, &(*ctx)->menu_stack, xml_menus, xml_menu, conference->timer_name); - if (status != SWITCH_STATUS_SUCCESS) - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "unable to build xml menu stack\n"); - - /* - // instruct ivr menu to use our file play and tts routines - status = switch_ivr_menu_set_fileplay_callback((*ctx)->menu_stack, &ivr_menu_callback_play_file); - if (status != SWITCH_STATUS_SUCCESS) - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "unable to set file play calback\n"); - status = switch_ivr_menu_set_tts_callback((*ctx)->menu_stack, &ivr_menu_callback_say); - if (status != SWITCH_STATUS_SUCCESS) - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "unable to set tts calback\n"); - */ - } else { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "unable to init xml menu context\n"); - } - if (status != SWITCH_STATUS_SUCCESS) - *ctx = NULL; - } - } else { - if (xml_menus == NULL) - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "caller control menu unable to find xml menus\n"); - if (xml_menu == NULL) - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "caller control menu unable to find xml menu '%s'\n", menu_name); - } - - return status; -} -#endif - -static switch_status_t conf_default_controls(conference_obj_t *conference) -{ - switch_status_t status = SWITCH_STATUS_FALSE; - uint32_t i; - caller_control_action_t *action; - - assert(conference != NULL); - - for(i = 0, status = SWITCH_STATUS_SUCCESS; status == SWITCH_STATUS_SUCCESS && i<CCFNTBL_QTY; i++) { - if (!switch_strlen_zero(ccfntbl[i].digits)) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Installing default caller control action '%s' bound to '%s'.\n", - ccfntbl[i].key, - ccfntbl[i].digits); - action = (caller_control_action_t *)switch_core_alloc(conference->pool, sizeof(caller_control_action_t)); - if (action != NULL) { - action->fndesc = &ccfntbl[i]; - action->data = NULL; - status = switch_ivr_digit_stream_parser_set_event(conference->dtmf_parser, ccfntbl[i].digits, action); - } else { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "unable to alloc memory for caller control binding '%s' to '%s'\n", - ccfntbl[i].key, ccfntbl[i].digits); - status = SWITCH_STATUS_MEMERR; - } - } - } - - - return status; -} - -static switch_status_t conference_new_install_caller_controls_custom(conference_obj_t *conference, switch_xml_t xml_controls, switch_xml_t xml_menus) -{ - switch_status_t status = SWITCH_STATUS_FALSE; - switch_xml_t xml_kvp; - - assert(conference != NULL); - assert(xml_controls != NULL); - - /* parse the controls tree for caller control digit strings */ - for (xml_kvp = switch_xml_child(xml_controls, "control"); xml_kvp; xml_kvp = xml_kvp->next) { - char *key = (char *) switch_xml_attr(xml_kvp, "action"); - char *val = (char *) switch_xml_attr(xml_kvp, "digits"); - char *data = (char *)switch_xml_attr_soft(xml_kvp, "data"); - - if (!switch_strlen_zero(key) && !switch_strlen_zero(val)) { - uint32_t i; - - /* scan through all of the valid actions, and if found, */ - /* set the new caller control action digit string, then */ - /* stop scanning the table, and go to the next xml kvp. */ - for(i = 0, status = SWITCH_STATUS_NOOP; i<CCFNTBL_QTY && status == SWITCH_STATUS_NOOP; i++) { - - if (strcasecmp(ccfntbl[i].key, key) == 0) { - status = SWITCH_STATUS_SUCCESS; -#ifdef OPTION_IVR_MENU_SUPPORT - if (xml_menus != NULL && ccfntbl[i].action == CALLER_CONTROL_MENU) { - char *menu_group_name = strdup(data); - char *menu_name = (menu_group_name != NULL ? strchr(menu_group_name, '/') : NULL); - - /* format: "menu_group_name/menu_name" */ - /* separate the menu name from the menu group */ - if (menu_name != NULL) { - *(menu_name++) = '\0'; - } - /* if there is a menu name, build the menu */ - if (menu_name != NULL) { - caller_control_menu_ctx_t *menu_ctx = NULL; - switch_xml_t menu_group = switch_xml_find_child(xml_menus, "group", "name", menu_group_name); - - status = conference_caller_control_menu_build(&menu_ctx, conference, menu_group, menu_name); - data = (char *)menu_ctx; - } else { - status = SWITCH_STATUS_FALSE; - } - - if (status != SWITCH_STATUS_SUCCESS) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "unable to build menu '%s' bound to '%s'\n", data, val); - } - - /* clean up */ - if (menu_group_name != NULL) { - free(menu_group_name); - } - } -#endif - - if (status == SWITCH_STATUS_SUCCESS) { - caller_control_action_t *action; - - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Installing caller control action '%s' bound to '%s'.\n", key, val); - action = (caller_control_action_t *)switch_core_alloc(conference->pool, sizeof(caller_control_action_t)); - if (action != NULL) { - action->fndesc = &ccfntbl[i]; - action->data = (void *)data; - status = switch_ivr_digit_stream_parser_set_event(conference->dtmf_parser, val, action); - } else { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "unable to alloc memory for caller control binding '%s' to '%s'\n", ccfntbl[i].key, ccfntbl[i].digits); - status = SWITCH_STATUS_MEMERR; - } - } - } - } - if (status == SWITCH_STATUS_NOOP) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Invalid caller control action name '%s'.\n", key); - } - } else { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Invalid caller control config entry pair action = '%s' digits = '%s'\n", key, val); - } - } - - return status; -} - /* create a new conferene with a specific profile */ -static conference_obj_t *conference_new(char *name, conf_xml_cfg_t cfg, switch_memory_pool_t *pool) +static conference_obj_t *conference_new(char *name, conf_xml_cfg_t *xml_cfg, switch_memory_pool_t *pool) { conference_obj_t *conference; switch_xml_t xml_kvp; @@ -4162,7 +4184,7 @@ } /* parse the profile tree for param values */ - for (xml_kvp = switch_xml_child(cfg.profile, "param"); xml_kvp; xml_kvp = xml_kvp->next) { + for (xml_kvp = switch_xml_child(xml_cfg->profile, "param"); xml_kvp; xml_kvp = xml_kvp->next) { char *var = (char *) switch_xml_attr_soft(xml_kvp, "name"); char *val = (char *) switch_xml_attr_soft(xml_kvp, "value"); char buf[128] = ""; @@ -4335,6 +4357,10 @@ conference->energy_level = atoi(energy_level); } + if (!switch_strlen_zero(caller_controls)) { + conference->caller_controls = switch_core_strdup(conference->pool, caller_controls); + } + conference->name = switch_core_strdup(conference->pool, name); if (domain) { conference->domain = switch_core_strdup(conference->pool, domain); @@ -4343,31 +4369,9 @@ } conference->rate = rate; conference->interval = interval; - conference->dtmf_parser = NULL; - - /* caller control configuration chores */ - if (switch_ivr_digit_stream_parser_new(conference->pool, &conference->dtmf_parser) == SWITCH_STATUS_SUCCESS) { - /* if no controls, or default controls specified, install default */ - if (caller_controls == NULL || *caller_controls == '\0' || strcasecmp(caller_controls, "default") == 0) { - status = conf_default_controls(conference); - } else if (strcasecmp(caller_controls, "none") != 0) { - /* try to build caller control if the group has been specified and != "none" */ - switch_xml_t xml_controls = switch_xml_find_child(cfg.controls, "group", "name", caller_controls); -#ifdef OPTION_IVR_MENU_SUPPORT - status = conference_new_install_caller_controls_custom(conference, xml_controls, cfg.menus); -#else - status = conference_new_install_caller_controls_custom(conference, xml_controls, NULL); -#endif - if (status != SWITCH_STATUS_SUCCESS) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Unable to install caller controls group '%s'\n", caller_controls); - } - } else { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "no caller controls intalled.\n"); - } - } else { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Unable to allocate caller control digit parser.\n"); - } + /* copy the xml config sections to the new conference */ + memcpy(&conference->xml_cfg,xml_cfg,sizeof(conf_xml_cfg_t)); /* Activate the conference mutex for exclusivity */ switch_mutex_init(&conference->mutex, SWITCH_MUTEX_NESTED, conference->pool);