Revision
15133
Author
anthm
Date
2009-10-09 15:48:24 -0500 (Fri, 09 Oct 2009)

Log Message

fix att-xfer...AGAIN

Modified Paths

Diff

Modified: freeswitch/trunk/src/include/switch_channel.h (15132 => 15133)


--- freeswitch/trunk/src/include/switch_channel.h	2009-10-09 19:29:30 UTC (rev 15132)
+++ freeswitch/trunk/src/include/switch_channel.h	2009-10-09 20:48:24 UTC (rev 15133)
@@ -262,6 +262,9 @@
  */
 SWITCH_DECLARE(void) switch_channel_variable_last(switch_channel_t *channel);
 
+
+SWITCH_DECLARE(switch_status_t) switch_channel_caller_extension_masquerade(switch_channel_t *orig_channel, switch_channel_t *new_channel, uint32_t offset);
+
 /*!
   \brief Assign a caller extension to a given channel
   \param channel channel to assign extension to

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


--- freeswitch/trunk/src/mod/endpoints/mod_sofia/sofia.c	2009-10-09 19:29:30 UTC (rev 15132)
+++ freeswitch/trunk/src/mod/endpoints/mod_sofia/sofia.c	2009-10-09 20:48:24 UTC (rev 15133)
@@ -4272,10 +4272,8 @@
 							switch_channel_set_variable(channel_b, SWITCH_HOLDING_UUID_VARIABLE, br_a);
 							switch_channel_set_flag(channel_b, CF_XFER_ZOMBIE);
 							switch_channel_set_flag(channel_b, CF_TRANSFER);
-
-							//switch_channel_set_variable(channel_b, "park_timeout", "2");
-							//switch_channel_set_state(channel_b, CS_PARK);
 							
+							
 							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);
@@ -4307,8 +4305,8 @@
 								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());
 
-
-								if (0 && b_tech_pvt) {
+								
+								if (1 && b_tech_pvt) {
 									sofia_set_flag_locked(b_tech_pvt, TFLAG_BYE);
 									nua_bye(b_tech_pvt->nh, 
 											SIPTAG_REASON_STR("Q.850;cause=16;text=\"normal_clearing\""),

Modified: freeswitch/trunk/src/switch_channel.c (15132 => 15133)


--- freeswitch/trunk/src/switch_channel.c	2009-10-09 19:29:30 UTC (rev 15132)
+++ freeswitch/trunk/src/switch_channel.c	2009-10-09 20:48:24 UTC (rev 15133)
@@ -1664,6 +1664,72 @@
 	switch_mutex_unlock(channel->state_mutex);
 }
 
+SWITCH_DECLARE(switch_status_t) switch_channel_caller_extension_masquerade(switch_channel_t *orig_channel, switch_channel_t *new_channel, uint32_t offset)
+{
+	switch_caller_profile_t *caller_profile;
+	switch_caller_extension_t *extension = NULL, *orig_extension = NULL;
+	switch_caller_application_t *ap;
+	switch_status_t status = SWITCH_STATUS_FALSE;
+	switch_event_header_t *hi = NULL;
+	const char *no_copy = switch_channel_get_variable(orig_channel, "attended_transfer_no_copy");
+	char *dup;
+	int i, argc = 0;
+	char *argv[128];
+
+	if (no_copy) {
+		dup = switch_core_session_strdup(new_channel->session, no_copy);
+		argc = switch_separate_string(dup, ',', argv, (sizeof(argv) / sizeof(argv[0])));
+	}
+
+
+	switch_mutex_lock(orig_channel->profile_mutex);
+	switch_mutex_lock(new_channel->profile_mutex);
+	
+	
+	caller_profile = switch_caller_profile_clone(new_channel->session, new_channel->caller_profile);
+	switch_assert(caller_profile);
+	extension = switch_caller_extension_new(new_channel->session, caller_profile->destination_number, caller_profile->destination_number);
+	orig_extension = switch_channel_get_caller_extension(orig_channel);
+	
+	
+	if (extension && orig_extension) {
+		for(ap = orig_extension->current_application; ap && offset > 0; offset--) {
+			ap = ap->next;
+		}
+		
+		for (; ap; ap = ap->next) {
+			switch_caller_extension_add_application(new_channel->session, extension, ap->application_name, ap->application_data);
+		}
+		
+		caller_profile->destination_number = switch_core_strdup(caller_profile->pool, orig_channel->caller_profile->destination_number);
+		switch_channel_set_caller_profile(new_channel, caller_profile);
+		switch_channel_set_caller_extension(new_channel, extension);
+
+		for (hi = orig_channel->variables->headers; hi; hi = hi->next) {
+			int ok = 1;
+			for (i = 0; i < argc; i++) {
+				if (!strcasecmp(argv[i], hi->name)) {
+					ok = 0;
+					break;
+				}
+			}
+			
+			if (!ok) continue;
+
+			switch_channel_set_variable(new_channel, hi->name, hi->value);
+		}
+
+		status = SWITCH_STATUS_SUCCESS;
+	}
+
+
+	switch_mutex_unlock(new_channel->profile_mutex);
+	switch_mutex_unlock(orig_channel->profile_mutex);
+
+
+	return status;
+}
+
 SWITCH_DECLARE(void) switch_channel_set_caller_extension(switch_channel_t *channel, switch_caller_extension_t *caller_extension)
 {
 	switch_assert(channel != NULL);

Modified: freeswitch/trunk/src/switch_ivr_bridge.c (15132 => 15133)


--- freeswitch/trunk/src/switch_ivr_bridge.c	2009-10-09 19:29:30 UTC (rev 15132)
+++ freeswitch/trunk/src/switch_ivr_bridge.c	2009-10-09 20:48:24 UTC (rev 15133)
@@ -569,7 +569,8 @@
 	} else if (state < CS_HANGUP && (var = switch_channel_get_variable(channel, SWITCH_TRANSFER_AFTER_BRIDGE_VARIABLE))) {
 		transfer_after_bridge(session, var);
 	} else {
-		if (!switch_channel_test_flag(channel, CF_TRANSFER) && !switch_channel_test_flag(channel, CF_REDIRECT) && bd && !bd->clean_exit 
+		if (!switch_channel_test_flag(channel, CF_TRANSFER) && !switch_channel_test_flag(channel, CF_REDIRECT) && 
+			!switch_channel_test_flag(channel, CF_XFER_ZOMBIE) && bd && !bd->clean_exit 
 			&& state != CS_PARK && state != CS_ROUTING && !switch_channel_test_flag(channel, CF_INNER_BRIDGE)) {
 			switch_channel_hangup(channel, SWITCH_CAUSE_NORMAL_CLEARING);
 		}
@@ -1082,8 +1083,8 @@
 
 	state = switch_channel_get_state(caller_channel);
 	
-	if (!switch_channel_test_flag(caller_channel, CF_TRANSFER) && !switch_channel_test_flag(caller_channel, CF_REDIRECT) 
-		&& !a_leg->clean_exit && !inner_bridge) {
+	if (!switch_channel_test_flag(caller_channel, CF_TRANSFER) && !switch_channel_test_flag(caller_channel, CF_REDIRECT) && 
+		!switch_channel_test_flag(caller_channel, CF_XFER_ZOMBIE) && !a_leg->clean_exit && !inner_bridge) {
 		if ((state != CS_EXECUTE && state != CS_SOFT_EXECUTE && state != CS_PARK && state != CS_ROUTING) ||
 			(switch_channel_test_flag(peer_channel, CF_ANSWERED) && state < CS_HANGUP)) {
 			if (switch_true(switch_channel_get_variable(caller_channel, SWITCH_PARK_AFTER_BRIDGE_VARIABLE))) {

Modified: freeswitch/trunk/src/switch_ivr_originate.c (15132 => 15133)


--- freeswitch/trunk/src/switch_ivr_originate.c	2009-10-09 19:29:30 UTC (rev 15132)
+++ freeswitch/trunk/src/switch_ivr_originate.c	2009-10-09 20:48:24 UTC (rev 15133)
@@ -2078,6 +2078,9 @@
 					if (switch_channel_media_ready(caller_channel)) {
 						tstatus = switch_core_session_read_frame(oglobals.session, &read_frame, SWITCH_IO_FLAG_NONE, 0);
 						if (!SWITCH_READ_ACCEPTABLE(tstatus)) {
+							if (switch_channel_test_flag(caller_channel, CF_XFER_ZOMBIE)) {
+								continue;
+							}
 							break;
 						}
 					} else {
@@ -2133,6 +2136,9 @@
 						}
 						
 						if (switch_core_session_write_frame(oglobals.session, &write_frame, SWITCH_IO_FLAG_NONE, 0) != SWITCH_STATUS_SUCCESS) {
+							if (switch_channel_test_flag(caller_channel, CF_XFER_ZOMBIE)) {
+								continue;
+							}
 							break;
 						}
 					}
@@ -2156,7 +2162,7 @@
 				}
 			}
 			
-			if (caller_channel && !switch_channel_ready(caller_channel)) {
+			if (caller_channel && !switch_channel_ready(caller_channel) && !switch_channel_test_flag(caller_channel, CF_XFER_ZOMBIE)) {
 				oglobals.idx = IDX_CANCEL;
 			}
 
@@ -2206,7 +2212,7 @@
 					const char *context = switch_channel_get_variable(peer_channel, "context");
 					const char *dialplan = switch_channel_get_variable(peer_channel, "dialplan");
 					switch_core_session_t *holding_session;
-
+					
 					if (caller_channel) {
 						if (switch_strlen_zero(context)) {
 							context = switch_channel_get_variable(caller_channel, "context"); 
@@ -2225,7 +2231,21 @@
 					}
 
 					if ((holding_session = switch_core_session_locate(holding))) {
-						switch_ivr_session_transfer(holding_session, dest, dialplan, context);
+						switch_channel_t *holding_channel = switch_core_session_get_channel(holding_session);
+						switch_status_t mstatus = SWITCH_STATUS_FALSE;
+						
+						if (caller_channel) {
+							if ((mstatus = switch_channel_caller_extension_masquerade(caller_channel, holding_channel, 1)) == SWITCH_STATUS_SUCCESS) {
+								switch_channel_set_state(holding_channel, CS_RESET);
+								switch_channel_wait_for_state_timeout(holding_channel, CS_RESET, 5000);
+								switch_channel_set_state(holding_channel, CS_EXECUTE);
+							}
+						}
+
+						if (mstatus != SWITCH_STATUS_SUCCESS) {
+							switch_ivr_session_transfer(holding_session, dest, dialplan, context);
+						}
+
 						switch_core_session_rwunlock(holding_session);
 						holding = NULL;
 						holding_session = NULL;
@@ -2233,6 +2253,7 @@
 
 					switch_channel_hangup(peer_channel, SWITCH_CAUSE_ATTENDED_TRANSFER);
 					switch_core_session_rwunlock(peer_session);
+					force_reason = SWITCH_CAUSE_ATTENDED_TRANSFER;
 				} else {
 					if (peer_channel && switch_channel_ready(peer_channel)) {
 						force_reason = SWITCH_CAUSE_ATTENDED_TRANSFER;
@@ -2273,9 +2294,7 @@
 				if (i != oglobals.idx) {
 					holding = NULL;
 
-					if (force_reason != SWITCH_CAUSE_NONE) {
-						reason = force_reason;
-					} else if (oglobals.idx == IDX_TIMEOUT || to) {
+					if (oglobals.idx == IDX_TIMEOUT || to) {
 						reason = SWITCH_CAUSE_NO_ANSWER;
 					} else {
 						if (oglobals.idx == IDX_CANCEL) {
@@ -2437,6 +2456,8 @@
 					switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(oglobals.session), SWITCH_LOG_DEBUG,
 									  "Originate Cancelled by originator termination Cause: %d [%s]\n", *cause, switch_channel_cause2str(*cause));
 
+				} else if (oglobals.idx == IDX_TIMEOUT) {
+					*cause = SWITCH_CAUSE_NO_ANSWER;
 				} else {
 					switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(oglobals.session), SWITCH_LOG_DEBUG,
 									  "Originate Resulted in Error Cause: %d [%s]\n", *cause, switch_channel_cause2str(*cause));
@@ -2561,6 +2582,10 @@
 		switch_channel_clear_flag(caller_channel, CF_XFER_ZOMBIE);
 	}
 
+	if (force_reason != SWITCH_CAUSE_NONE) {
+		*cause = force_reason;
+	}
+
 	return status;
 }