Revision
15105
Author
anthm
Date
2009-10-06 23:30:19 -0500 (Tue, 06 Oct 2009)

Log Message

make moc happy

Modified Paths

Diff

Modified: freeswitch/trunk/src/include/switch_types.h (15104 => 15105)


--- freeswitch/trunk/src/include/switch_types.h	2009-10-07 02:49:23 UTC (rev 15104)
+++ freeswitch/trunk/src/include/switch_types.h	2009-10-07 04:30:19 UTC (rev 15105)
@@ -128,6 +128,7 @@
 #define SWITCH_CHANNEL_EXECUTE_ON_RING_VARIABLE "execute_on_ring"
 #define SWITCH_CALL_TIMEOUT_VARIABLE "call_timeout"
 #define SWITCH_HOLDING_UUID_VARIABLE "holding_uuid"
+#define SWITCH_SOFT_HOLDING_UUID_VARIABLE "soft_holding_uuid"
 #define SWITCH_API_BRIDGE_END_VARIABLE "api_after_bridge"
 #define SWITCH_API_HANGUP_HOOK_VARIABLE "api_hangup_hook"
 #define SWITCH_SESSION_IN_HANGUP_HOOK_VARIABLE "session_in_hangup_hook"
@@ -869,7 +870,7 @@
 	CF_ANSWERED = 1,
 	CF_OUTBOUND,
 	CF_EARLY_MEDIA,
-	CF_ORIGINATOR,
+	CF_BRIDGE_ORIGINATOR,
 	CF_TRANSFER,
 	CF_ACCEPT_CNG,
 	CF_REDIRECT,
@@ -903,6 +904,8 @@
 	CF_REPORTING,
 	CF_PARK,
 	CF_TIMESTAMP_SET,
+	CF_ORIGINATOR,
+	CF_XFER_ZOMBIE,
 	/* WARNING: DO NOT ADD ANY FLAGS BELOW THIS LINE */
 	CF_FLAG_MAX
 } switch_channel_flag_t;

Modified: freeswitch/trunk/src/mod/applications/mod_dptools/mod_dptools.c (15104 => 15105)


--- freeswitch/trunk/src/mod/applications/mod_dptools/mod_dptools.c	2009-10-07 02:49:23 UTC (rev 15104)
+++ freeswitch/trunk/src/mod/applications/mod_dptools/mod_dptools.c	2009-10-07 04:30:19 UTC (rev 15105)
@@ -1533,7 +1533,7 @@
 				switch_caller_extension_t *extension = NULL;
 				const char *app = "three_way";
 				const char *app_arg = switch_core_session_get_uuid(session);
-				const char *holding = switch_channel_get_variable(channel, SWITCH_HOLDING_UUID_VARIABLE);
+				const char *holding = switch_channel_get_variable(channel, SWITCH_SOFT_HOLDING_UUID_VARIABLE);
 				switch_core_session_t *b_session;
 
 				if (holding && (b_session = switch_core_session_locate(holding))) {
@@ -1603,9 +1603,9 @@
 		bond = switch_core_session_strdup(session, bond);
 	}
 
-	switch_channel_set_variable(channel, SWITCH_HOLDING_UUID_VARIABLE, bond);
+	switch_channel_set_variable(channel, SWITCH_SOFT_HOLDING_UUID_VARIABLE, bond);
+	switch_channel_set_flag(channel, CF_XFER_ZOMBIE);
 
-
 	if ((var = switch_channel_get_variable(channel, SWITCH_CALL_TIMEOUT_VARIABLE))) {
 		timelimit = atoi(var);
 	}
@@ -1654,7 +1654,8 @@
 	switch_core_session_rwunlock(peer_session);
 
   end:
-	switch_channel_set_variable(channel, SWITCH_HOLDING_UUID_VARIABLE, NULL);
+	switch_channel_set_variable(channel, SWITCH_SOFT_HOLDING_UUID_VARIABLE, NULL);
+	switch_channel_clear_flag(channel, CF_XFER_ZOMBIE);
 }
 
 SWITCH_STANDARD_APP(read_function)
@@ -1906,6 +1907,35 @@
 
 }
 
