[Freeswitch-branches] [commit] r3439 - in freeswitch/branches/knhor/trunk/src: . include

Freeswitch SVN knhor at freeswitch.org
Wed Nov 22 20:37:56 EST 2006


Author: knhor
Date: Wed Nov 22 20:37:55 2006
New Revision: 3439

Modified:
   freeswitch/branches/knhor/trunk/src/include/switch_ivr.h
   freeswitch/branches/knhor/trunk/src/switch_ivr.c

Log:
rename switch_ivr_find_menu -> switch_ivr_menu_find
rename switch_ivr_menu_free_stack -> switch_ivr_menu_stack_free
add timer_name parameter to play_or_say and switch_ivr_menu_stack_xml_build
add arg parameter to switch_ivr_menu_bind_function
add switch_ivr_menu_stack_xml_add
add switch_ivr_menu_stack_xml_init
add switch_ivr_menu_stack_xml_add_custom
add exit-sound to ivr_menu


Modified: freeswitch/branches/knhor/trunk/src/include/switch_ivr.h
==============================================================================
--- freeswitch/branches/knhor/trunk/src/include/switch_ivr.h	(original)
+++ freeswitch/branches/knhor/trunk/src/include/switch_ivr.h	Wed Nov 22 20:37:55 2006
@@ -479,15 +479,16 @@
 typedef enum {
 	SWITCH_IVR_ACTION_DIE, 		/* Exit the menu.                  */
 	SWITCH_IVR_ACTION_EXECMENU,	/* Goto another menu in the stack. */
-	SWITCH_IVR_ACTION_EXECAPP,		/* Execute an application.         */
+	SWITCH_IVR_ACTION_EXECAPP,	/* Execute an application.         */
 	SWITCH_IVR_ACTION_PLAYSOUND,	/* Play a sound.                   */
-	SWITCH_IVR_ACTION_SAYTEXT,	/* say text.                   */
+	SWITCH_IVR_ACTION_SAYTEXT,	/* say text.                       */
 	SWITCH_IVR_ACTION_BACK,		/* Go back 1 menu.                 */
-	SWITCH_IVR_ACTION_TOMAIN,		/* Go back to the top level menu.  */
+	SWITCH_IVR_ACTION_TOMAIN,	/* Go back to the top level menu.  */
 	SWITCH_IVR_ACTION_TRANSFER,	/* Transfer caller to another ext. */
+	SWITCH_IVR_ACTION_NOOP,		/* No operation                    */
 } switch_ivr_action_t;
 struct switch_ivr_menu;
-typedef switch_ivr_action_t switch_ivr_menu_action_function_t(struct switch_ivr_menu *, char *, size_t, void *);
+typedef switch_ivr_action_t switch_ivr_menu_action_function_t(struct switch_ivr_menu *, char *, char *, size_t, void *);
 typedef struct switch_ivr_menu switch_ivr_menu_t;
 typedef struct switch_ivr_menu_action switch_ivr_menu_action_t;
 /******************************************************************************************************/
@@ -499,11 +500,13 @@
  *\param name A pointer to the name of this menu.
  *\param greeting_sound Optional pointer to a main sound (press 1 for this 2 for that).
  *\param short_greeting_sound Optional pointer to a shorter main sound for subsequent loops.
+ *\param exit_sound Optional pointer to a sound to play upon exiting the menu
  *\param invalid_sound Optional pointer to a sound to play after invalid input.
  *\param tts_engine Text To Speech engine name
  *\param tts_voice Text To Speech engine voice name
  *\param timeout A number of milliseconds to pause before looping.
  *\param max_failures Maximum number of failures to withstand before hangingup This resets everytime you enter the menu.
+ *\param timer_name A pointer to a timer name
  *\param pool memory pool (NULL to create one)
  *\return SWITCH_STATUS_SUCCESS if the menu was created
  */
@@ -512,11 +515,13 @@
 													 char *name, 
 													 char *greeting_sound, 
 													 char *short_greeting_sound,
+													 char *exit_sound,
 													 char *invalid_sound, 
 													 char *tts_engine,
 													 char *tts_voice,
 													 int timeout,
 													 int max_failures, 
+													 char *timer_name,
 													 switch_memory_pool_t *pool);
 
 /*!
@@ -534,13 +539,14 @@
  *\brief Bind a keystroke to a callback function.
  *\param menu The menu obj you wish to bind to.
  *\param function The function to call [int proto(struct switch_ivr_menu *, char *, size_t, void *)]
+ *\param arg Optional (sometimes necessary) string arguement.
  *\param bind KeyStrokes to bind the action to.
  *\note The function is passed a buffer to fill in with any required argument data.
  *\note The function is also passed an optional void pointer to an object set upon menu execution. (think threads)
  *\note The function returns an switch_ivr_action_t enum of what you want to do. and looks to your buffer for args.
  *\return SWUTCH_STATUS_SUCCESS if the function was binded
  */
