fix att-xfer...AGAIN

git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@15133 d0543943-73ff-0310-b7d9-9358b9ac24b2
This commit is contained in:
Anthony Minessale 2009-10-09 20:48:24 +00:00
parent e6ea90cebf
commit 7681f944b4
5 changed files with 107 additions and 14 deletions

View File

@ -262,6 +262,9 @@ SWITCH_DECLARE(switch_event_header_t *) switch_channel_variable_first(switch_cha
*/
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

View File

@ -4272,9 +4272,7 @@ void sofia_handle_sip_i_refer(nua_t *nua, sofia_profile_t *profile, nua_handle_t
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;
@ -4307,8 +4305,8 @@ void sofia_handle_sip_i_refer(nua_t *nua, sofia_profile_t *profile, nua_handle_t
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\""),

View File

@ -1664,6 +1664,72 @@ SWITCH_DECLARE(void) switch_channel_clear_state_handler(switch_channel_t *channe
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);

View File

@ -569,7 +569,8 @@ static switch_status_t audio_bridge_on_exchange_media(switch_core_session_t *ses
} 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 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_multi_threaded_bridge(switch_core_ses
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))) {

View File

@ -2078,6 +2078,9 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_originate(switch_core_session_t *sess
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 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_originate(switch_core_session_t *sess
}
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 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_originate(switch_core_session_t *sess
}
}
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 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_originate(switch_core_session_t *sess
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 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_originate(switch_core_session_t *sess
}
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_DECLARE(switch_status_t) switch_ivr_originate(switch_core_session_t *sess
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 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_originate(switch_core_session_t *sess
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_DECLARE(switch_status_t) switch_ivr_originate(switch_core_session_t *sess
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_DECLARE(switch_status_t) switch_ivr_originate(switch_core_session_t *sess
switch_channel_clear_flag(caller_channel, CF_XFER_ZOMBIE);
}
if (force_reason != SWITCH_CAUSE_NONE) {
*cause = force_reason;
}
return status;
}