]> git.ipfire.org Git - thirdparty/freeswitch.git/commitdiff
fix att-xfer...AGAIN
authorAnthony Minessale <anthony.minessale@gmail.com>
Fri, 9 Oct 2009 20:48:24 +0000 (20:48 +0000)
committerAnthony Minessale <anthony.minessale@gmail.com>
Fri, 9 Oct 2009 20:48:24 +0000 (20:48 +0000)
git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@15133 d0543943-73ff-0310-b7d9-9358b9ac24b2

src/include/switch_channel.h
src/mod/endpoints/mod_sofia/sofia.c
src/switch_channel.c
src/switch_ivr_bridge.c
src/switch_ivr_originate.c

index c4d4e6d12b9e87c5fd26ad72561675f0e2a63352..8a7a80e908245edf16be330caa021e1dbc9624d6 100644 (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
index 5ec7e03b79b8c9716ed2b1b4db8b785fe208b72c..0c281cfd48a6a12bcfb82ad65d05fba9c64e7c72 100644 (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\""),
index fe7b02e1cef0dc38eb992c17ec839090fdf4217d..acefb6ed815c90dacac0a5f473c80a086bc4ebcf 100644 (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);
index 8f9cba49d12716b63a6f8b4bbc86139a71fa9fad..66667cea2a19873005a42d557e3f37f14beebdfe 100644 (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))) {
index 5b7c3a9a57fd308b5c74c8c447c398dda12a4d97..218098e510b3167fd9743ca2f7c6bcf838fdc6b9 100644 (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;
 }