[Freeswitch-svn] [commit] r3341 - in freeswitch/trunk: . src src/include
Freeswitch SVN
mikej at freeswitch.org
Mon Nov 13 11:29:17 EST 2006
Author: mikej
Date: Mon Nov 13 11:29:16 2006
New Revision: 3341
Modified:
freeswitch/trunk/AUTHORS
freeswitch/trunk/src/include/switch_ivr.h
freeswitch/trunk/src/include/switch_types.h
freeswitch/trunk/src/switch_ivr.c
Log:
add switch_ivr_digit_stream functions and switch_ivr_build_xml_menu_stack to switch ivr, merged from knhor branch. thanks neal!
Modified: freeswitch/trunk/AUTHORS
==============================================================================
--- freeswitch/trunk/AUTHORS (original)
+++ freeswitch/trunk/AUTHORS Mon Nov 13 11:29:16 2006
@@ -26,9 +26,9 @@
Yossi Neiman of Cartis Solutions, Inc. <freeswitch AT cartissolutions.com> - implementation of mod_cdr (perldd, mysql, csv)
Stefan Knoblich - Various patches and support. Thanks.
Justin Unger - <justinunger at gmail dot com> Lots of help with patches and SIP testing. Thanks!
- Paul D. Tinsley - Various patches and support. <pdt at jackhammer.org>
+ Paul D. Tinsley - Various patches and support. <pdt at jackhammer.org>
Ken Rice of Asteria Solutions Group, INC <ken AT asteriasgi.com> - xmlcdr, sofia improvements, load testing.
- Neal Horman <neal at wanlink dot com> - conference improvements and other tweaks.
+ Neal Horman <neal at wanlink dot com> - conference improvements, switch_ivr menu additions and other tweaks.
A big THANK YOU goes to:
Modified: freeswitch/trunk/src/include/switch_ivr.h
==============================================================================
--- freeswitch/trunk/src/include/switch_ivr.h (original)
+++ freeswitch/trunk/src/include/switch_ivr.h Mon Nov 13 11:29:16 2006
@@ -24,6 +24,7 @@
* Contributor(s):
*
* Anthony Minessale II <anthmct at yahoo.com>
+ * Neal Horman <neal at wanlink dot com>
*
*
* switch_ivr.h -- IVR Library
@@ -402,6 +403,63 @@
*/
SWITCH_DECLARE(switch_status_t) switch_ivr_transfer_variable(switch_core_session_t *sessa, switch_core_session_t *sessb, char *var);
+
+struct switch_ivr_digit_stream_parser;
+typedef struct switch_ivr_digit_stream_parser switch_ivr_digit_stream_parser_t;
+/*!
+ \brief Create a digit stream parser object
+ \param pool the pool to use for the new hash
+ \param parser a pointer to the object pointer
+ \return SWITCH_STATUS_SUCCESS if all is well
+*/
+SWITCH_DECLARE(switch_status_t) switch_ivr_digit_stream_parser_new(switch_memory_pool_t *pool, switch_ivr_digit_stream_parser_t **parser);
+
+/*!
+ \brief Destroy a digit stream parser object
+ \param parser a pointer to the object pointer
+ \return SWITCH_STATUS_SUCCESS if all is well
+*/
+SWITCH_DECLARE(switch_status_t) switch_ivr_digit_stream_parser_destroy(switch_ivr_digit_stream_parser_t **parser);
+
+/*!
+ \brief Set a digit string to action mapping
+ \param parser a pointer to the parser object created by switch_ivr_digit_stream_parser_new
+ \param digits a string of digits to associate with an action
+ \param data consumer data attached to this digit string
+ \return SWITCH_STATUS_SUCCESS if all is well
+*/
+SWITCH_DECLARE(switch_status_t) switch_ivr_digit_stream_parser_set_event(switch_ivr_digit_stream_parser_t *parser, char *digits, void *data);
+
+/*!
+ \brief Delete a string to action mapping
+ \param parser a pointer to the parser object created by switch_ivr_digit_stream_parser_new
+ \param digits the digit string to be removed from the map
+ \return SWITCH_STATUS_SUCCESS if all is well
+*/
+SWITCH_DECLARE(switch_status_t) switch_ivr_digit_stream_parser_del_event(switch_ivr_digit_stream_parser_t *parser, char *digits);
+
+/*!
+ \brief Create a digit stream parser object
+ \param parser a pointer to the parser object created by switch_ivr_digit_stream_parser_new
+ \param digit a digit to collect and test against the map of digit strings
+ \return NULL if no match found or consumer data that was associated with a given digit string when matched
+*/
+SWITCH_DECLARE(void *) switch_ivr_digit_stream_parser_feed(switch_ivr_digit_stream_parser_t *parser, char digit);
+
+/*!
+ \brief Reset the collected digit stream to nothing
+ \param parser a pointer to the parser object created by switch_ivr_digit_stream_parser_new
+ \return SWITCH_STATUS_SUCCESS if all is well
+*/
+SWITCH_DECLARE(switch_status_t) switch_ivr_digit_stream_parser_reset(switch_ivr_digit_stream_parser_t *parser);
+
+/*!
+ \brief Set a digit string terminator
+ \param parser a pointer to the parser object created by switch_ivr_digit_stream_parser_new
+ \return SWITCH_STATUS_SUCCESS if all is well
+*/
+SWITCH_DECLARE(switch_status_t) switch_ivr_digit_stream_parser_set_terminator(switch_ivr_digit_stream_parser_t *parser, char digit);
+
/** @} */
/**
@@ -442,10 +500,12 @@
*\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 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 pool memory pool (NULL to create one)
- *\return SWUTCH_STATUS_SUCCESS if the menu was created
+ *\return SWITCH_STATUS_SUCCESS if the menu was created
*/
SWITCH_DECLARE(switch_status_t) switch_ivr_menu_init(switch_ivr_menu_t **new_menu,
switch_ivr_menu_t *main,
@@ -500,6 +560,18 @@
*/
SWITCH_DECLARE(switch_status_t) switch_ivr_menu_free_stack(switch_ivr_menu_t *stack);
+/*!
+ *\brief build a menu stack from an xml source
+ *\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 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_END_EXTERN_C
Modified: freeswitch/trunk/src/include/switch_types.h
==============================================================================
--- freeswitch/trunk/src/include/switch_types.h (original)
+++ freeswitch/trunk/src/include/switch_types.h Mon Nov 13 11:29:16 2006
@@ -905,6 +905,8 @@
struct switch_core_session;
/*! \brief An audio bug */
struct switch_media_bug;
+/*! \brief A digit stream parser object */
+struct switch_ivr_digit_stream_parser;
SWITCH_END_EXTERN_C
Modified: freeswitch/trunk/src/switch_ivr.c
==============================================================================
--- freeswitch/trunk/src/switch_ivr.c (original)
+++ freeswitch/trunk/src/switch_ivr.c Mon Nov 13 11:29:16 2006
@@ -25,6 +25,7 @@
*
* Anthony Minessale II <anthmct at yahoo.com>
* Paul D. Tinsley <pdt at jackhammer.org>
+ * Neal Horman <neal at wanlink dot com>
*
* switch_ivr_api.c -- IVR Library
*
@@ -3254,7 +3255,169 @@
return SWITCH_STATUS_SUCCESS;
}
+struct switch_ivr_digit_stream_parser {
+ int pool_auto_created;
+ switch_memory_pool_t *pool;
+ switch_hash_t *hash;
+ char *digits;
+ char terminator;
+ switch_size_t maxlen;
+};
+SWITCH_DECLARE(switch_status_t) switch_ivr_digit_stream_parser_new(switch_memory_pool_t *pool, switch_ivr_digit_stream_parser_t **parser)
+{ switch_status_t status = SWITCH_STATUS_FALSE;
+
+ if(parser != NULL) {
+ int pool_auto_created = 0;
+
+ // if the caller didn't provide a pool, make one
+ if (pool == NULL) {
+ switch_core_new_memory_pool(&pool);
+ if (pool != NULL) {
+ pool_auto_created = 1;
+ }
+ }
+
+ // if we have a pool, make a parser object
+ if (pool != NULL) {
+ *parser = (switch_ivr_digit_stream_parser_t *)switch_core_alloc(pool,sizeof(switch_ivr_digit_stream_parser_t));
+ }
+
+ // if we have parser object, initialize it for the caller
+ if (*parser != NULL) {
+ memset(*parser,0,sizeof(switch_ivr_digit_stream_parser_t));
+ (*parser)->pool_auto_created = pool_auto_created;
+ (*parser)->pool = pool;
+ 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 (pool != NULL && pool_auto_created) {
+ switch_core_destroy_memory_pool(&pool);
+ }
+ }
+ }
+
+ return status;
+}
+
+SWITCH_DECLARE(switch_status_t) switch_ivr_digit_stream_parser_destroy(switch_ivr_digit_stream_parser_t **parser)
+{ switch_status_t status = SWITCH_STATUS_FALSE;
+
+ if (parser != NULL && *parser != NULL) {
+ if ((*parser)->hash != NULL) {
+ switch_core_hash_destroy((*parser)->hash);
+ (*parser)->hash = NULL;
+ }
+ // free the memory pool if we created it
+ if ((*parser)->pool_auto_created && (*parser)->pool != NULL) {
+ status = switch_core_destroy_memory_pool(&(*parser)->pool);
+ }
+ // clean up for the caller
+ *parser = NULL;
+ }
+
+ return status;
+}
+
+SWITCH_DECLARE(switch_status_t) switch_ivr_digit_stream_parser_set_event(switch_ivr_digit_stream_parser_t *parser, char *digits, void *data)
+{ 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_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "unable to add hash for '%s'\n",digits);
+ }
+
+ return status;
+}
+
+SWITCH_DECLARE(switch_status_t) switch_ivr_digit_stream_parser_del_event(switch_ivr_digit_stream_parser_t *parser, char *digits)
+{ switch_status_t status = SWITCH_STATUS_FALSE;
+
+ if (parser != NULL && digits != NULL && *digits) {
+ status = switch_core_hash_delete(parser->hash,digits);
+ }
+
+ if (status != SWITCH_STATUS_SUCCESS) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "unable to del hash for '%s'\n",digits);
+ }
+
+ return status;
+}
+
+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 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;
+
+ while (*src) {
+ *(dst++) = *(src++);
+ }
+ *dst = digit;
+ } else {
+ parser->digits = realloc(parser->digits,len+2);
+ *(parser->digits+(len++)) = digit;
+ *(parser->digits+len) = '\0';
+ }
+ }
+
+ // if we have digits to test
+ if (len) {
+ result = switch_core_hash_find(parser->hash,parser->digits);
+ // if we matched the digit string, or this digit is the terminator
+ // reset the collected digits for next digit string
+ if (result != NULL || parser->terminator == digit) {
+ free(parser->digits);
+ parser->digits = NULL;
+ }
+ }
+ }
+
+ return result;
+}
+
+SWITCH_DECLARE(switch_status_t) switch_ivr_digit_stream_parser_reset(switch_ivr_digit_stream_parser_t *parser)
+{ switch_status_t status = SWITCH_STATUS_FALSE;
+
+ if (parser != NULL && parser->digits != NULL) {
+ free(parser->digits);
+ parser->digits = NULL;
+ status = SWITCH_STATUS_SUCCESS;
+ }
+
+ return status;
+}
+
+SWITCH_DECLARE(switch_status_t) switch_ivr_digit_stream_parser_set_terminator(switch_ivr_digit_stream_parser_t *parser, char digit)
+{ switch_status_t status = SWITCH_STATUS_FALSE;
+
+ if (parser != NULL) {
+ parser->terminator = digit;
+ parser->maxlen = 0;
+ status = SWITCH_STATUS_SUCCESS;
+ }
+
+ return status;
+}
+
struct switch_ivr_menu_action;
struct switch_ivr_menu {
@@ -3533,15 +3696,16 @@
if (!strcmp(menu->buf, ap->bind)) {
char *membuf;
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "IVR menu %s matched %s\n", menu->name, menu->buf);
match++;
errs = 0;
if (ap->function) {
todo = ap->function(menu, 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;
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "IVR action on menu '%s' matched '%s' param '%s'\n", menu->name, menu->buf,aptr);
}
switch(todo) {
@@ -3566,6 +3730,7 @@
break;
case SWITCH_IVR_ACTION_EXECAPP: {
const switch_application_interface_t *application_interface;
+
if ((membuf = strdup(aptr))) {
char *app_name = membuf;
char *app_arg = strchr(app_name, ' ');
@@ -3630,3 +3795,91 @@
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)
+{
+ 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;
+
+ 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 {
+ char *name;
+ switch_ivr_action_t action;
+ } iam [] = {
+ {"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-back", SWITCH_IVR_ACTION_BACK},
+ {"menu-top", SWITCH_IVR_ACTION_TOMAIN},
+ {"call-transfer", SWITCH_IVR_ACTION_TRANSFER},
+ };
+ int iam_qty = sizeof(iam)/sizeof(iam[0]);
+
+ // set the menu stack for the caller
+ if (*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 (!switch_strlen_zero(action) && !switch_strlen_zero(digits)) {
+ int i,found;
+
+ for(i=0,found=0; i<iam_qty && !found; i++) {
+ found = (strcasecmp(iam[i].name,action) == 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);
+ }
+ }
+ // finally bind the menu entry
+ if (status == SWITCH_STATUS_SUCCESS) {
+ status = switch_ivr_menu_bind_action(menu, iam[i].action, param, digits);
+ }
+ }
+ } 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);
+ }
+
+ return status;
+}
More information about the Freeswitch-svn
mailing list