+
+
+SWITCH_STANDARD_APP(endless_playback_function)
+{
+	switch_channel_t *channel = switch_core_session_get_channel(session);
+	switch_status_t status = SWITCH_STATUS_SUCCESS;
+	const char *file = data;
+	
+	while(switch_channel_ready(channel)) {
+		if ((status = switch_ivr_play_file(session, NULL, file, NULL)) == SWITCH_STATUS_NOTFOUND) {
+			break;
+		}
+	}
+
+	switch (status) {
+	case SWITCH_STATUS_SUCCESS:
+	case SWITCH_STATUS_BREAK:
+		switch_channel_set_variable(channel, SWITCH_CURRENT_APPLICATION_RESPONSE_VARIABLE, "FILE PLAYED");
+		break;
+	case SWITCH_STATUS_NOTFOUND:
+		switch_channel_set_variable(channel, SWITCH_CURRENT_APPLICATION_RESPONSE_VARIABLE, "FILE NOT FOUND");
+		break;
+	default:
+		switch_channel_set_variable(channel, SWITCH_CURRENT_APPLICATION_RESPONSE_VARIABLE, "PLAYBACK ERROR");
+		break;
+	}
+
+}
+
 SWITCH_STANDARD_APP(gentones_function)
 {
 	char *tone_script = NULL;
@@ -2791,6 +2821,8 @@
 	SWITCH_ADD_APP(app_interface, "park_state", "Park State", "Park State", park_state_function, "", SAF_NONE);
 	SWITCH_ADD_APP(app_interface, "gentones", "Generate Tones", "Generate tones to the channel", gentones_function, "<tgml_script>[|<loops>]", SAF_NONE);
 	SWITCH_ADD_APP(app_interface, "playback", "Playback File", "Playback a file to the channel", playback_function, "<path>", SAF_NONE);
+	SWITCH_ADD_APP(app_interface, "endless_playback", "Playback File Endlessly", "Endlessly Playback a file to the channel", 
+				   endless_playback_function, "<path>", SAF_NONE);
 	SWITCH_ADD_APP(app_interface, "att_xfer", "Attended Transfer", "Attended Transfer", att_xfer_function, "<channel_url>", SAF_NONE);
 	SWITCH_ADD_APP(app_interface, "read", "Read Digits", "Read Digits", read_function, "<min> <max> <file> <var_name> <timeout> <terminators>", SAF_NONE);
 	SWITCH_ADD_APP(app_interface, "play_and_get_digits", "Play and get Digits", "Play and get Digits", 

Modified: freeswitch/trunk/src/mod/applications/mod_fifo/mod_fifo.c (15104 => 15105)


--- freeswitch/trunk/src/mod/applications/mod_fifo/mod_fifo.c	2009-10-07 02:49:23 UTC (rev 15104)
+++ freeswitch/trunk/src/mod/applications/mod_fifo/mod_fifo.c	2009-10-07 04:30:19 UTC (rev 15105)
@@ -89,7 +89,7 @@
 
 			const char *consumer_exit_key = switch_channel_get_variable(channel, "fifo_consumer_exit_key");
 
-			if (switch_channel_test_flag(switch_core_session_get_channel(session), CF_ORIGINATOR)) {
+			if (switch_channel_test_flag(switch_core_session_get_channel(session), CF_BRIDGE_ORIGINATOR)) {
 				if ( consumer_exit_key && dtmf->digit == *consumer_exit_key ) {
 					switch_channel_hangup(bchan, SWITCH_CAUSE_NORMAL_CLEARING);
 					return SWITCH_STATUS_BREAK;

Modified: freeswitch/trunk/src/mod/endpoints/mod_sofia/sofia.c (15104 => 15105)


--- freeswitch/trunk/src/mod/endpoints/mod_sofia/sofia.c	2009-10-07 02:49:23 UTC (rev 15104)
+++ freeswitch/trunk/src/mod/endpoints/mod_sofia/sofia.c	2009-10-07 04:30:19 UTC (rev 15105)
@@ -4117,8 +4117,46 @@
 
 						br_a = switch_channel_get_variable(channel_a, SWITCH_SIGNAL_BOND_VARIABLE);
 						br_b = switch_channel_get_variable(channel_b, SWITCH_SIGNAL_BOND_VARIABLE);
+						
+						if (switch_channel_test_flag(channel_b, CF_ORIGINATOR)) {
+							switch_core_session_t *a_session;
 
-						if (br_a && br_b) {
+							switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_NOTICE, 
+											  "Attended Transfer on originating session %s\n", switch_core_session_get_uuid(b_session));
+							
+
+							
+							switch_channel_set_variable(channel_b, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, "ATTENDED_TRANSFER");
+							
+							
+							sofia_clear_flag_locked(b_tech_pvt, TFLAG_SIP_HOLD);
+							sofia_clear_flag_locked(tech_pvt, TFLAG_HOLD_LOCK);
+
+							switch_channel_set_variable(channel_b, SWITCH_HOLDING_UUID_VARIABLE, br_a);
+							switch_channel_set_flag(channel_b, CF_XFER_ZOMBIE);
+
+							if ((a_session = switch_core_session_locate(br_a))) {
+								const char *moh = profile->hold_music;
+								switch_channel_t *a_channel = switch_core_session_get_channel(a_session);
+								const char *tmp;
+
+								if ((tmp = switch_channel_get_variable(a_channel, SWITCH_HOLD_MUSIC_VARIABLE))) {
+									moh = tmp;
+								}
+								//switch_channel_set_variable(a_channel, SWITCH_PARK_AFTER_BRIDGE_VARIABLE, "true");
+								switch_channel_set_variable_printf(a_channel, SWITCH_TRANSFER_AFTER_BRIDGE_VARIABLE, "'endless_playback:%s':inline", moh);
+								//switch_channel_set_variable_printf(a_channel, "park_command", "moh");
+								switch_core_session_rwunlock(a_session);
+							}
+
+							nua_notify(tech_pvt->nh, NUTAG_NEWSUB(1), SIPTAG_CONTENT_TYPE_STR("message/sipfrag"),
+									   NUTAG_SUBSTATE(nua_substate_terminated), SIPTAG_PAYLOAD_STR("SIP/2.0 200 OK"), SIPTAG_EVENT_STR(etmp), TAG_END());
+
+							//switch_channel_set_variable(channel_b, "park_timeout", "2");
+							//switch_channel_set_state(channel_b, CS_PARK);
+							
+											  
+						} else if (br_a && br_b) {
 							switch_core_session_t *new_b_session = NULL, *a_session = NULL, *tmp = NULL;
 						
 							switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_NOTICE, "Attended Transfer [%s][%s]\n", 
@@ -4138,8 +4176,9 @@
 
 							sofia_clear_flag_locked(b_tech_pvt, TFLAG_SIP_HOLD);
 							sofia_clear_flag_locked(tech_pvt, TFLAG_HOLD_LOCK);
-							switch_channel_set_variable(switch_core_session_get_channel(b_session), "park_timeout", "2");
-							switch_channel_set_state(switch_core_session_get_channel(b_session), CS_PARK);
+							switch_channel_set_variable(channel_b, "park_timeout", "2");
+							switch_channel_set_state(channel_b, CS_PARK);
+							
 
 							new_b_session = switch_core_session_locate(br_b);
 							a_session = switch_core_session_locate(br_a);

Modified: freeswitch/trunk/src/switch_channel.c (15104 => 15105)


--- freeswitch/trunk/src/switch_channel.c	2009-10-07 02:49:23 UTC (rev 15104)
+++ freeswitch/trunk/src/switch_channel.c	2009-10-07 04:30:19 UTC (rev 15105)
@@ -1706,10 +1706,11 @@
 	switch_channel_clear_flag(channel, CF_BLOCK_STATE);
 	
 	if (channel->state < CS_HANGUP) {
-		switch_channel_state_t last_state = channel->state;
+		switch_channel_state_t last_state;
 		switch_event_t *event;
 
 		switch_mutex_lock(channel->state_mutex);
+		last_state = channel->state;
 		channel->state = CS_HANGUP;
 		switch_mutex_unlock(channel->state_mutex);
 

Modified: freeswitch/trunk/src/switch_ivr.c (15104 => 15105)


--- freeswitch/trunk/src/switch_ivr.c	2009-10-07 02:49:23 UTC (rev 15104)
+++ freeswitch/trunk/src/switch_ivr.c	2009-10-07 04:30:19 UTC (rev 15105)
@@ -666,6 +666,7 @@
 			expires = switch_epoch_time_now(NULL) + timeout;
 		}
 		switch_channel_set_variable(channel, "park_timeout", NULL);
+		switch_channel_set_variable(channel, SWITCH_PARK_AFTER_BRIDGE_VARIABLE, NULL);
 	}
 
 	switch_channel_set_flag(channel, CF_CONTROLLED);
@@ -1150,7 +1151,7 @@
 	if ((session = switch_core_session_locate(uuid))) {
 		channel = switch_core_session_get_channel(session);
 
-		if ((flags & SMF_REBRIDGE) && !switch_channel_test_flag(channel, CF_ORIGINATOR)) {
+		if ((flags & SMF_REBRIDGE) && !switch_channel_test_flag(channel, CF_BRIDGE_ORIGINATOR)) {
 			swap = 1;
 		}
 
@@ -1214,7 +1215,7 @@
 		status = SWITCH_STATUS_SUCCESS;
 		channel = switch_core_session_get_channel(session);
 
-		if ((flags & SMF_REBRIDGE) && !switch_channel_test_flag(channel, CF_ORIGINATOR)) {
+		if ((flags & SMF_REBRIDGE) && !switch_channel_test_flag(channel, CF_BRIDGE_ORIGINATOR)) {
 			swap = 1;
 		}
 

Modified: freeswitch/trunk/src/switch_ivr_bridge.c (15104 => 15105)


--- freeswitch/trunk/src/switch_ivr_bridge.c	2009-10-07 02:49:23 UTC (rev 15104)
+++ freeswitch/trunk/src/switch_ivr_bridge.c	2009-10-07 04:30:19 UTC (rev 15105)
@@ -131,7 +131,7 @@
 	chan_b = switch_core_session_get_channel(session_b);
 
 	ans_a = switch_channel_test_flag(chan_a, CF_ANSWERED);
-	if ((originator = switch_channel_test_flag(chan_a, CF_ORIGINATOR))) {
+	if ((originator = switch_channel_test_flag(chan_a, CF_BRIDGE_ORIGINATOR))) {
 		pre_b = switch_channel_test_flag(chan_a, CF_EARLY_MEDIA);
 		ans_b = switch_channel_test_flag(chan_b, CF_ANSWERED);
 	}
@@ -478,7 +478,9 @@
 	int argc;
 	char *argv[4] = { 0 };
 	char *mydata;
-	
+
+	switch_channel_set_variable(switch_core_session_get_channel(session), SWITCH_TRANSFER_AFTER_BRIDGE_VARIABLE, NULL);
+
 	if (!switch_strlen_zero(where) && (mydata = switch_core_session_strdup(session, where))) {
 		if ((argc = switch_separate_string(mydata, ':', argv, (sizeof(argv) / sizeof(argv[0])))) >= 1) {
 			switch_ivr_session_transfer(session, argv[0], argv[1], argv[2]);
@@ -583,7 +585,7 @@
 
 	switch_channel_clear_flag(channel, CF_ORIGINATING);
 
-	if (switch_channel_test_flag(channel, CF_ORIGINATOR)) {
+	if (switch_channel_test_flag(channel, CF_BRIDGE_ORIGINATOR)) {
 		switch_channel_set_state(channel, CS_SOFT_EXECUTE);
 	}
 
@@ -605,11 +607,11 @@
 	switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s CUSTOM SOFT_EXECUTE\n", switch_channel_get_name(channel));
 	switch_channel_clear_state_handler(channel, &uuid_bridge_state_handlers);
 
-	if (!switch_channel_test_flag(channel, CF_ORIGINATOR)) {
+	if (!switch_channel_test_flag(channel, CF_BRIDGE_ORIGINATOR)) {
 		return SWITCH_STATUS_SUCCESS;
 	}
 
-	switch_channel_clear_flag(channel, CF_ORIGINATOR);
+	switch_channel_clear_flag(channel, CF_BRIDGE_ORIGINATOR);
 	
 	if ((other_uuid = switch_channel_get_variable(channel, SWITCH_UUID_BRIDGE)) && (other_session = switch_core_session_locate(other_uuid))) {
 		switch_channel_t *other_channel = switch_core_session_get_channel(other_session);
@@ -731,8 +733,8 @@
         switch_core_session_rwunlock(other_session);
     }
 	
-	if (switch_channel_test_flag(channel, CF_ORIGINATOR)) {
-		switch_channel_clear_flag(channel, CF_ORIGINATOR);
+	if (switch_channel_test_flag(channel, CF_BRIDGE_ORIGINATOR)) {
+		switch_channel_clear_flag(channel, CF_BRIDGE_ORIGINATOR);
 		if (switch_event_create(&event, SWITCH_EVENT_CHANNEL_UNBRIDGE) == SWITCH_STATUS_SUCCESS) {
 			switch_channel_event_set_data(channel, event);
 			switch_event_fire(&event);
@@ -772,7 +774,7 @@
 	switch_channel_set_variable(caller_channel, SWITCH_SIGNAL_BRIDGE_VARIABLE, switch_core_session_get_uuid(peer_session));
 	switch_channel_set_variable(peer_channel, SWITCH_SIGNAL_BRIDGE_VARIABLE, switch_core_session_get_uuid(session));
 
-	switch_channel_set_flag(caller_channel, CF_ORIGINATOR);
+	switch_channel_set_flag(caller_channel, CF_BRIDGE_ORIGINATOR);
 
 	switch_channel_clear_state_handler(caller_channel, NULL);
 	switch_channel_clear_state_handler(peer_channel, NULL);
@@ -837,7 +839,7 @@
 		return switch_ivr_signal_bridge(session, peer_session);
 	}
 
-	switch_channel_set_flag(caller_channel, CF_ORIGINATOR);
+	switch_channel_set_flag(caller_channel, CF_BRIDGE_ORIGINATOR);
 
 	b_leg->session = peer_session;
 	switch_copy_string(b_leg->b_uuid, switch_core_session_get_uuid(session), sizeof(b_leg->b_uuid));
@@ -962,7 +964,7 @@
 			switch_channel_set_state(peer_channel, CS_EXCHANGE_MEDIA);
 			audio_bridge_thread(NULL, (void *) a_leg);
 			
-			switch_channel_clear_flag(caller_channel, CF_ORIGINATOR);
+			switch_channel_clear_flag(caller_channel, CF_BRIDGE_ORIGINATOR);
 
 			while (switch_channel_get_state(peer_channel) == CS_EXCHANGE_MEDIA) {
 				switch_cond_next();
@@ -1184,10 +1186,13 @@
 			switch_channel_clear_flag(originatee_channel, CF_ORIGINATING);
 
 			/* change the states and let the chips fall where they may */
+
+			switch_channel_set_variable(originator_channel, SWITCH_PARK_AFTER_BRIDGE_VARIABLE, NULL);
+			switch_channel_set_variable(originatee_channel, SWITCH_PARK_AFTER_BRIDGE_VARIABLE, NULL);
 			switch_channel_clear_state_handler(originator_channel, NULL);
 			switch_channel_clear_state_handler(originatee_channel, NULL);
-			switch_channel_set_state_flag(originator_channel, CF_ORIGINATOR);
-			switch_channel_clear_flag(originatee_channel, CF_ORIGINATOR);
+			switch_channel_set_state_flag(originator_channel, CF_BRIDGE_ORIGINATOR);
+			switch_channel_clear_flag(originatee_channel, CF_BRIDGE_ORIGINATOR);
 			switch_channel_add_state_handler(originator_channel, &uuid_bridge_state_handlers);
 			switch_channel_add_state_handler(originatee_channel, &uuid_bridge_state_handlers);
 

Modified: freeswitch/trunk/src/switch_ivr_originate.c (15104 => 15105)


--- freeswitch/trunk/src/switch_ivr_originate.c	2009-10-07 02:49:23 UTC (rev 15104)
+++ freeswitch/trunk/src/switch_ivr_originate.c	2009-10-07 04:30:19 UTC (rev 15105)
@@ -118,6 +118,7 @@
 
 
 typedef enum {
+	IDX_KEY_CANCEL = -4,
 	IDX_TIMEOUT = -3,
 	IDX_CANCEL = -2,
 	IDX_NADA = -1
@@ -661,9 +662,14 @@
 	const char *var;
 	switch_time_t start = 0;
 	const char *cancel_key = NULL;
+	switch_channel_state_t wait_state = 0;
 
 	switch_assert(peer_channel);
 	
+	if (switch_channel_get_state(peer_channel) == CS_RESET) {
+		switch_channel_set_state(peer_channel, CS_SOFT_EXECUTE);
+	}
+
 	if (session) {
 		caller_channel = switch_core_session_get_channel(session);
 	}
@@ -810,8 +816,11 @@
 
  no_ringback:
 
-	while (switch_channel_ready(peer_channel)
-		   && !(switch_channel_test_flag(peer_channel, CF_ANSWERED) || switch_channel_test_flag(peer_channel, CF_EARLY_MEDIA))) {
+	if (caller_channel) {
+		wait_state = switch_channel_get_state(caller_channel);
+	}
+
+	while (switch_channel_ready(peer_channel) && !switch_channel_media_ready(peer_channel)) {
 		int diff = (int) (switch_micro_time_now() - start);
 
 		if (caller_channel && cancel_key) {
@@ -826,6 +835,10 @@
 			}
 		}
 
+		if (caller_channel && switch_channel_get_state(caller_channel) != wait_state) {
+			goto done;
+		}
+
 		if (diff > timelimit) {
 			status = SWITCH_STATUS_TIMEOUT;
 			goto done;
@@ -918,7 +931,18 @@
 
  end:
 
-	return (!caller_channel || switch_channel_ready(caller_channel)) ? status : SWITCH_STATUS_FALSE;
+	if (!switch_channel_media_ready(peer_channel)) {
+		if (switch_channel_up(peer_channel)) {
+			switch_channel_hangup(peer_channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER);
+		}
+		status = SWITCH_STATUS_FALSE;
+	}
+	
+	if (caller_channel && !switch_channel_ready(caller_channel)) {
+		status = SWITCH_STATUS_FALSE;
+	}
+
+	return status;
 }
 
 SWITCH_DECLARE(void) switch_process_import(switch_core_session_t *session, switch_channel_t *peer_channel, const char *varname)
@@ -945,6 +969,12 @@
 }
 
 
+#define peer_eligible(_peer) (_peer && !(switch_channel_test_flag(_peer, CF_TRANSFER) || \
+										 switch_channel_test_flag(_peer, CF_REDIRECT) || \
+										 switch_channel_test_flag(_peer, CF_BRIDGED) || \
+										 switch_channel_get_state(_peer) == CS_RESET || \
+										 !switch_channel_test_flag(_peer, CF_ORIGINATING)))
+
 #define MAX_PEERS 128
 SWITCH_DECLARE(switch_status_t) switch_ivr_originate(switch_core_session_t *session,
 													 switch_core_session_t **bleg,
@@ -981,6 +1011,7 @@
 	uint8_t pass = 0;
 	char *odata, *var;
 	switch_call_cause_t reason = SWITCH_CAUSE_NONE;
+	switch_call_cause_t force_reason = SWITCH_CAUSE_NONE;
 	uint8_t to = 0;
 	char *var_val, *vars = NULL;
 	int var_block_count = 0;
@@ -998,9 +1029,12 @@
 	int cdr_total = 0;
 	int local_clobber = 0;
 	const char *cancel_key = NULL;
+	const char *holding = NULL;
+	switch_channel_state_t wait_state = 0;
 
 	if (session) {
 		caller_channel = switch_core_session_get_channel(session);
+		switch_channel_set_flag(caller_channel, CF_ORIGINATOR);
 		oglobals.session = session;
 
 		if (switch_true(switch_channel_get_variable(caller_channel, SWITCH_PROXY_MEDIA_VARIABLE))) {
@@ -1925,7 +1959,13 @@
 				oglobals.early_ok = 0;
 			}
 #endif
-			while ((!caller_channel || switch_channel_ready(caller_channel)) && check_channel_status(&oglobals, originate_status, and_argc)) {
+
+			if (caller_channel) {
+				wait_state = switch_channel_get_state(caller_channel);
+			}
+			
+			while ((!caller_channel || switch_channel_ready(caller_channel) || switch_channel_test_flag(caller_channel, CF_XFER_ZOMBIE)) && 
+				   check_channel_status(&oglobals, originate_status, and_argc)) {
 				time_t elapsed = switch_epoch_time_now(NULL) - start;
 				if (caller_channel && !oglobals.sent_ring && oglobals.ring_ready && !oglobals.return_ring_ready) {
 					switch_channel_ring_ready(caller_channel);
@@ -1939,6 +1979,11 @@
 					switch_ivr_parse_all_events(oglobals.session);
 				}
 
+				if (caller_channel && switch_channel_get_state(caller_channel) != wait_state && !switch_channel_test_flag(caller_channel, CF_XFER_ZOMBIE)) {
+					oglobals.idx = IDX_NADA;
+                    goto notready;
+				}
+
 				if (!oglobals.sent_ring && !oglobals.progress && (progress_timelimit_sec && elapsed > (time_t) progress_timelimit_sec)) {
 					oglobals.idx = IDX_TIMEOUT;
 					goto notready;
@@ -1991,9 +2036,10 @@
 				if (oglobals.session &&
 					!switch_channel_test_flag(caller_channel, CF_PROXY_MODE) &&
 					!switch_channel_test_flag(caller_channel, CF_PROXY_MEDIA) &&
+					!switch_channel_test_flag(caller_channel, CF_XFER_ZOMBIE) &&
 					(ringback_data
 					 || (switch_channel_test_flag(caller_channel, CF_ANSWERED) || switch_channel_test_flag(caller_channel, CF_EARLY_MEDIA)))) {
-
+					
 					switch_status_t tstatus = SWITCH_STATUS_SUCCESS;
 					int silence = 0;
 
@@ -2002,7 +2048,7 @@
 							switch_dtmf_t dtmf = { 0, 0 };
 							if (switch_channel_dequeue_dtmf(caller_channel, &dtmf) == SWITCH_STATUS_SUCCESS) {
 								if (dtmf.digit == *cancel_key) {
-									oglobals.idx = IDX_CANCEL;
+									oglobals.idx = IDX_KEY_CANCEL;
 									goto notready;
 								}
 							}
@@ -2079,6 +2125,17 @@
 
 		  notready:
 
+			if (caller_channel) {
+				const char *soft_holding = switch_channel_get_variable(caller_channel, SWITCH_SOFT_HOLDING_UUID_VARIABLE);
+				holding = switch_channel_get_variable(caller_channel, SWITCH_HOLDING_UUID_VARIABLE);
+				switch_channel_set_variable(caller_channel, SWITCH_HOLDING_UUID_VARIABLE, NULL);
+
+				if (soft_holding && switch_channel_test_flag(caller_channel, CF_XFER_ZOMBIE)) {
+					holding = soft_holding;
+					switch_channel_set_variable(caller_channel, SWITCH_SOFT_HOLDING_UUID_VARIABLE, NULL);
+				}
+			}
+			
 			if (caller_channel && !switch_channel_ready(caller_channel)) {
 				oglobals.idx = IDX_CANCEL;
 			}
@@ -2088,26 +2145,86 @@
 				switch_core_session_reset(oglobals.session, SWITCH_FALSE, SWITCH_TRUE);
 			}
 
-			for (i = 0; i < and_argc; i++) {
-				if (!originate_status[i].peer_channel) {
-					continue;
+			if ((oglobals.idx == IDX_TIMEOUT || oglobals.idx == IDX_KEY_CANCEL) && switch_channel_ready(caller_channel)) {
+				holding = NULL;
+			}
+
+			if (holding) {
+				if (oglobals.idx > IDX_NADA) {
+					peer_session = originate_status[oglobals.idx].peer_session;
+					peer_channel = originate_status[oglobals.idx].peer_channel;
+					originate_status[oglobals.idx].peer_channel = NULL;
+				} else if (and_argc == 1) {
+					peer_session = originate_status[0].peer_session;
+					peer_channel = originate_status[0].peer_channel;
+					originate_status[0].peer_channel = NULL;
+				} else {
+					for (i = 0; i < and_argc; i++) {
+						if (!peer_eligible(originate_status[i].peer_channel)) {
+							continue;
+						}
+						if (switch_channel_media_ready(originate_status[i].peer_channel)) {
+							peer_session = originate_status[i].peer_session;
+							peer_channel = originate_status[i].peer_channel;
+							originate_status[i].peer_channel = NULL;
+							goto end_search;
+						}
+					}
+					for (i = 0; i < and_argc; i++) {
+						if (!peer_eligible(originate_status[i].peer_channel)) {
+							continue;
+						}
+						if (switch_channel_up(originate_status[i].peer_channel)) {
+							peer_session = originate_status[i].peer_session;
+							peer_channel = originate_status[i].peer_channel;
+							originate_status[i].peer_channel = NULL;
+							break;
+						}
+					}
 				}
 
-				//switch_channel_clear_flag(originate_status[i].peer_channel, CF_BLOCK_STATE);
+			end_search:
 
-				if (switch_channel_test_flag(originate_status[i].peer_channel, CF_TRANSFER) 
-					|| switch_channel_test_flag(originate_status[i].peer_channel, CF_REDIRECT) 
-					|| switch_channel_test_flag(originate_status[i].peer_channel, CF_BRIDGED) ||
-					switch_channel_get_state(originate_status[i].peer_channel) == CS_RESET || 
-					!switch_channel_test_flag(originate_status[i].peer_channel, CF_ORIGINATING)
-					) {
+
+				if (peer_channel && switch_channel_ready(peer_channel)) {
+					force_reason = SWITCH_CAUSE_ATTENDED_TRANSFER;
+					switch_ivr_uuid_bridge(holding, switch_core_session_get_uuid(peer_session));
+					oglobals.idx = IDX_NADA;
+					if (caller_channel) {
+						switch_channel_hangup(caller_channel, SWITCH_CAUSE_ATTENDED_TRANSFER);
+					}
+					switch_core_session_rwunlock(peer_session);
+				} else {
+					switch_core_session_t *holding_session;
+
+					if ((holding_session = switch_core_session_locate(holding))) {
+						switch_channel_t *holding_channel = switch_core_session_get_channel(holding_session);
+						if (caller_channel && switch_channel_ready(caller_channel)) {
+							switch_ivr_uuid_bridge(holding, switch_core_session_get_uuid(session));
+						} else {
+							switch_channel_hangup(holding_channel, SWITCH_CAUSE_NORMAL_UNSPECIFIED);
+						}
+						switch_core_session_rwunlock(holding_session);
+					}
+				}
+
+				peer_session = NULL;
+				peer_channel = NULL;
+				
+			}
+
+
+			for (i = 0; i < and_argc; i++) {
+				if (!peer_eligible(originate_status[i].peer_channel)) {
 					continue;
 				}
-
+				
 				if (i != oglobals.idx) {
-					const char *holding = NULL;
+					holding = NULL;
 
-					if (oglobals.idx == IDX_TIMEOUT || to) {
+					if (force_reason != SWITCH_CAUSE_NONE) {
+						reason = force_reason;
+					} else if (oglobals.idx == IDX_TIMEOUT || to) {
 						reason = SWITCH_CAUSE_NO_ANSWER;
 					} else {
 						if (oglobals.idx == IDX_CANCEL) {
@@ -2122,19 +2239,19 @@
 					}
 					if (switch_channel_up(originate_status[i].peer_channel)) {
 						if (caller_channel && i == 0) {
-							holding = switch_channel_get_variable(caller_channel, SWITCH_HOLDING_UUID_VARIABLE);
-							switch_channel_set_variable(caller_channel, SWITCH_HOLDING_UUID_VARIABLE, NULL);
-						}
-						if (holding && oglobals.idx != IDX_TIMEOUT && oglobals.idx != IDX_CANCEL) {
-							switch_ivr_uuid_bridge(holding, switch_core_session_get_uuid(originate_status[i].peer_session));
-						} else {
+                            holding = switch_channel_get_variable(caller_channel, SWITCH_SOFT_HOLDING_UUID_VARIABLE);
+                            switch_channel_set_variable(caller_channel, SWITCH_SOFT_HOLDING_UUID_VARIABLE, NULL);
+                        }
+						
+						if (holding && oglobals.idx != IDX_TIMEOUT && oglobals.idx != IDX_KEY_CANCEL) {
+                            switch_ivr_uuid_bridge(holding, switch_core_session_get_uuid(originate_status[i].peer_session));
+                        } else {
 							switch_channel_hangup(originate_status[i].peer_channel, reason);
 						}
 					}
 				}
 			}
-
-
+			
 			if (oglobals.idx > IDX_NADA) {
 				peer_session = originate_status[oglobals.idx].peer_session;
 				peer_channel = originate_status[oglobals.idx].peer_channel;
@@ -2384,6 +2501,11 @@
 	switch_safe_free(write_frame.data);
 	switch_safe_free(fail_on_single_reject_var);
 
+	if (caller_channel) {
+		switch_channel_clear_flag(caller_channel, CF_ORIGINATOR);
+		switch_channel_clear_flag(caller_channel, CF_XFER_ZOMBIE);
+	}
+
 	return status;
 }