-SWITCH_DECLARE(switch_status_t) switch_ivr_menu_bind_function(switch_ivr_menu_t *menu, switch_ivr_menu_action_function_t *function, char *bind);
+SWITCH_DECLARE(switch_status_t) switch_ivr_menu_bind_function(switch_ivr_menu_t *menu, switch_ivr_menu_action_function_t *function, char *arg, char *bind);
 
 
 /*!
@@ -558,20 +564,31 @@
  *\param stack The top level menu you wish to destroy.
  *\return SWITCH_STATUS_SUCCESS if the object was a top level menu and it was freed
  */
-SWITCH_DECLARE(switch_status_t) switch_ivr_menu_free_stack(switch_ivr_menu_t *stack);
+SWITCH_DECLARE(switch_status_t) switch_ivr_menu_stack_free(switch_ivr_menu_t *stack);
 
+
+struct switch_ivr_menu_xml_ctx;
+typedef struct switch_ivr_menu_xml_ctx switch_ivr_menu_xml_ctx_t;
 /*!
- *\brief build a menu stack from an xml source
+ *\brief Build a menu stack from an xml source
  *\param 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_DECLARE(switch_status_t) switch_ivr_menu_stack_xml_build(switch_ivr_menu_xml_ctx_t *xml_menu_ctx,
+										switch_ivr_menu_t **menu_stack,
 										switch_xml_t xml_menus,
 										switch_xml_t xml_menu,
-										switch_memory_pool_t *pool);
+										char *timer_name);
+
+SWITCH_DECLARE(switch_status_t) switch_ivr_menu_stack_xml_add_custom(switch_ivr_menu_xml_ctx_t *xml_menu_ctx,
+										char *name,
+										switch_ivr_menu_action_function_t *function);
+
+SWITCH_DECLARE(switch_status_t) switch_ivr_menu_stack_xml_init(switch_ivr_menu_xml_ctx_t **xml_menu_ctx, switch_memory_pool_t *pool);
+
 /** @} */
 
 SWITCH_END_EXTERN_C

Modified: freeswitch/branches/knhor/trunk/src/switch_ivr.c
==============================================================================
--- freeswitch/branches/knhor/trunk/src/switch_ivr.c	(original)
+++ freeswitch/branches/knhor/trunk/src/switch_ivr.c	Wed Nov 22 20:37:55 2006
@@ -186,7 +186,7 @@
 	uint32_t elapsed;
 
 	channel = switch_core_session_get_channel(session);
-    assert(channel != NULL);
+	assert(channel != NULL);
 
 	if (!input_callback) {
 		return SWITCH_STATUS_GENERR;
@@ -1005,6 +1005,7 @@
 		switch_channel_set_variable(channel, "RECORD_DATE", (char *)p);
 	}
 	
+	switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "timer name '%s'\n",timer_name);
 	switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, 
 					  "OPEN FILE %s %uhz %u channels\n"
 					  "TITLE=%s\n"
