[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