@@ -3364,7 +3365,7 @@
 		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) {
+			if ( len > 0 && parser->maxlen != 0 && len >= parser->maxlen) {
 				char *src = parser->digits + 1;
 				char *dst = parser->digits;
 
@@ -3425,10 +3426,12 @@
 	char *greeting_sound;
 	char *short_greeting_sound;
 	char *invalid_sound;
+	char *exit_sound;
 	char *tts_engine;
 	char *tts_voice;
 	char *buf;
 	char *ptr;
+	char *timer_name;
 	int max_failures;
 	int timeout;
 	uint32_t inlen;
@@ -3438,7 +3441,6 @@
 	switch_memory_pool_t *pool;
 };
 
-
 struct switch_ivr_menu_action {
 	switch_ivr_menu_action_function_t *function;
 	switch_ivr_action_t ivr_action;
@@ -3447,7 +3449,7 @@
 	struct switch_ivr_menu_action *next;
 };
 
-static switch_ivr_menu_t *switch_ivr_find_menu(switch_ivr_menu_t *stack, char *name) {
+static switch_ivr_menu_t *switch_ivr_menu_find(switch_ivr_menu_t *stack, char *name) {
 	switch_ivr_menu_t *ret;
 	for(ret = stack; ret ; ret = ret->next) {
 		if (!name || !strcmp(ret->name, name))
@@ -3456,8 +3458,7 @@
 	return ret;
 }
 
-
-static void switch_ivr_menu_stack(switch_ivr_menu_t **top, switch_ivr_menu_t *bottom) 
+static void switch_ivr_menu_stack_add(switch_ivr_menu_t **top, switch_ivr_menu_t *bottom) 
 {
 	switch_ivr_menu_t *ptr;
 
@@ -3477,10 +3478,12 @@
 													 char *greeting_sound, 
 													 char *short_greeting_sound,
 													 char *invalid_sound, 
+													 char *exit_sound,
 													 char *tts_engine,
 													 char *tts_voice,
 													 int timeout,
 													 int max_failures, 
+													 char *timer_name,
 													 switch_memory_pool_t *pool)
 {
 	switch_ivr_menu_t *menu;
@@ -3504,30 +3507,38 @@
 
 	menu->pool = pool;
 
-	if (name) {
+	if (!switch_strlen_zero(name)) {
 		menu->name = switch_core_strdup(menu->pool, name);
 	}
 
-	if (greeting_sound) {
+	if (!switch_strlen_zero(greeting_sound)) {
 		menu->greeting_sound = switch_core_strdup(menu->pool, greeting_sound);
 	}
 
-	if (short_greeting_sound) {
+	if (!switch_strlen_zero(short_greeting_sound)) {
 		menu->short_greeting_sound = switch_core_strdup(menu->pool, short_greeting_sound);
 	}
 
-	if (invalid_sound) {
+	if (!switch_strlen_zero(invalid_sound)) {
 		menu->invalid_sound = switch_core_strdup(menu->pool, invalid_sound);
 	}
 
-	if (tts_engine) {
+	if (!switch_strlen_zero(exit_sound)) {
+		menu->exit_sound = switch_core_strdup(menu->pool, exit_sound);
+	}
+
+	if (!switch_strlen_zero(tts_engine)) {
 		menu->tts_engine = switch_core_strdup(menu->pool, tts_engine);
 	}
 
-	if (tts_voice) {
+	if (!switch_strlen_zero(tts_voice)) {
 		menu->tts_voice = switch_core_strdup(menu->pool, tts_voice);
 	}
 
+	if (!switch_strlen_zero(timer_name)) {
+		menu->timer_name = switch_core_strdup(menu->pool, timer_name);
+	}
+
 	menu->max_failures = max_failures;
 
 	menu->timeout = timeout;
@@ -3543,7 +3554,7 @@
 	}
 
 	if (main) {
-		switch_ivr_menu_stack(&main, menu);
+		switch_ivr_menu_stack_add(&main, menu);
 	} else {
 		menu->flags |= SWITCH_IVR_MENU_FLAG_STACK;
 	}
@@ -3558,6 +3569,7 @@
 {
 	switch_ivr_menu_action_t *action;
 	uint32_t len;
+
 	if ((action = switch_core_alloc(menu->pool, sizeof(*action)))) {
 		action->bind = switch_core_strdup(menu->pool, bind);
 		action->next = menu->actions;
@@ -3575,15 +3587,20 @@
 }
 
 
-SWITCH_DECLARE(switch_status_t) switch_ivr_menu_bind_function(switch_ivr_menu_t *menu, switch_ivr_menu_action_function_t *function, char *bind)
+SWITCH_DECLARE(switch_status_t) switch_ivr_menu_bind_function(switch_ivr_menu_t *menu, switch_ivr_menu_action_function_t *function, char *arg, char *bind)
 {
 	switch_ivr_menu_action_t *action;
+	uint32_t len;
 
-
 	if ((action = switch_core_alloc(menu->pool, sizeof(*action)))) {
 		action->bind = bind;
-		action->function = function;
 		action->next = menu->actions;
+		action->arg = switch_core_strdup(menu->pool, arg);
+		len = (uint32_t)strlen(action->bind);
+		if (len > menu->inlen) {
+			menu->inlen = len;
+		}
+		action->function = function;
 		menu->actions = action;
 		return SWITCH_STATUS_SUCCESS;
 	}
@@ -3591,57 +3608,60 @@
 	return SWITCH_STATUS_MEMERR;
 }
 
-SWITCH_DECLARE(switch_status_t) switch_ivr_menu_free_stack(switch_ivr_menu_t *stack) 
+SWITCH_DECLARE(switch_status_t) switch_ivr_menu_stack_free(switch_ivr_menu_t *stack) 
 {
-	switch_memory_pool_t *pool;
+	switch_status_t status = SWITCH_STATUS_FALSE;
 
-	if (!switch_test_flag(stack, SWITCH_IVR_MENU_FLAG_STACK) || switch_test_flag(stack, SWITCH_IVR_MENU_FLAG_FREEPOOL)) {
-		return SWITCH_STATUS_FALSE;
+	if (stack != NULL && stack->pool != NULL) {
+		if (switch_test_flag(stack, SWITCH_IVR_MENU_FLAG_STACK) && switch_test_flag(stack, SWITCH_IVR_MENU_FLAG_FREEPOOL)) {
+			switch_memory_pool_t *pool = stack->pool;
+			status = switch_core_destroy_memory_pool(&pool);
+		} else {
+			status = SWITCH_STATUS_SUCCESS;
+		}
 	}
 
-	pool = stack->pool;
-	switch_core_destroy_memory_pool(&pool);
-	pool = NULL;
-
-	return SWITCH_STATUS_SUCCESS;
-
+	return status;
 }
 
-static switch_status_t play_or_say(switch_core_session_t *session, switch_ivr_menu_t *menu, char *sound, uint32_t need)
+static switch_status_t play_or_say(switch_core_session_t *session, switch_ivr_menu_t *menu, char *sound, uint32_t need, char *timer_name)
 {
 	char terminator;
 	uint32_t len;
 	char *ptr;
-	switch_status_t status = SWITCH_STATUS_SUCCESS;
+	switch_status_t status = SWITCH_STATUS_FALSE;
 
-	memset(menu->buf, 0, menu->inlen);
-	menu->ptr = menu->buf;
+	if (session != NULL && menu != NULL && !switch_strlen_zero(sound)) {
+		memset(menu->buf, 0, menu->inlen);
+		menu->ptr = menu->buf;
 
-	if (!need) {
-		len = 1;
-		ptr = NULL;
-	} else {
-		len = menu->inlen + 1;
-		ptr = menu->ptr;
-	}
+		if (!need) {
+			len = 1;
+			ptr = NULL;
+		} else {
+			len = menu->inlen + 1;
+			ptr = menu->ptr;
+		}
 
-	if (*sound == '/' || *sound == '\\') {
-		switch_ivr_play_file(session, NULL, sound, NULL, NULL, ptr, len);
-	} else {
-		if (menu->tts_engine && menu->tts_voice) {
-			switch_ivr_speak_text(session, menu->tts_engine, menu->tts_voice, NULL, 0, NULL, sound, ptr, len);
+		if (*sound == '/' || *sound == '\\') {
+			status = switch_ivr_play_file(session, NULL, sound, timer_name, NULL, ptr, need ? 1 : 0);
+		} else {
+			if (menu->tts_engine && menu->tts_voice) {
+				status = switch_ivr_speak_text(session, menu->tts_engine, menu->tts_voice, NULL, 0, NULL, sound, ptr, len);
+			}
 		}
-	}
 
-	if (need) {
-		menu->ptr += strlen(menu->buf);
-		if (strlen(menu->buf) < need) {
-			status = switch_ivr_collect_digits_count(session, menu->ptr, menu->inlen - strlen(menu->buf), need, "#", &terminator, menu->timeout);
+		if (need) {
+			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "waiting for %u digits\n",need);
+			menu->ptr += strlen(menu->buf);
+			if (strlen(menu->buf) < need) {
+				status = switch_ivr_collect_digits_count(session, menu->ptr, menu->inlen - strlen(menu->buf), need, "#", &terminator, menu->timeout);
+			}
+			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "digits '%s'\n",menu->buf);
 		}
 	}
 
 	return status;
-	
 }
 
 SWITCH_DECLARE(switch_status_t) switch_ivr_menu_execute(switch_core_session_t *session, switch_ivr_menu_t *stack, char *name, void *obj)
@@ -3655,21 +3675,27 @@
 	switch_channel_t *channel;
 	switch_status_t status = SWITCH_STATUS_SUCCESS;
 
+	if (session == NULL || stack == NULL || switch_strlen_zero(name)) {
+		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid menu context\n");
+		return SWITCH_STATUS_FALSE;
+	}
+
 	channel = switch_core_session_get_channel(session);
 	assert(channel != NULL);
 
-
-	if (!(menu = switch_ivr_find_menu(stack, name))) {
+	if (!(menu = switch_ivr_menu_find(stack, name))) {
 		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid Menu!\n");
-		return -1;
+		return SWITCH_STATUS_FALSE;
 	}
 	
 	if (!(menu->buf = malloc(menu->inlen))) {
 		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "No Memory!\n");
-		return -1;
+		return SWITCH_STATUS_FALSE;
 	}
 	
 	switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Executing IVR menu %s\n", menu->name);
+	switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "stack timer name '%s'\n",stack->timer_name);
+	switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "menu timer name '%s'\n",menu->timer_name);
 
 	for (reps = 0 ; (running && status == SWITCH_STATUS_SUCCESS && errs < menu->max_failures) ; reps++) {
 		if (!switch_channel_ready(channel)) {
@@ -3687,10 +3713,9 @@
 
 		memset(arg, 0, sizeof(arg));
 
+		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "want %d digits\n",menu->inlen);
+		play_or_say(session, menu, greeting_sound, menu->inlen, stack->timer_name);
 
-		play_or_say(session, menu, greeting_sound, menu->inlen);
-		
-
 		if (!switch_strlen_zero(menu->buf)) {
 			for(ap = menu->actions; ap ; ap = ap->next) {
 				if (!strcmp(menu->buf, ap->bind)) {
@@ -3699,9 +3724,9 @@
 					match++;
 					errs = 0;
 					if (ap->function) {
-						todo = ap->function(menu, arg, sizeof(arg), obj);
+						switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "IVR function on menu '%s' matched '%s' param '%s'\n", menu->name, menu->buf, ap->arg);
+						todo = ap->function(menu, ap->arg, arg, sizeof(arg), obj);
 						aptr = arg;
-						switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "IVR function on menu '%s' matched '%s'\n", menu->name, menu->buf);
 					} else {
 						todo = ap->ivr_action;
 						aptr = ap->arg;
@@ -3713,7 +3738,7 @@
 						status = SWITCH_STATUS_FALSE;
 						break;
 					case SWITCH_IVR_ACTION_PLAYSOUND:
-						status = switch_ivr_play_file(session, NULL, aptr, NULL, NULL, NULL, 0);
+						status = switch_ivr_play_file(session, NULL, aptr, stack->timer_name, NULL, NULL, 0);
 						break;
 					case SWITCH_IVR_ACTION_SAYTEXT:
 						if (menu->tts_engine &&  menu->tts_voice) {
@@ -3758,6 +3783,9 @@
 						switch_set_flag(stack, SWITCH_IVR_MENU_FLAG_FALLTOMAIN);
 						status = SWITCH_STATUS_BREAK;
 						break;
+					case SWITCH_IVR_ACTION_NOOP:
+						status = SWITCH_STATUS_SUCCESS;
+						break;
 					default:
 						switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Invalid TODO!\n");
 						break;
@@ -3766,8 +3794,8 @@
 			}
 
 
-			if (switch_test_flag(menu, SWITCH_IVR_MENU_FLAG_STACK)) { /* top level */ 
-				if (switch_test_flag(stack, SWITCH_IVR_MENU_FLAG_FALLTOMAIN)) { /* catch the fallback and recover */
+			if (switch_test_flag(menu, SWITCH_IVR_MENU_FLAG_STACK)) { // top level
+				if (switch_test_flag(stack, SWITCH_IVR_MENU_FLAG_FALLTOMAIN)) { // catch the fallback and recover
 					switch_clear_flag(stack, SWITCH_IVR_MENU_FLAG_FALLTOMAIN);
 					status = SWITCH_STATUS_SUCCESS;
 					running = 1;
@@ -3776,10 +3804,10 @@
 			}
 		}
 		if (!match) {
-			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "IVR menu %s caught invalid input %s\n", menu->name, menu->buf);
+			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "IVR menu '%s' caught invalid input '%s'\n", menu->name, menu->buf);
 
 			if (menu->invalid_sound) {
-				play_or_say(session, menu, menu->invalid_sound, 0);
+				play_or_say(session, menu, menu->invalid_sound, 0, stack->timer_name);
 			}
 			errs++;
 
@@ -3787,99 +3815,236 @@
 				status = switch_ivr_sleep(session, 1000);
 			}
 		}
-		
 	}
 
+	switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "exit-sound '%s'\n",menu->exit_sound);
+	if (!switch_strlen_zero(menu->exit_sound))
+		status = switch_ivr_play_file(session, NULL, menu->exit_sound, stack->timer_name, NULL, NULL, 0);
+
 	switch_safe_free(menu->buf);
 
 	return status;
 }
 
-SWITCH_DECLARE(switch_status_t) switch_ivr_build_xml_menu_stack(switch_ivr_menu_t **menu_stack,
-										switch_xml_t xml_menus,
-										switch_xml_t xml_menu,
-										switch_memory_pool_t *pool)
+typedef struct switch_ivr_menu_xml_map {
+	char *name;
+	switch_ivr_action_t action;
+	switch_ivr_menu_action_function_t *function;
+	struct switch_ivr_menu_xml_map *next;
+} switch_ivr_menu_xml_map_t;
+
+struct switch_ivr_menu_xml_ctx {
+	switch_memory_pool_t *pool;
+	struct switch_ivr_menu_xml_map *map;
+	int autocreated;
+};
+
+static switch_ivr_menu_xml_map_t *switch_ivr_menu_stack_xml_find(switch_ivr_menu_xml_ctx_t *xml_ctx, char *name)
 {
+	switch_ivr_menu_xml_map_t *map = (xml_ctx != NULL ? xml_ctx->map : NULL);
+	int rc = -1;
+
+	while (map != NULL && (rc = strcasecmp(map->name,name)) != 0) {
+		map =  map->next;
+	}
+
+	return (rc == 0 ? map : NULL);
+}
+
+static switch_status_t switch_ivr_menu_stack_xml_add(switch_ivr_menu_xml_ctx_t *xml_ctx, char*name, int action, switch_ivr_menu_action_function_t *function)
+{
+	switch_status_t status = SWITCH_STATUS_FALSE;
+
+	// if this action/function does not exist yet
+	if (xml_ctx != NULL && name != NULL && xml_ctx->pool != NULL && switch_ivr_menu_stack_xml_find(xml_ctx,name) == NULL) {
+		switch_ivr_menu_xml_map_t *map = switch_core_alloc(xml_ctx->pool,sizeof(switch_ivr_menu_xml_map_t));
+
+		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG,
+			"switch_ivr_menu_stack_xml_add bindng '%s'\n",name);
+		// and we have memory
+		if (map != NULL) {
+			map->name = switch_core_strdup(xml_ctx->pool,name);
+			map->action = action;
+			map->function = function;
+
+			if (map->name != NULL) {
+				// insert map item at top of list
+				map->next = xml_ctx->map;
+				xml_ctx->map = map;
+				status = SWITCH_STATUS_SUCCESS;
+			} else {
+				status = SWITCH_STATUS_MEMERR;
+			}
+		} else {
+			status = SWITCH_STATUS_MEMERR;
+		}
+	}
+
+	return status;
+}
+
+SWITCH_DECLARE(switch_status_t) switch_ivr_menu_stack_xml_init(switch_ivr_menu_xml_ctx_t **xml_menu_ctx, switch_memory_pool_t *pool)
+{
 	switch_status_t status	= SWITCH_STATUS_FALSE;
-	char *menu_name		= (char *)switch_xml_attr_soft(xml_menu,"name");		// if the attr doesn't exist, return ""
-	char *greet_long	= (char *)switch_xml_attr(xml_menu,"greet-long");		// if the attr doesn't exist, return NULL
-	char *greet_short	= (char *)switch_xml_attr(xml_menu,"greet-short");		// if the attr doesn't exist, return NULL
-	char *invalid_sound	= (char *)switch_xml_attr(xml_menu,"invalid-sound");		// if the attr doesn't exist, return NULL
-	char *tts_engine	= (char *)switch_xml_attr(xml_menu,"tts-engine");		// if the attr doesn't exist, return NULL
-	char *tts_voice		= (char *)switch_xml_attr(xml_menu,"tts-voice");		// if the attr doesn't exist, return NULL
-	char *timeout		= (char *)switch_xml_attr_soft(xml_menu,"timeout");		// if the attr doesn't exist, return ""
-	char *max_failures	= (char *)switch_xml_attr_soft(xml_menu,"max-failures");	// if the attr doesn't exist, return ""
-	switch_ivr_menu_t *menu	= NULL;
+	int autocreated = 0;
 
-	status = switch_ivr_menu_init(&menu,
-								*menu_stack,
-								menu_name,
-								greet_long,
-								greet_short,
-								invalid_sound,
-								tts_engine,
-								tts_voice,
-								atoi(timeout)*1000,
-								atoi(max_failures),
-								pool
-								);
-	if (status == SWITCH_STATUS_SUCCESS) {
-		switch_xml_t xml_kvp;
-		struct ivr_action_map {
+	// build a memory pool ?
+	if (pool == NULL) {
+		status = switch_core_new_memory_pool(&pool);
+		autocreated = 1;
+	}
+
+	// allocate the xml context
+	if (xml_menu_ctx != NULL && pool != NULL) {
+		*xml_menu_ctx = switch_core_alloc(pool,sizeof(switch_ivr_menu_xml_ctx_t));
+		if (*xml_menu_ctx != NULL) {
+			(*xml_menu_ctx)->pool = pool;
+			(*xml_menu_ctx)->autocreated = autocreated;
+			(*xml_menu_ctx)->map = NULL;
+			status = SWITCH_STATUS_SUCCESS;
+		} else {
+			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Unable to alloc xml_ctx\n");
+			status = SWITCH_STATUS_FALSE;
+		}
+	}
+
+	// build the standard/default xml menu handler mappings
+	if (status == SWITCH_STATUS_SUCCESS && xml_menu_ctx != NULL && *xml_menu_ctx != NULL) {
+		struct iam_s {
 			char *name;
 			switch_ivr_action_t action;
 		} iam [] = {
-			{"exit",		SWITCH_IVR_ACTION_DIE},
+			{"menu-exit",		SWITCH_IVR_ACTION_DIE},
 			{"menu-sub",		SWITCH_IVR_ACTION_EXECMENU},
-			{"exec-api",		SWITCH_IVR_ACTION_EXECAPP},
-			{"play-sound",		SWITCH_IVR_ACTION_PLAYSOUND},
-			{"say-text",		SWITCH_IVR_ACTION_SAYTEXT},
+			{"menu-exec-api",	SWITCH_IVR_ACTION_EXECAPP},
+			{"menu-play-sound",	SWITCH_IVR_ACTION_PLAYSOUND},
+			{"menu-say-text",	SWITCH_IVR_ACTION_SAYTEXT},
 			{"menu-back",		SWITCH_IVR_ACTION_BACK},
 			{"menu-top",		SWITCH_IVR_ACTION_TOMAIN},
-			{"call-transfer",	SWITCH_IVR_ACTION_TRANSFER},
+			{"menu-call-transfer",	SWITCH_IVR_ACTION_TRANSFER},
 		};
-		int iam_qty = sizeof(iam)/sizeof(iam[0]);
+		int iam_qty = (sizeof(iam)/sizeof(iam[0]));
+		int i;
 
-		// set the menu stack for the caller
-		if (*menu_stack == NULL) {
+		for(i=0; i<iam_qty && status == SWITCH_STATUS_SUCCESS; i++) {
+			status = switch_ivr_menu_stack_xml_add(*xml_menu_ctx,iam[i].name,iam[i].action,NULL);
+		}
+	}
+
+	return status;
+}
+
+SWITCH_DECLARE(switch_status_t) switch_ivr_menu_stack_xml_add_custom(switch_ivr_menu_xml_ctx_t *xml_menu_ctx, char *name, switch_ivr_menu_action_function_t *function)
+{	
+	return switch_ivr_menu_stack_xml_add(xml_menu_ctx, name, -1, function);
+}
+
+SWITCH_DECLARE(switch_status_t) switch_ivr_menu_stack_xml_build(switch_ivr_menu_xml_ctx_t *xml_menu_ctx,
+										switch_ivr_menu_t **menu_stack,
+										switch_xml_t xml_menus,
+										switch_xml_t xml_menu,
+										char *timer_name)
+{
+	switch_status_t status	= SWITCH_STATUS_FALSE;
+
+	if (xml_menu_ctx != NULL && menu_stack  != NULL && xml_menu != NULL) {
+		char *menu_name		= (char *)switch_xml_attr_soft(xml_menu,"name");		// if the attr doesn't exist, return ""
+		char *greet_long	= (char *)switch_xml_attr(xml_menu,"greet-long");		// if the attr doesn't exist, return NULL
+		char *greet_short	= (char *)switch_xml_attr(xml_menu,"greet-short");		// if the attr doesn't exist, return NULL
+		char *invalid_sound	= (char *)switch_xml_attr(xml_menu,"invalid-sound");		// if the attr doesn't exist, return NULL
+		char *exit_sound	= (char *)switch_xml_attr(xml_menu,"exit-sound");		// if the attr doesn't exist, return NULL
+		char *tts_engine	= (char *)switch_xml_attr(xml_menu,"tts-engine");		// if the attr doesn't exist, return NULL
+		char *tts_voice		= (char *)switch_xml_attr(xml_menu,"tts-voice");		// if the attr doesn't exist, return NULL
+		char *timeout		= (char *)switch_xml_attr_soft(xml_menu,"timeout");		// if the attr doesn't exist, return ""
+		char *max_failures	= (char *)switch_xml_attr_soft(xml_menu,"max-failures");	// if the attr doesn't exist, return ""
+		switch_ivr_menu_t *menu	= NULL;
+
+		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "building menu '%s'\n",menu_name);
+		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "timer_name '%s'\n",timer_name);
+		status = switch_ivr_menu_init(&menu,
+									*menu_stack,
+									menu_name,
+									greet_long,
+									greet_short,
+									invalid_sound,
+									exit_sound,
+									tts_engine,
+									tts_voice,
+									atoi(timeout)*1000,
+									atoi(max_failures),
+									timer_name,
+									xml_menu_ctx->pool
+									);
+		// set the menu_stack for the caller
+		if (status == SWITCH_STATUS_SUCCESS && *menu_stack == NULL) {
 			*menu_stack = menu;
 		}
 
-		// build menu entries
-		for(xml_kvp = switch_xml_child(xml_menu, "entry"); xml_kvp != NULL && status == SWITCH_STATUS_SUCCESS; xml_kvp = xml_kvp->next) {
-			char *action	= (char *)switch_xml_attr(xml_kvp, "action");
-			char *digits	= (char *)switch_xml_attr(xml_kvp, "digits");
-			char *param	= (char *)switch_xml_attr_soft(xml_kvp, "param");
+		if (status == SWITCH_STATUS_SUCCESS && menu != NULL) {
+			switch_xml_t xml_kvp;
 
-			if (!switch_strlen_zero(action) && !switch_strlen_zero(digits)) {
-				int i,found;
+			// build menu entries
+			for(xml_kvp = switch_xml_child(xml_menu, "entry"); xml_kvp != NULL && status == SWITCH_STATUS_SUCCESS; xml_kvp = xml_kvp->next) {
+				char *action	= (char *)switch_xml_attr(xml_kvp, "action");
+				char *digits	= (char *)switch_xml_attr(xml_kvp, "digits");
+				char *param	= (char *)switch_xml_attr_soft(xml_kvp, "param");
 
-				for(i=0,found=0; i<iam_qty && !found; i++) {
-					found = (strcasecmp(iam[i].name,action) == 0);
-				}
+				if (!switch_strlen_zero(action) && !switch_strlen_zero(digits)) {
+					switch_ivr_menu_xml_map_t *xml_map = xml_menu_ctx->map;
+					int found = 0;
 
-				if (found) {
-					i--;
-					// do we need to build a new sub-menu ?
-					if (iam[i].action == SWITCH_IVR_ACTION_EXECMENU && switch_ivr_find_menu(*menu_stack, param) == NULL) {
-						if ((xml_menu = switch_xml_find_child(xml_menus, "menu", "name", param)) != NULL) {
-							status = switch_ivr_build_xml_menu_stack(menu_stack, xml_menus, xml_menu, pool);
+					// find and appropriate xml handler
+					while(xml_map != NULL && !found) {
+						if (!(found = (strcasecmp(xml_map->name,action) == 0))) {
+							xml_map = xml_map->next;
 						}
 					}
-					// finally bind the menu entry
-					if (status == SWITCH_STATUS_SUCCESS) {
-						status = switch_ivr_menu_bind_action(menu, iam[i].action, param, digits);
+
+					if (found && xml_map != NULL) {
+						// do we need to build a new sub-menu ?
+						if (xml_map->action == SWITCH_IVR_ACTION_EXECMENU && switch_ivr_menu_find(*menu_stack, param) == NULL) {
+							if ((xml_menu = switch_xml_find_child(xml_menus, "menu", "name", param)) != NULL) {
+								status = switch_ivr_menu_stack_xml_build(xml_menu_ctx, menu_stack, xml_menus, xml_menu, timer_name);
+							}
+						}
+
+						// finally bind the menu entry
+						if (status == SWITCH_STATUS_SUCCESS) {
+							if (xml_map->function != NULL) {
+								switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG,
+									"binding menu caller control '%s'/'%s' to '%s'\n", xml_map->name, param, digits);
+								status = switch_ivr_menu_bind_function(menu, xml_map->function, param, digits);
+							} else {
+								switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG,
+									"binding menu action '%s' to '%s'\n", xml_map->name, digits);
+								status = switch_ivr_menu_bind_action(menu, xml_map->action, param, digits);
+							}
+						}
 					}
+				} else {
+					status = SWITCH_STATUS_FALSE;
 				}
-			} else {
-				status = SWITCH_STATUS_FALSE;
 			}
 		}
 	}
 
 	if (status != SWITCH_STATUS_SUCCESS) {
-		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Unable to build xml menu '%s'\n",menu_name);
+		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Unable to build xml menu\n");
 	}
 
 	return status;
 }
+/*
+SWITCH_DECLARE(switch_status_t) switch_ivr_menu_stack_xml_free(switch_ivr_menu_xml_ctx_t **xml_menu_ctx,
+										switch_ivr_menu_t **menu_stack)
+{
+	switch_status_t status = SWITCH_STATUS_FALSE;
+
+	if (xml_menu_ctx != NULL && *xml_menu_ctx != NULL ) {
+	}
+
+	status = switch_ivr_menu_stack_free(menu_stack);
+
+	return status
+}
+*/



More information about the Freeswitch-branches mailing list