]> git.ipfire.org Git - thirdparty/freeswitch.git/commitdiff
Insane amounts of yucky satanic code to make transfer and that kind of thing work.
authorAnthony Minessale <anthony.minessale@gmail.com>
Fri, 6 Oct 2006 22:39:49 +0000 (22:39 +0000)
committerAnthony Minessale <anthony.minessale@gmail.com>
Fri, 6 Oct 2006 22:39:49 +0000 (22:39 +0000)
Transfers work better when both legs of the call live in thier own channel eg bridged calls
A -> B where you want a to make B -> C

when you route a call to an IVR or playback app you are not really bridging you have
A all alone executing the script so it's hard to transfer that.

I do have it aparently working but it's goofy and you are better off
putting your IVR on it's own switch so they are all inbound calls
then you have A -> B -> IVR
now A can happily transfer B who can stay on line with IVR without stopping
the execution.  You can also accomplish this by calling in a loop back to the same box
if you dont want to have 2 boxes.

Also the beginning effort at bridging calls with no media is here
set this magic variable in your dialplan to convince mod_sofia
to pass A's sdp as it's own to B and return B's sdp back to A on 200 or 183

<action application="set" data="no_media=true"/>
<action application="bridge" data="sofia/id@host.com"/>

You will need a new sofia tarball for this version

There is a bunch of other odds and ends added like a function or 2 etc
Oh,

And don't be suprised if it introduces all kinds of bugs!

git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@2992 d0543943-73ff-0310-b7d9-9358b9ac24b2

src/include/switch_ivr.h
src/include/switch_types.h
src/include/switch_utils.h
src/mod/applications/mod_bridgecall/mod_bridgecall.c
src/mod/endpoints/mod_sofia/mod_sofia.c
src/switch_caller.c
src/switch_console.c
src/switch_core.c
src/switch_ivr.c
src/switch_rtp.c
src/switch_utils.c

index eb472da44b9983fda0a943e8f87df0d94aa09e6e..7c6b6d819d190f1c6fbb62305fa7b4f8d27a9d5c 100644 (file)
@@ -223,6 +223,13 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_multi_threaded_bridge(switch_core_ses
                                                                                                                                 void *session_data,
                                                                                                                                 void *peer_session_data);
 
+/*!
+  \brief Bridge Signalling from one session to another
+  \param session one session
+  \param peer_session the other session
+  \return SWITCH_STATUS_SUCCESS if all is well
+*/
+SWITCH_DECLARE(switch_status_t) switch_ivr_signal_bridge(switch_core_session_t *session, switch_core_session_t *peer_session);
 
 /*!
   \brief Transfer an existing session to another location
index 9ccf83188688320200218f54aab767038ad0df11..81ff52de7ce453179002566f85bd51cb366e7f1e 100644 (file)
@@ -72,6 +72,11 @@ SWITCH_BEGIN_EXTERN_C
 #define SWITCH_HTDOCS_DIR SWITCH_PREFIX_DIR SWITCH_PATH_SEPARATOR "htdocs"
 #endif
 
+#define SWITCH_R_SDP_VARIABLE "_switch_r_sdp_"
+#define SWITCH_L_SDP_VARIABLE "_switch_l_sdp_"
+#define SWITCH_BRIDGE_VARIABLE "BRIDGETO"
+#define SWITCH_SIGNAL_BRIDGE_VARIABLE "SIGNAL_BRIDGETO"
+
 #define SWITCH_BITS_PER_BYTE 8
 typedef uint8_t switch_byte_t;
 
@@ -232,7 +237,8 @@ typedef enum {
        SWITCH_MESSAGE_TRANSMIT_TEXT      - A text message
        SWITCH_MESSAGE_INDICATE_PROGRESS  - indicate progress 
        SWITCH_MESSAGE_INDICATE_BRIDGE    - indicate a bridge starting
-       SWITCH_MESSAGE_INDICATE_UNBRIDGE    - indicate a bridge ending
+       SWITCH_MESSAGE_INDICATE_UNBRIDGE  - indicate a bridge ending
+       SWITCH_MESSAGE_INDICATE_TRANSFER  - indicate a transfer is taking place
 </pre>
  */
 typedef enum {
@@ -240,7 +246,8 @@ typedef enum {
        SWITCH_MESSAGE_TRANSMIT_TEXT,
        SWITCH_MESSAGE_INDICATE_PROGRESS,
        SWITCH_MESSAGE_INDICATE_BRIDGE,
-       SWITCH_MESSAGE_INDICATE_UNBRIDGE
+       SWITCH_MESSAGE_INDICATE_UNBRIDGE,
+       SWITCH_MESSAGE_INDICATE_TRANSFER
 } switch_core_session_message_types_t;
 
 
@@ -392,6 +399,7 @@ CF_SERVICE          = (1 <<  9) - Channel has a service thread
 CF_TAGGED              = (1 << 10) - Channel is tagged
 CF_WINNER              = (1 << 11) - Channel is the winner
 CF_CONTROLLED  = (1 << 12) - Channel is under control
+CF_NOMEDIA             = (1 << 13) - Channel has no media
 </pre>
  */
 
@@ -408,7 +416,8 @@ typedef enum {
        CF_SERVICE              = (1 <<  9),
        CF_TAGGED               = (1 << 10),
        CF_WINNER               = (1 << 11),
-       CF_CONTROLLED   = (1 << 12)
+       CF_CONTROLLED   = (1 << 12),
+       CF_NOMEDIA              = (1 << 13)
 } switch_channel_flag_t;
 
 
index 02cb144507de0016a5f4df1c8ed179632c3209b8..10286a1d5dbe36c89b346b50e8a9fbf91e805c59 100644 (file)
@@ -192,6 +192,16 @@ if (vname) {free(vname); vname = NULL;}vname = strdup(string);}
 */
 SWITCH_DECLARE(unsigned int) switch_separate_string(char *buf, char delim, char **array, int arraylen);
 
+/*!
+  \brief Escape a string by prefixing a list of characters with an escape character
+  \param pool a memory pool to use
+  \param in the string
+  \param delim the list of characters to escape
+  \param esc the escape character
+  \return the escaped string
+*/
+SWITCH_DECLARE(char *) switch_escape_char(switch_memory_pool_t *pool, char *in, char *delim, char esc);
+
 /*!
   \brief Create a set of file descriptors to poll
   \param poll the polfd to create
index 2fec1c03f02e244a9be2e52bce2470e84b7144c5..89e16549c69588da49e418d1c1266e10ba1226a8 100644 (file)
@@ -51,23 +51,32 @@ static void audio_bridge_function(switch_core_session_t *session, char *data)
                timelimit = atoi(var);
        }
 
+       if ((var = switch_channel_get_variable(caller_channel, "no_media"))) {
+               switch_channel_set_flag(caller_channel, CF_NOMEDIA);            
+       }
+
        if (switch_ivr_originate(session, &peer_session, &cause, data, timelimit, NULL, NULL, NULL, NULL) != SWITCH_STATUS_SUCCESS) {
                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Cannot Create Outgoing Channel!\n");
                /* Hangup the channel with the cause code from the failed originate.*/
                switch_channel_hangup(caller_channel, cause);
                return;
        } else {
-               switch_ivr_multi_threaded_bridge(session, peer_session, NULL, NULL, NULL);
+               if (switch_channel_test_flag(caller_channel, CF_NOMEDIA)) {
+                       switch_ivr_signal_bridge(session, peer_session);                        
+               } else {
+                       switch_ivr_multi_threaded_bridge(session, peer_session, NULL, NULL, NULL);
+               }
        }
 }
 
-
 static const switch_application_interface_t bridge_application_interface = {
        /*.interface_name */ "bridge",
-       /*.application_function */ audio_bridge_function
+       /*.application_function */ audio_bridge_function,
+       /* long_desc */ "Bridge the audio between two sessions",
+       /* short_desc */ "Bridge Audio",
+       /* syntax */ "<channel_url>",
 };
 
-
 static const switch_loadable_module_interface_t mod_bridgecall_module_interface = {
        /*.module_name = */ modname,
        /*.endpoint_interface = */ NULL,
index 18c146fd792c93e540d9b7e021d3504ed59d3274..7ab1e3a6766bdb9537556fb2b4b228d7840dec89 100644 (file)
@@ -62,6 +62,7 @@ typedef struct private_object private_object_t;
 #define MULTICAST_EVENT "multicast::event"
 #define SOFIA_REPLACES_HEADER "_sofia_replaces_"
 
+
 #include <sofia-sip/nua.h>
 #include <sofia-sip/sip_status.h>
 #include <sofia-sip/sdp.h>
@@ -131,7 +132,10 @@ typedef enum {
        TFLAG_TIMER = (1 << 14),
        TFLAG_READY = (1 << 15),
        TFLAG_REINVITE = (1 << 16),
-       TFLAG_REFER = (1 << 17)
+       TFLAG_REFER = (1 << 17),
+       TFLAG_NOHUP = (1 << 18),
+       TFLAG_XFER = (1 << 19),
+       TFLAG_NOMEDIA = (1 << 20)
 } TFLAGS;
 
 static struct {
@@ -250,11 +254,14 @@ struct private_object {
        char *local_sdp_str;
        char *dest;
        char *key;
+       char *xferto;
+       char *kick;
        unsigned long rm_rate;
        switch_payload_t pt;
        switch_mutex_t *flag_mutex;
        switch_payload_t te;
        nua_handle_t *nh;
+       nua_handle_t *nh2;
        su_home_t *home;
        sip_contact_t *contact;
 };
@@ -594,8 +601,10 @@ static void set_local_sdp(private_object_t *tech_pvt)
        char buf[1024];
        switch_time_t now = switch_time_now();
 
-       assert(tech_pvt != NULL);
-       
+       if (switch_test_flag(tech_pvt, TFLAG_NOMEDIA)) {
+               return;
+       }
+
        snprintf(buf, sizeof(buf), 
                         "v=0\n"
                         "o=FreeSWITCH %d%"APR_TIME_T_FMT" %d%"APR_TIME_T_FMT" IN IP4 %s\n"
@@ -653,6 +662,11 @@ static void set_local_sdp(private_object_t *tech_pvt)
 
 static void tech_set_codecs(private_object_t *tech_pvt)
 {
+
+       if (switch_test_flag(tech_pvt, TFLAG_NOMEDIA)) {
+               return;
+       }
+
        if (tech_pvt->num_codecs) {
                return;
        }
@@ -734,11 +748,11 @@ static switch_status_t tech_choose_port(private_object_t *tech_pvt)
        char *ip = tech_pvt->profile->rtpip;
        switch_port_t sdp_port;
        char *err;
-       
-       if (tech_pvt->adv_sdp_audio_port) {
+
+       if (switch_test_flag(tech_pvt, TFLAG_NOMEDIA) || tech_pvt->adv_sdp_audio_port) {
                return SWITCH_STATUS_SUCCESS;
        }
-
+       
        tech_pvt->local_sdp_audio_ip = ip;
        tech_pvt->local_sdp_audio_port = switch_rtp_request_port();
        sdp_port = tech_pvt->local_sdp_audio_port;
@@ -787,6 +801,8 @@ static void do_invite(switch_core_session_t *session)
 
        caller_profile = switch_channel_get_caller_profile(channel);
 
+       
+
        if ((tech_pvt->from_str = switch_core_db_mprintf("\"%s\" <sip:%s@%s>", 
                                                                                                         (char *) caller_profile->caller_id_name, 
                                                                                                         (char *) caller_profile->caller_id_number,
@@ -794,21 +810,75 @@ static void do_invite(switch_core_session_t *session)
                                                                                                         ))) {
 
                char *rep = switch_channel_get_variable(channel, SOFIA_REPLACES_HEADER);
-
+               
                tech_choose_port(tech_pvt);
                set_local_sdp(tech_pvt);
+
                switch_set_flag_locked(tech_pvt, TFLAG_READY);
 
-               tech_pvt->nh = nua_handle(tech_pvt->profile->nua, NULL,
+               if (!tech_pvt->nh) {
+                       tech_pvt->nh = nua_handle(tech_pvt->profile->nua, NULL,
+                                                                         SIPTAG_TO_STR(tech_pvt->dest),
+                                                                         SIPTAG_FROM_STR(tech_pvt->from_str),
+                                                                         SIPTAG_CONTACT_STR(tech_pvt->profile->url),
+                                                                         TAG_END());
+
+                       tech_pvt->sofia_private.session = session;
+                       nua_handle_bind(tech_pvt->nh, &tech_pvt->sofia_private);
+
+               }
+
+               nua_invite(tech_pvt->nh,
+                                  SOATAG_USER_SDP_STR(tech_pvt->local_sdp_str),
+                                  SOATAG_RTP_SORT(SOA_RTP_SORT_REMOTE),
+                                  SOATAG_RTP_SELECT(SOA_RTP_SELECT_ALL),
+                                  TAG_IF(rep, SIPTAG_REPLACES_STR(rep)),
+                                  TAG_END());
+       } else {
+               switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Memory Error!\n");
+       }
+       
+}
+
+
+
+static void do_xfer_invite(switch_core_session_t *session)
+{
+       private_object_t *tech_pvt;
+    switch_channel_t *channel = NULL;
+       switch_caller_profile_t *caller_profile;
+
+    channel = switch_core_session_get_channel(session);
+    assert(channel != NULL);
+
+    tech_pvt = (private_object_t *) switch_core_session_get_private(session);
+    assert(tech_pvt != NULL);
+
+       caller_profile = switch_channel_get_caller_profile(channel);
+
+       
+
+       if ((tech_pvt->from_str = switch_core_db_mprintf("\"%s\" <sip:%s@%s>", 
+                                                                                                        (char *) caller_profile->caller_id_name, 
+                                                                                                        (char *) caller_profile->caller_id_number,
+                                                                                                        tech_pvt->profile->sipip
+                                                                                                        ))) {
+
+               char *rep = switch_channel_get_variable(channel, SOFIA_REPLACES_HEADER);
+               
+
+               tech_pvt->nh2 = nua_handle(tech_pvt->profile->nua, NULL,
                                                                  SIPTAG_TO_STR(tech_pvt->dest),
                                                                  SIPTAG_FROM_STR(tech_pvt->from_str),
                                                                  SIPTAG_CONTACT_STR(tech_pvt->profile->url),
                                                                  TAG_END());
+                       
 
-               tech_pvt->sofia_private.session = session;
-               nua_handle_bind(tech_pvt->nh, &tech_pvt->sofia_private);
-               
-               nua_invite(tech_pvt->nh,
+               nua_handle_bind(tech_pvt->nh2, &tech_pvt->sofia_private);
+
+
+
+               nua_invite(tech_pvt->nh2,
                                   SOATAG_USER_SDP_STR(tech_pvt->local_sdp_str),
                                   SOATAG_RTP_SORT(SOA_RTP_SORT_REMOTE),
                                   SOATAG_RTP_SELECT(SOA_RTP_SELECT_ALL),
@@ -829,6 +899,7 @@ static switch_status_t sofia_on_init(switch_core_session_t *session)
 {
        private_object_t *tech_pvt;
        switch_channel_t *channel = NULL;
+       char *sdp;
 
        channel = switch_core_session_get_channel(session);
        assert(channel != NULL);
@@ -841,6 +912,16 @@ static switch_status_t sofia_on_init(switch_core_session_t *session)
        switch_channel_set_variable(channel, "endpoint_disposition", "INIT");
        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "SOFIA INIT\n");
 
+       if (switch_channel_test_flag(channel, CF_NOMEDIA)) {
+               switch_set_flag_locked(tech_pvt, TFLAG_NOMEDIA);
+       }
+       
+       if ((sdp = switch_channel_get_variable(channel, SWITCH_L_SDP_VARIABLE))) {
+               tech_pvt->local_sdp_str = switch_core_session_strdup(session, sdp);
+               switch_set_flag(tech_pvt, TFLAG_NOMEDIA);
+               switch_channel_set_flag(channel, CF_NOMEDIA);
+       }
+
        if (switch_test_flag(tech_pvt, TFLAG_OUTBOUND)) {
                do_invite(session);
        }
@@ -937,6 +1018,7 @@ static int hangup_cause_to_sip(switch_call_cause_t cause) {
 
 static switch_status_t sofia_on_hangup(switch_core_session_t *session)
 {
+       switch_core_session_t *asession;
        private_object_t *tech_pvt;
        switch_channel_t *channel = NULL;
        switch_call_cause_t cause;
@@ -958,6 +1040,13 @@ static switch_status_t sofia_on_hangup(switch_core_session_t *session)
        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Channel %s hanging up, cause: %s\n", 
                          switch_channel_get_name(channel), switch_channel_cause2str(cause), sip_cause);
 
+
+       if (tech_pvt->kick && (asession = switch_core_session_locate(tech_pvt->kick))) {
+               switch_channel_t *a_channel = switch_core_session_get_channel(asession);
+               switch_channel_hangup(a_channel, switch_channel_get_cause(channel));
+               switch_core_session_rwunlock(asession);
+       }
+
        if (tech_pvt->nh) {
                if (!switch_test_flag(tech_pvt, TFLAG_BYE)) {
                        if (switch_test_flag(tech_pvt, TFLAG_ANS)) {
@@ -1088,6 +1177,9 @@ static switch_status_t activate_rtp(private_object_t *tech_pvt)
        channel = switch_core_session_get_channel(tech_pvt->session);
        assert(channel != NULL);
 
+       if (switch_test_flag(tech_pvt, TFLAG_NOMEDIA)) {
+               return SWITCH_STATUS_SUCCESS;
+       }
 
        if (switch_rtp_ready(tech_pvt->rtp_session) && !switch_test_flag(tech_pvt, TFLAG_REINVITE)) {
                return SWITCH_STATUS_SUCCESS;
@@ -1168,7 +1260,8 @@ static switch_status_t sofia_answer_channel(switch_core_session_t *session)
 {
        private_object_t *tech_pvt;
        switch_channel_t *channel = NULL;
-
+       char *sdp;
+       
        assert(session != NULL);
 
        channel = switch_core_session_get_channel(session);
@@ -1177,13 +1270,25 @@ static switch_status_t sofia_answer_channel(switch_core_session_t *session)
        tech_pvt = (private_object_t *) switch_core_session_get_private(session);
        assert(tech_pvt != NULL);
 
+       if ((sdp = switch_channel_get_variable(channel, SWITCH_L_SDP_VARIABLE))) {
+               tech_pvt->local_sdp_str = switch_core_session_strdup(session, sdp);
+               switch_set_flag(tech_pvt, TFLAG_NOMEDIA);
+               switch_channel_set_flag(channel, CF_NOMEDIA);
+       }
+
+
        if (!switch_test_flag(tech_pvt, TFLAG_ANS) && !switch_channel_test_flag(channel, CF_OUTBOUND)) {
                switch_set_flag_locked(tech_pvt, TFLAG_ANS);
+
+
                tech_choose_port(tech_pvt);
                set_local_sdp(tech_pvt);
                activate_rtp(tech_pvt);
+               
                if (tech_pvt->nh) {
-                       switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Local SDP:\n%s\n", tech_pvt->local_sdp_str);
+                       switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Local SDP %s:\n%s\n",
+                                                         switch_channel_get_name(channel),
+                                                         tech_pvt->local_sdp_str);
                        nua_respond(tech_pvt->nh, SIP_200_OK, 
                                                SOATAG_USER_SDP_STR(tech_pvt->local_sdp_str),
                                                SOATAG_AUDIO_AUX("cn telephone-event"),
@@ -1203,10 +1308,6 @@ static switch_status_t sofia_read_frame(switch_core_session_t *session, switch_f
        switch_channel_t *channel = NULL;
        int payload = 0;
 
-       //switch_time_t now, started = switch_time_now(), last_act = switch_time_now();
-       //unsigned int elapsed;
-       //uint32_t hard_timeout = 60000 * 3;
-
        channel = switch_core_session_get_channel(session);
        assert(channel != NULL);
 
@@ -1246,7 +1347,6 @@ static switch_status_t sofia_read_frame(switch_core_session_t *session, switch_f
 
 
                while (!switch_test_flag(tech_pvt, TFLAG_BYE) && switch_test_flag(tech_pvt, TFLAG_IO) && tech_pvt->read_frame.datalen == 0) {
-                       //now = switch_time_now();
                        tech_pvt->read_frame.flags = SFF_NONE;
 
                        status = switch_rtp_zerocopy_read_frame(tech_pvt->rtp_session, &tech_pvt->read_frame);
@@ -1448,6 +1548,34 @@ static switch_status_t sofia_receive_message(switch_core_session_t *session, swi
 
        switch (msg->message_id) {
        case SWITCH_MESSAGE_INDICATE_BRIDGE:
+
+               if (switch_test_flag(tech_pvt, TFLAG_XFER)) {
+                       switch_clear_flag_locked(tech_pvt, TFLAG_XFER);
+                       if (msg->pointer_arg) {
+                               switch_core_session_t *asession, *bsession = msg->pointer_arg;
+
+                               if ((asession = switch_core_session_locate(tech_pvt->xferto))) {
+                                       private_object_t *a_tech_pvt = switch_core_session_get_private(asession);
+                                       private_object_t *b_tech_pvt = switch_core_session_get_private(bsession);
+
+                                       switch_set_flag_locked(a_tech_pvt, TFLAG_REINVITE);
+                                       a_tech_pvt->remote_sdp_audio_ip = switch_core_session_strdup(asession, b_tech_pvt->remote_sdp_audio_ip);
+                                       a_tech_pvt->remote_sdp_audio_port = b_tech_pvt->remote_sdp_audio_port;
+                                       a_tech_pvt->local_sdp_audio_ip = switch_core_session_strdup(asession, b_tech_pvt->local_sdp_audio_ip);
+                                       a_tech_pvt->local_sdp_audio_port = b_tech_pvt->local_sdp_audio_port;
+                                       activate_rtp(a_tech_pvt);
+                                       
+                                       b_tech_pvt->kick = switch_core_session_strdup(bsession, tech_pvt->xferto);
+                                       
+
+                                       switch_core_session_rwunlock(asession);
+                               }
+
+
+                               msg->pointer_arg = NULL;
+                               return SWITCH_STATUS_FALSE;
+                       }
+               }
                if (tech_pvt->rtp_session && switch_test_flag(tech_pvt, TFLAG_TIMER)) {
                        switch_rtp_clear_flag(tech_pvt->rtp_session, SWITCH_RTP_FLAG_USE_TIMER);
                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "De-activate timed RTP!\n");
@@ -1462,17 +1590,26 @@ static switch_status_t sofia_receive_message(switch_core_session_t *session, swi
        case SWITCH_MESSAGE_INDICATE_PROGRESS: {
                struct private_object *tech_pvt;
            switch_channel_t *channel = NULL;
-                 
+               char *sdp;
+
            channel = switch_core_session_get_channel(session);
            assert(channel != NULL);
 
            tech_pvt = switch_core_session_get_private(session);
            assert(tech_pvt != NULL);
-               
+
            if (!switch_test_flag(tech_pvt, TFLAG_EARLY_MEDIA)) {
                        switch_set_flag_locked(tech_pvt, TFLAG_EARLY_MEDIA);
                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Asked to send early media by %s\n", msg->from);
 
+
+                       if ((sdp = switch_channel_get_variable(channel, SWITCH_L_SDP_VARIABLE))) {
+                               tech_pvt->local_sdp_str = switch_core_session_strdup(session, sdp);
+                               switch_set_flag(tech_pvt, TFLAG_NOMEDIA);
+                               switch_channel_set_flag(channel, CF_NOMEDIA);
+                       }
+
+
                        /* Transmit 183 Progress with SDP */
                        tech_choose_port(tech_pvt);
                        set_local_sdp(tech_pvt);
@@ -1540,6 +1677,7 @@ static switch_status_t sofia_outgoing_channel(switch_core_session_t *session, sw
        switch_caller_profile_t *caller_profile = NULL;
        private_object_t *tech_pvt = NULL;
        switch_channel_t *channel;
+       switch_channel_t *nchannel;
        char *host;
 
        *new_session = NULL;
@@ -1586,19 +1724,24 @@ static switch_status_t sofia_outgoing_channel(switch_core_session_t *session, sw
                tech_pvt->dest = switch_core_session_alloc(nsession, strlen(dest) + 5);
                snprintf(tech_pvt->dest, strlen(dest) + 5, "sip:%s", dest);
        }
-
-       channel = switch_core_session_get_channel(nsession);
-       attach_private(nsession, profile, tech_pvt, dest);      
+       attach_private(nsession, profile, tech_pvt, dest);
+       channel = switch_core_session_get_channel(session);
+       nchannel = switch_core_session_get_channel(nsession);
        caller_profile = switch_caller_profile_clone(nsession, outbound_profile);
-       switch_channel_set_caller_profile(channel, caller_profile);
-       switch_channel_set_flag(channel, CF_OUTBOUND);
+       switch_channel_set_caller_profile(nchannel, caller_profile);
+       switch_channel_set_flag(nchannel, CF_OUTBOUND);
        switch_set_flag_locked(tech_pvt, TFLAG_OUTBOUND);
-       switch_channel_set_state(channel, CS_INIT);
-       switch_channel_set_variable(channel, "endpoint_disposition", "OUTBOUND");
+       switch_channel_set_state(nchannel, CS_INIT);
+       switch_channel_set_variable(nchannel, "endpoint_disposition", "OUTBOUND");
        *new_session = nsession;
        status = SWITCH_STATUS_SUCCESS;
        if (session) {
+               char *val;
                switch_ivr_transfer_variable(session, nsession, SOFIA_REPLACES_HEADER);
+
+               if (switch_channel_test_flag(channel, CF_NOMEDIA) && (val = switch_channel_get_variable(channel, SWITCH_R_SDP_VARIABLE))) {
+                       switch_channel_set_variable(nchannel, SWITCH_L_SDP_VARIABLE, val);
+               }
        }
 
  done:
@@ -1723,7 +1866,6 @@ static void sip_i_state(int status,
         
 {
        char const *l_sdp = NULL, *r_sdp = NULL;
-       //int audio = nua_active_inactive, video = nua_active_inactive, chat = nua_active_inactive;
        int offer_recv = 0, answer_recv = 0, offer_sent = 0, answer_sent = 0;
        int ss_state = nua_callstate_init;
        switch_channel_t *channel = NULL;
@@ -1758,6 +1900,7 @@ static void sip_i_state(int status,
                if (r_sdp) {
                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Remote SDP:\n%s\n", r_sdp);                    
                        tech_pvt->remote_sdp_str = switch_core_session_strdup(session, (char *)r_sdp);
+                       switch_channel_set_variable(channel, SWITCH_R_SDP_VARIABLE, (char *) r_sdp);
                }
        }
 
@@ -1772,34 +1915,38 @@ static void sip_i_state(int status,
        case nua_callstate_proceeding:
                if (channel) {
                        if (r_sdp) {
-                               sdp_parser_t *parser = sdp_parse(tech_pvt->home, r_sdp, (int)strlen(r_sdp), 0);
-                               sdp_session_t *sdp;
-                               uint8_t match = 0;
+                               if (switch_test_flag(tech_pvt, TFLAG_NOMEDIA)) {
+                                       switch_channel_pre_answer(channel);
+                                       return;
+                               } else {
+                                       sdp_parser_t *parser = sdp_parse(tech_pvt->home, r_sdp, (int)strlen(r_sdp), 0);
+                                       sdp_session_t *sdp;
+                                       uint8_t match = 0;
 
-                               if (tech_pvt->num_codecs) {
-                                       if ((sdp = sdp_session(parser))) {
-                                               match = negotiate_sdp(session, sdp);
+                                       if (tech_pvt->num_codecs) {
+                                               if ((sdp = sdp_session(parser))) {
+                                                       match = negotiate_sdp(session, sdp);
+                                               }
                                        }
-                               }
 
-                               if (parser) {
-                                       sdp_parser_free(parser);
-                               }
+                                       if (parser) {
+                                               sdp_parser_free(parser);
+                                       }
 
 
-                               if (match) {
-                                       tech_choose_port(tech_pvt);
-                                       activate_rtp(tech_pvt);
-                                       switch_channel_set_variable(channel, "endpoint_disposition", "EARLY MEDIA");
-                                       switch_channel_pre_answer(channel);
-                                       return;
+                                       if (match) {
+                                               tech_choose_port(tech_pvt);
+                                               activate_rtp(tech_pvt);
+                                               switch_channel_set_variable(channel, "endpoint_disposition", "EARLY MEDIA");
+                                               switch_channel_pre_answer(channel);
+                                               return;
+                                       }
+                                       switch_channel_set_variable(channel, "endpoint_disposition", "NO CODECS");
+                                       nua_respond(nh, SIP_488_NOT_ACCEPTABLE, 
+                                                               TAG_END());
                                }
-                               switch_channel_set_variable(channel, "endpoint_disposition", "NO CODECS");
-                               nua_respond(nh, SIP_488_NOT_ACCEPTABLE, 
-                                                       TAG_END());
                        }
                }
-
                break;
        case nua_callstate_completing:
                nua_ack(nh, TAG_END());
@@ -1807,60 +1954,69 @@ static void sip_i_state(int status,
        case nua_callstate_received: 
                if (channel) {
                        if (r_sdp) {
-                               sdp_parser_t *parser = sdp_parse(tech_pvt->home, r_sdp, (int)strlen(r_sdp), 0);
-                               sdp_session_t *sdp;
-                               uint8_t match = 0;
+                               if (switch_test_flag(tech_pvt, TFLAG_NOMEDIA)) {
+                                       switch_channel_set_variable(channel, "endpoint_disposition", "RECEIVED_NOMEDIA");
+                                       switch_channel_set_state(channel, CS_INIT);
+                                       switch_set_flag_locked(tech_pvt, TFLAG_READY);
+                                       switch_core_session_thread_launch(session);
+                                       return;
+                               } else {
+                                       sdp_parser_t *parser = sdp_parse(tech_pvt->home, r_sdp, (int)strlen(r_sdp), 0);
+                                       sdp_session_t *sdp;
+                                       uint8_t match = 0;
                                
-                               if (tech_pvt->num_codecs) {
-                                       if ((sdp = sdp_session(parser))) {
-                                               match = negotiate_sdp(session, sdp);
+                                       if (tech_pvt->num_codecs) {
+                                               if ((sdp = sdp_session(parser))) {
+                                                       match = negotiate_sdp(session, sdp);
+                                               }
                                        }
-                               }
 
-                               if (parser) {
-                                       sdp_parser_free(parser);
-                               }
+                                       if (parser) {
+                                               sdp_parser_free(parser);
+                                       }
 
-                               if (match) {
-                                       nua_handle_t *bnh;
-                                       sip_replaces_t *replaces;
+                                       if (match) {
+                                               nua_handle_t *bnh;
+                                               sip_replaces_t *replaces;
                                        
-                                       switch_channel_set_variable(channel, "endpoint_disposition", "RECEIVED");
-                                       switch_channel_set_state(channel, CS_INIT);
-                                       switch_set_flag_locked(tech_pvt, TFLAG_READY);
-                                       switch_core_session_thread_launch(session);
-
-                                       if (replaces_str && (replaces = sip_replaces_make(tech_pvt->home, replaces_str)) && (bnh = nua_handle_by_replaces(nua, replaces))) {
-                                               sofia_private_t *b_private;
+                                               switch_channel_set_variable(channel, "endpoint_disposition", "RECEIVED");
+                                               switch_channel_set_state(channel, CS_INIT);
+                                               switch_set_flag_locked(tech_pvt, TFLAG_READY);
+                                               switch_core_session_thread_launch(session);
 
-                                               switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Processing Attended Transfer\n");
-                                               while (switch_channel_get_state(channel) < CS_EXECUTE) {
-                                                       switch_yield(10000);
-                                               }
+                                               if (replaces_str && (replaces = sip_replaces_make(tech_pvt->home, replaces_str)) && (bnh = nua_handle_by_replaces(nua, replaces))) {
+                                                       sofia_private_t *b_private;
 
-                                               if ((b_private = nua_handle_fetch(bnh))) {
-                                                       char *br_b = switch_channel_get_variable(channel, "BRIDGETO");
-                                                       char *br_a = switch_core_session_get_uuid(b_private->session);
+                                                       switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Processing Replaces Attended Transfer\n");
+                                                       while (switch_channel_get_state(channel) < CS_EXECUTE) {
+                                                               switch_yield(10000);
+                                                       }
 
-                                                       if (br_b) {
-                                                               switch_ivr_uuid_bridge(br_a, br_b);
-                                                               switch_channel_set_variable(channel, "endpoint_disposition", "ATTENDED_TRANSFER");
-                                                               switch_channel_hangup(channel, SWITCH_CAUSE_ATTENDED_TRANSFER);
+                                                       if ((b_private = nua_handle_fetch(bnh))) {
+                                                               char *br_b = switch_channel_get_variable(channel, SWITCH_BRIDGE_VARIABLE);
+                                                               char *br_a = switch_core_session_get_uuid(b_private->session);
+
+                                                               if (br_b) {
+                                                                       switch_ivr_uuid_bridge(br_a, br_b);
+                                                                       switch_channel_set_variable(channel, "endpoint_disposition", "ATTENDED_TRANSFER");
+                                                                       switch_channel_hangup(channel, SWITCH_CAUSE_ATTENDED_TRANSFER);
+                                                               } else {
+                                                                       switch_channel_set_variable(channel, "endpoint_disposition", "ATTENDED_TRANSFER_ERROR");
+                                                                       switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER);
+                                                               }
                                                        } else {
                                                                switch_channel_set_variable(channel, "endpoint_disposition", "ATTENDED_TRANSFER_ERROR");
                                                                switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER);
                                                        }
-                                               } else {
-                                                       switch_channel_set_variable(channel, "endpoint_disposition", "ATTENDED_TRANSFER_ERROR");
-                                                       switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER);
+                                                       nua_handle_unref(bnh);
                                                }
+                                               return;
                                        }
-                                       return;
-                               }
 
-                               switch_channel_set_variable(channel, "endpoint_disposition", "NO CODECS");
-                               nua_respond(nh, SIP_488_NOT_ACCEPTABLE, 
-                                                       TAG_END());
+                                       switch_channel_set_variable(channel, "endpoint_disposition", "NO CODECS");
+                                       nua_respond(nh, SIP_488_NOT_ACCEPTABLE, 
+                                                               TAG_END());
+                               }
                        }
                }
 
@@ -1869,76 +2025,103 @@ static void sip_i_state(int status,
                break;
        case nua_callstate_completed:
                if (tech_pvt && r_sdp) {
-                       sdp_parser_t *parser = sdp_parse(tech_pvt->home, r_sdp, (int)strlen(r_sdp), 0);
-                       sdp_session_t *sdp;
-                       uint8_t match = 0;
+                       if (r_sdp) {
+                               if (switch_test_flag(tech_pvt, TFLAG_NOMEDIA)) {
+                                       switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "What should i do?\n%s\n", r_sdp);
+                                       return;
+                               } else {
+                                       sdp_parser_t *parser = sdp_parse(tech_pvt->home, r_sdp, (int)strlen(r_sdp), 0);
+                                       sdp_session_t *sdp;
+                                       uint8_t match = 0;
 
-                       if (tech_pvt->num_codecs) {
-                               if ((sdp = sdp_session(parser))) {
-                                       match = negotiate_sdp(session, sdp);
+                                       if (tech_pvt->num_codecs) {
+                                               if ((sdp = sdp_session(parser))) {
+                                                       match = negotiate_sdp(session, sdp);
+                                               }
+                                       }
+                                       tech_choose_port(tech_pvt);
+                                       set_local_sdp(tech_pvt);
+                                       tech_set_codec(tech_pvt);
+                                       switch_set_flag_locked(tech_pvt, TFLAG_REINVITE);
+                                       activate_rtp(tech_pvt);
+                                       switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Processing Reinvite\n");
+                                       if (parser) {
+                                               sdp_parser_free(parser);
+                                       }
                                }
                        }
-                       tech_choose_port(tech_pvt);
-                       set_local_sdp(tech_pvt);
-                       tech_set_codec(tech_pvt);
-                       switch_set_flag_locked(tech_pvt, TFLAG_REINVITE);
-                       activate_rtp(tech_pvt);
-                       switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Processing Reinvite\n");
-                       if (parser) {
-                               sdp_parser_free(parser);
-                       }
                }
                break;
        case nua_callstate_ready:
+               if (nh == tech_pvt->nh2) {
+                       switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Cheater Reinvite!\n");
+                       switch_set_flag_locked(tech_pvt, TFLAG_REINVITE);
+                       tech_pvt->nh = tech_pvt->nh2;
+                       tech_pvt->nh2 = NULL;
+                       tech_choose_port(tech_pvt);
+                       activate_rtp(tech_pvt);
+                       return;
+               }
+
                if (channel) {
                        if (r_sdp) {
-                               sdp_parser_t *parser = sdp_parse(tech_pvt->home, r_sdp, (int)strlen(r_sdp), 0);
-                               sdp_session_t *sdp;
-                               uint8_t match = 0;
+                               if (switch_test_flag(tech_pvt, TFLAG_NOMEDIA)) {
+                                       switch_set_flag_locked(tech_pvt, TFLAG_ANS);
+                                       switch_channel_answer(channel);
+                                       return;
+                               } else {
+                                       sdp_parser_t *parser = sdp_parse(tech_pvt->home, r_sdp, (int)strlen(r_sdp), 0);
+                                       sdp_session_t *sdp;
+                                       uint8_t match = 0;
 
-                               if (tech_pvt->num_codecs) {
-                                       if ((sdp = sdp_session(parser))) {
-                                               match = negotiate_sdp(session, sdp);
+                                       if (tech_pvt->num_codecs) {
+                                               if ((sdp = sdp_session(parser))) {
+                                                       match = negotiate_sdp(session, sdp);
+                                               }
                                        }
-                               }
 
-                               if (parser) {
-                                       sdp_parser_free(parser);
-                               }
+                                       if (parser) {
+                                               sdp_parser_free(parser);
+                                       }
 
 
-                               if (match) {
-                                       switch_set_flag_locked(tech_pvt, TFLAG_ANS);
-                                       switch_channel_set_variable(channel, "endpoint_disposition", "ANSWER");
-                                       tech_choose_port(tech_pvt);
-                                       activate_rtp(tech_pvt);
-                                       switch_channel_answer(channel);
-                                       return;
+                                       if (match) {
+                                               switch_set_flag_locked(tech_pvt, TFLAG_ANS);
+                                               switch_channel_set_variable(channel, "endpoint_disposition", "ANSWER");
+                                               tech_choose_port(tech_pvt);
+                                               activate_rtp(tech_pvt);
+                                               switch_channel_answer(channel);
+                                               return;
+                                       }
+                                       
+                                       switch_channel_set_variable(channel, "endpoint_disposition", "NO CODECS");
+                                       nua_respond(nh, SIP_488_NOT_ACCEPTABLE, TAG_END());
                                }
-
-                               switch_channel_set_variable(channel, "endpoint_disposition", "NO CODECS");
-                               nua_respond(nh, SIP_488_NOT_ACCEPTABLE, 
-                                                       TAG_END());
                        } else if (switch_test_flag(tech_pvt, TFLAG_EARLY_MEDIA)) {
                                switch_set_flag_locked(tech_pvt, TFLAG_ANS);
                                switch_channel_set_variable(channel, "endpoint_disposition", "ANSWER");
                                switch_channel_answer(channel);
                                return;
                        } //else probably an ack
-
                }
-
+               
                break;
        case nua_callstate_terminating:
                break;
-       case nua_callstate_terminated:
+       case nua_callstate_terminated: 
                if (session) {
                        switch_set_flag_locked(tech_pvt, TFLAG_BYE);
-                       terminate_session(&session, sip_cause_to_freeswitch(status), __LINE__);
+                       if (switch_test_flag(tech_pvt, TFLAG_NOHUP)) {
+                               switch_clear_flag_locked(tech_pvt, TFLAG_NOHUP);
+                               nua_handle_destroy(tech_pvt->nh);
+                               tech_pvt->nh = NULL;
+                       } else {
+                               terminate_session(&session, sip_cause_to_freeswitch(status), __LINE__);
+                       }
                }
                break;
        }
-
+       
 
 }
 
@@ -2235,9 +2418,27 @@ static void sip_i_refer(nua_t *nua,
 
        if (session) {
                private_object_t *tech_pvt = NULL;
-               char *exten = NULL;
+               char *etmp = NULL, *exten = NULL;
+               switch_channel_t *channel_a = NULL, *channel_b = NULL;
 
                tech_pvt = switch_core_session_get_private(session);
+               channel_a = switch_core_session_get_channel(session);
+
+               
+               if (!sip->sip_cseq || !(etmp = switch_core_db_mprintf("refer;id=%u", sip->sip_cseq->cs_seq))) {
+                       switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Memory Error!\n");
+                       goto done;
+               }
+
+
+               if (switch_channel_test_flag(channel_a, CF_NOMEDIA)) {
+                       nua_notify(tech_pvt->nh, SIPTAG_CONTENT_TYPE_STR("message/sipfrag"),
+                                          SIPTAG_PAYLOAD_STR("SIP/2.0 403 Forbidden"),
+                                          SIPTAG_EVENT_STR(etmp),
+                                          TAG_END());
+                       goto done;
+               }
+               
                from = sip->sip_from;
                to = sip->sip_to;
 
@@ -2256,12 +2457,11 @@ static void sip_i_refer(nua_t *nua,
                                char *rep;
 
                                if ((rep = strchr(refer_to->r_url->url_headers, '='))) {
-                                       switch_channel_t *channel_a = NULL, *channel_b = NULL;
                                        char *br_a = NULL, *br_b = NULL;
                                        char *buf;
                                        rep++;
 
-                                       channel_a = switch_core_session_get_channel(session);
+                                       
 
                                        if ((buf = switch_core_session_alloc(session, strlen(rep) + 1))) {
                                                rep = url_unescape(buf, (const char *) rep); 
@@ -2272,45 +2472,86 @@ static void sip_i_refer(nua_t *nua,
                                        }
                                        if ((replaces = sip_replaces_make(tech_pvt->home, rep)) && (bnh = nua_handle_by_replaces(nua, replaces))) {
                                                sofia_private_t *b_private;
-                                               
+                                       
+                                               switch_channel_set_variable(channel_a, SOFIA_REPLACES_HEADER, rep);     
                                                if ((b_private = nua_handle_fetch(bnh))) {
                                                        channel_b = switch_core_session_get_channel(b_private->session);
                                
-                                                       br_a = switch_channel_get_variable(channel_a, "BRIDGETO");
-                                                       br_b = switch_channel_get_variable(channel_b, "BRIDGETO");
+                                                       br_a = switch_channel_get_variable(channel_a, SWITCH_BRIDGE_VARIABLE);
+                                                       br_b = switch_channel_get_variable(channel_b, SWITCH_BRIDGE_VARIABLE);
 
                                                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Attended Transfer [%s][%s]\n", br_a, br_b);
 
                                                        if (br_a && br_b) {
                                                                switch_ivr_uuid_bridge(br_a, br_b);
                                                                switch_channel_set_variable(channel_b, "endpoint_disposition", "ATTENDED_TRANSFER");
-                                                               switch_channel_hangup(channel_b, SWITCH_CAUSE_ATTENDED_TRANSFER);
-                                                               switch_channel_set_variable(channel_a, "endpoint_disposition", "ATTENDED_TRANSFER");
-                                                               switch_channel_hangup(channel_a, SWITCH_CAUSE_ATTENDED_TRANSFER);
+                                                                       
+                                                               nua_notify(tech_pvt->nh, SIPTAG_CONTENT_TYPE_STR("message/sipfrag"),
+                                                                                  SIPTAG_PAYLOAD_STR("SIP/2.0 200 OK"),
+                                                                                  SIPTAG_EVENT_STR(etmp),
+                                                                                  TAG_END());
+                                                               
                                                        } else {
-                                                               switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid Transfer! [%s][%s]\n", br_a, br_b);
-                                                               switch_channel_set_variable(channel_b, "endpoint_disposition", "ATTENDED_TRANSFER_ERROR");
-                                                               switch_channel_hangup(channel_b, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER);
-                                                               switch_channel_set_variable(channel_a, "endpoint_disposition", "ATTENDED_TRANSFER_ERROR");
-                                                               switch_channel_hangup(channel_a, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER);
+                                                               private_object_t *tech_pvt_b = (private_object_t *) switch_core_session_get_private(b_private->session);
+
+                                                               if (!br_a && !br_b) {
+                                                                       switch_set_flag_locked(tech_pvt, TFLAG_NOHUP);
+                                                                       switch_set_flag_locked(tech_pvt_b, TFLAG_XFER);
+                                                                       tech_pvt_b->xferto = switch_core_session_strdup(b_private->session, switch_core_session_get_uuid(session));
+                                                               } else if (!br_a && br_b) {
+                                                                       switch_core_session_t *bsession;
+
+                                                                       if ((bsession = switch_core_session_locate(br_b))) {
+                                                                               private_object_t *b_tech_pvt = switch_core_session_get_private(bsession);
+                                                                               switch_channel_t *b_channel = switch_core_session_get_channel(bsession);
+                                                                               private_object_t *bp_tech_pvt = switch_core_session_get_private(b_private->session);
+
+                                                                               switch_core_session_get_uuid(b_private->session);
+                                                                               switch_set_flag_locked(tech_pvt, TFLAG_NOHUP);
+                                                                               
+                                                                               switch_channel_clear_state_handler(b_channel, NULL);
+                                                                               switch_channel_set_state_flag(b_channel, CF_TRANSFER);
+                                                                               switch_channel_set_state(b_channel, CS_TRANSMIT);
+
+                                                                               switch_set_flag_locked(tech_pvt, TFLAG_REINVITE);
+                                                                               tech_pvt->local_sdp_audio_ip = switch_core_session_strdup(session, bp_tech_pvt->local_sdp_audio_ip);
+                                                                               tech_pvt->local_sdp_audio_port = bp_tech_pvt->local_sdp_audio_port;
+
+                                                                               tech_pvt->remote_sdp_audio_ip = switch_core_session_strdup(session, b_tech_pvt->remote_sdp_audio_ip);
+                                                                               tech_pvt->remote_sdp_audio_port = b_tech_pvt->remote_sdp_audio_port;
+                                                                               activate_rtp(tech_pvt);
+       
+                                                                               b_tech_pvt->kick = switch_core_session_strdup(bsession, switch_core_session_get_uuid(session));
+                                                                               
+
+                                                                               switch_core_session_rwunlock(bsession);
+                                                                       }
+
+                                                                       switch_channel_hangup(channel_b, SWITCH_CAUSE_ATTENDED_TRANSFER);
+                                                               }
+
+                                                               nua_notify(tech_pvt->nh, SIPTAG_CONTENT_TYPE_STR("message/sipfrag"),
+                                                                                  SIPTAG_PAYLOAD_STR("SIP/2.0 200 OK"),
+                                                                                  SIPTAG_EVENT_STR(etmp),
+                                                                                  TAG_END());
+
                                                        }
                                                }
-                                       
                                                nua_handle_unref(bnh);
                                        } else { /* the other channel is on a different box, we have to go find them */
-                                               if (exten && (br_a = switch_channel_get_variable(channel_a, "BRIDGETO"))) {
-                                                       switch_core_session_t *bsession;
+                                               if (exten && (br_a = switch_channel_get_variable(channel_a, SWITCH_BRIDGE_VARIABLE))) {
+                                                       switch_core_session_t *asession;
                                                        switch_channel_t *channel = switch_core_session_get_channel(session);
                                                        
-                                                       if ((bsession = switch_core_session_locate(br_a))) {
+                                                       if ((asession = switch_core_session_locate(br_a))) {
                                                                switch_core_session_t *tsession;
                                                                switch_call_cause_t cause = SWITCH_CAUSE_NORMAL_CLEARING;
                                                                uint32_t timeout = 60;
                                                                char *tuuid_str;
 
-                                                               channel = switch_core_session_get_channel(bsession);
+                                                               channel = switch_core_session_get_channel(asession);
 
-                                                               exten = switch_core_db_mprintf("sofia/%s/%s@%s:%d", 
+                                                               exten = switch_core_db_mprintf("sofia/%s/%s@%s:%s", 
                                                                                                                           profile->name,
                                                                                                                           (char *) refer_to->r_url->url_user,
                                                                                                                           (char *) refer_to->r_url->url_host,
@@ -2319,7 +2560,7 @@ static void sip_i_refer(nua_t *nua,
 
                                                                switch_channel_set_variable(channel, SOFIA_REPLACES_HEADER, rep);
                                                                
-                                                               if (switch_ivr_originate(bsession,
+                                                               if (switch_ivr_originate(asession,
                                                                                                                 &tsession,
                                                                                                                 &cause,
                                                                                                                 exten,
@@ -2329,14 +2570,21 @@ static void sip_i_refer(nua_t *nua,
                                                                                                                 NULL,
                                                                                                                 NULL) != SWITCH_STATUS_SUCCESS) {
                                                                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Cannot Create Outgoing Channel! [%s]\n", exten);
+                                                                       nua_notify(tech_pvt->nh, SIPTAG_CONTENT_TYPE_STR("message/sipfrag"),
+                                                                                          SIPTAG_PAYLOAD_STR("SIP/2.0 403 Forbidden"),
+                                                                                          SIPTAG_EVENT_STR(etmp),
+                                                                                          TAG_END());
                                                                        goto done;
                                                                } 
 
-                                                               switch_core_session_rwunlock(bsession);
+                                                               switch_core_session_rwunlock(asession);
                                                                tuuid_str = switch_core_session_get_uuid(tsession);
                                                                switch_ivr_uuid_bridge(br_a, tuuid_str);
                                                                switch_channel_set_variable(channel_a, "endpoint_disposition", "ATTENDED_TRANSFER");
-                                                               switch_channel_hangup(channel_a, SWITCH_CAUSE_ATTENDED_TRANSFER);
+                                                               nua_notify(tech_pvt->nh, SIPTAG_CONTENT_TYPE_STR("message/sipfrag"),
+                                                                                  SIPTAG_PAYLOAD_STR("SIP/2.0 200 OK"),
+                                                                                  SIPTAG_EVENT_STR(etmp),
+                                                                                  TAG_END());
                                                        } else {
                                                                goto error;
                                                        }
@@ -2344,7 +2592,10 @@ static void sip_i_refer(nua_t *nua,
                                                } else { error:
                                                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid Transfer! [%s]\n", br_a);
                                                        switch_channel_set_variable(channel_a, "endpoint_disposition", "ATTENDED_TRANSFER_ERROR");
-                                                       switch_channel_hangup(channel_a, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER);
+                                                       nua_notify(tech_pvt->nh, SIPTAG_CONTENT_TYPE_STR("message/sipfrag"),
+                                                                          SIPTAG_PAYLOAD_STR("SIP/2.0 403 Forbidden"),
+                                                                          SIPTAG_EVENT_STR(etmp),
+                                                                          TAG_END());
                                                }
                                        }
                                } else {
@@ -2362,26 +2613,50 @@ static void sip_i_refer(nua_t *nua,
                        switch_channel_t *channel = switch_core_session_get_channel(session);
                        char *br;
                                
-                       switch_channel_set_variable(channel, "endpoint_disposition", "BLIND_TRANSFER");
-                       switch_channel_hangup(channel, SWITCH_CAUSE_BLIND_TRANSFER);
-
-                       if ((br = switch_channel_get_variable(channel, "BRIDGETO"))) {
+                       if ((br = switch_channel_get_variable(channel, SWITCH_BRIDGE_VARIABLE))) {
                                switch_core_session_t *bsession;
-                                       
+                               
                                if ((bsession = switch_core_session_locate(br))) {
                                        channel = switch_core_session_get_channel(bsession);
                                        switch_channel_set_variable(channel, "TRANSFER_FALLBACK", (char *) from->a_user);
                                        switch_ivr_session_transfer(bsession, exten, profile->dialplan, profile->context);
                                        switch_core_session_rwunlock(bsession);
                                } 
-                       }
                                
+                               switch_channel_set_variable(channel, "endpoint_disposition", "BLIND_TRANSFER");
+                               
+                               nua_notify(tech_pvt->nh, SIPTAG_CONTENT_TYPE_STR("message/sipfrag"),
+                                                  SIPTAG_PAYLOAD_STR("SIP/2.0 200 OK"),
+                                                  SIPTAG_EVENT_STR(etmp),
+                                                  TAG_END());
+                       } else {
+                               exten = switch_core_db_mprintf("sip:%s@%s:%s", 
+                                                                                          (char *) refer_to->r_url->url_user,
+                                                                                          (char *) refer_to->r_url->url_host,
+                                                                                          refer_to->r_url->url_port);
+                               tech_pvt->dest = switch_core_session_strdup(session, exten);
+                               
+                               
+                               switch_set_flag_locked(tech_pvt, TFLAG_NOHUP);
+
+
+                               nua_notify(tech_pvt->nh, SIPTAG_CONTENT_TYPE_STR("message/sipfrag"),
+                                                  SIPTAG_PAYLOAD_STR("SIP/2.0 200 OK"),
+                                                  SIPTAG_EVENT_STR(etmp),
+                                                  TAG_END());
+
+                               do_xfer_invite(session);
+
+                       }
                }
 
        done:
-               if (strchr(exten, '@')) {
+               if (exten && strchr(exten, '@')) {
                        switch_core_db_free(exten);
                }
+               if (etmp) {
+                       switch_core_db_free(etmp);
+               }
        }
 
 }
@@ -2394,11 +2669,11 @@ static void sip_i_invite(nua_t *nua,
                                                 tagi_t tags[])
 {
        switch_core_session_t *session = sofia_private ? sofia_private->session : NULL;
-       //refer_handle_t *refer = sofia_private ? sofia_private->refer : NULL;
        char key[128] = "";
 
-       if (!session) {
 
+       if (!session) {
+               
                if ((profile->pflags & PFLAG_AUTH_CALLS)) {
                        if (handle_register(nua, profile, nh, sip, REG_INVITE, key, sizeof(key))) {
                                return;
@@ -2510,7 +2785,6 @@ static void sip_i_register(nua_t *nua,
                                                   sip_t const *sip,
                                                   tagi_t tags[])
 {
-       //switch_core_session_t *session = sofia_private ? sofia_private->session : NULL;
        handle_register(nua, profile, nh, sip, REG_REGISTER, NULL, 0);
 }
 
@@ -2547,15 +2821,11 @@ static void sip_r_register(int status,
                if ((tech_pvt = switch_core_session_get_private(session)) && switch_test_flag(tech_pvt, TFLAG_REFER)) {
                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "received reply from refer\n");
                        
-                       if (status == 200) {
-                               //crap
-                       }
                        return;
                }
        }
        
        if (!oreg) {
-               switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "No authentication available!\n");
                if (sofia_private->oreg) {
                        nua_handle_destroy(nh); 
                }
@@ -2906,9 +3176,7 @@ static void *SWITCH_THREAD_FUNC profile_thread_run(switch_thread_t *thread, void
                }
 
                su_root_step(profile->s_root, 1000);
-               //su_root_run(profile->s_root);
        }
-
        
        if (switch_event_create(&s_event, SWITCH_EVENT_UNPUBLISH) == SWITCH_STATUS_SUCCESS) {
                switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, "service", "_sip._udp");
index 20b2c7fdbd489ca355a8fab45ca512042b8eb3fc..03ec4e9bbcc91a13f33252d9a014987377ffc69d 100644 (file)
@@ -145,55 +145,55 @@ SWITCH_DECLARE(void) switch_caller_profile_event_set_data(switch_caller_profile_
 
        if (caller_profile->username) {
                snprintf(header_name, sizeof(header_name), "%s-Username", prefix);
-               switch_event_add_header(event, SWITCH_STACK_BOTTOM, header_name, caller_profile->username);
+               switch_event_add_header(event, SWITCH_STACK_BOTTOM, header_name, "%s", caller_profile->username);
        }
        if (caller_profile->dialplan) {
                snprintf(header_name, sizeof(header_name), "%s-Dialplan", prefix);
-               switch_event_add_header(event, SWITCH_STACK_BOTTOM, header_name, caller_profile->dialplan);
+               switch_event_add_header(event, SWITCH_STACK_BOTTOM, header_name, "%s", caller_profile->dialplan);
        }
        if (caller_profile->caller_id_name) {
                snprintf(header_name, sizeof(header_name), "%s-Caller-ID-Name", prefix);
-               switch_event_add_header(event, SWITCH_STACK_BOTTOM, header_name, caller_profile->caller_id_name);
+               switch_event_add_header(event, SWITCH_STACK_BOTTOM, header_name, "%s", caller_profile->caller_id_name);
        }
        if (caller_profile->caller_id_number) {
                snprintf(header_name, sizeof(header_name), "%s-Caller-ID-Number", prefix);
-               switch_event_add_header(event, SWITCH_STACK_BOTTOM, header_name, caller_profile->caller_id_number);
+               switch_event_add_header(event, SWITCH_STACK_BOTTOM, header_name, "%s", caller_profile->caller_id_number);
        }
        if (caller_profile->network_addr) {
                snprintf(header_name, sizeof(header_name), "%s-Network-Addr", prefix);
-               switch_event_add_header(event, SWITCH_STACK_BOTTOM, header_name, caller_profile->network_addr);
+               switch_event_add_header(event, SWITCH_STACK_BOTTOM, header_name, "%s", caller_profile->network_addr);
        }
        if (caller_profile->ani) {
                snprintf(header_name, sizeof(header_name), "%s-ANI", prefix);
-               switch_event_add_header(event, SWITCH_STACK_BOTTOM, header_name, caller_profile->ani);
+               switch_event_add_header(event, SWITCH_STACK_BOTTOM, header_name, "%s", caller_profile->ani);
        }
        if (caller_profile->ani2) {
                snprintf(header_name, sizeof(header_name), "%s-ANI2", prefix);
-               switch_event_add_header(event, SWITCH_STACK_BOTTOM, header_name, caller_profile->ani2);
+               switch_event_add_header(event, SWITCH_STACK_BOTTOM, header_name, "%s", caller_profile->ani2);
        }
        if (caller_profile->destination_number) {
                snprintf(header_name, sizeof(header_name), "%s-Destination-Number", prefix);
-               switch_event_add_header(event, SWITCH_STACK_BOTTOM, header_name, caller_profile->destination_number);
+               switch_event_add_header(event, SWITCH_STACK_BOTTOM, header_name, "%s", caller_profile->destination_number);
        }
        if (caller_profile->uuid) {
                snprintf(header_name, sizeof(header_name), "%s-Unique-ID", prefix);
-               switch_event_add_header(event, SWITCH_STACK_BOTTOM, header_name, caller_profile->uuid);
+               switch_event_add_header(event, SWITCH_STACK_BOTTOM, header_name, "%s", caller_profile->uuid);
        }
        if (caller_profile->source) {
                snprintf(header_name, sizeof(header_name), "%s-Source", prefix);
-               switch_event_add_header(event, SWITCH_STACK_BOTTOM, header_name, caller_profile->source);
+               switch_event_add_header(event, SWITCH_STACK_BOTTOM, header_name, "%s", caller_profile->source);
        }
        if (caller_profile->context) {
                snprintf(header_name, sizeof(header_name), "%s-Context", prefix);
-               switch_event_add_header(event, SWITCH_STACK_BOTTOM, header_name, caller_profile->context);
+               switch_event_add_header(event, SWITCH_STACK_BOTTOM, header_name, "%s", caller_profile->context);
        }
        if (caller_profile->rdnis) {
                snprintf(header_name, sizeof(header_name), "%s-RDNIS", prefix);
-               switch_event_add_header(event, SWITCH_STACK_BOTTOM, header_name, caller_profile->rdnis);
+               switch_event_add_header(event, SWITCH_STACK_BOTTOM, header_name, "%s", caller_profile->rdnis);
        }
        if (caller_profile->chan_name) {
                snprintf(header_name, sizeof(header_name), "%s-Channel-Name", prefix);
-               switch_event_add_header(event, SWITCH_STACK_BOTTOM, header_name, caller_profile->chan_name);
+               switch_event_add_header(event, SWITCH_STACK_BOTTOM, header_name, "%s", caller_profile->chan_name);
        }
 
 }
index c1aa794131895ca45799934f04a1509cbb0e9a04..2b2d821f58287129081ffcf9584139bdae640621 100644 (file)
@@ -88,7 +88,7 @@ SWITCH_DECLARE(switch_status_t) switch_console_stream_write(switch_stream_handle
                        ret = -1;
                } else {
                        ret = 0;
-                       snprintf(end, remaining, data);
+                       snprintf(end, remaining, "%s", data);
                        handle->data_len = strlen(buf);
                        handle->end = (uint8_t *)(handle->data) + handle->data_len;
                }
index 659df3c8d35e3f254d50cd7f07fad67a86d9e660..3a4345e2fcbf1fdb230c7ff89950d9afec12c895 100644 (file)
@@ -2456,8 +2456,8 @@ static void switch_core_standard_on_execute(switch_core_session_t *session)
                
                if (switch_event_create(&event, SWITCH_EVENT_CHANNEL_EXECUTE) == SWITCH_STATUS_SUCCESS) {
                        switch_channel_event_set_data(session->channel, event);
-                       switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Application", extension->current_application->application_name);
-                       switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Application-Data", extension->current_application->application_data);
+                       switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Application", "%s", extension->current_application->application_name);
+                       switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Application-Data", "%s", extension->current_application->application_data);
                        switch_event_fire(&event);
                }
                application_interface->application_function(session, extension->current_application->application_data);
index 6600d4a4d21259a3ab15d3bdf5e3e30a05c6db69..85f41a25901865daf2ce9a5b256da279e92636dc 100644 (file)
@@ -1372,7 +1372,7 @@ static void *audio_bridge_thread(switch_thread_t *thread, void *obj)
        msg.from = __FILE__;
        switch_core_session_receive_message(session_a, &msg);
 
-       switch_channel_set_variable(chan_a, "BRIDGETO", NULL);
+       switch_channel_set_variable(chan_a, SWITCH_BRIDGE_VARIABLE, NULL);
        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "BRIDGE THREAD DONE [%s]\n", switch_channel_get_name(chan_a));
 
        switch_channel_clear_flag(chan_a, CF_BRIDGED);
@@ -1514,14 +1514,14 @@ static switch_status_t uuid_bridge_on_transmit(switch_core_session_t *session)
                if (switch_event_create(&event, SWITCH_EVENT_CHANNEL_EXECUTE) == SWITCH_STATUS_SUCCESS) {
                        switch_channel_event_set_data(channel, event);
                        switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Application", "uuid_bridge");
-                       switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Application-Data", switch_core_session_get_uuid(other_session));
+                       switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Application-Data", "%s", switch_core_session_get_uuid(other_session));
                        switch_event_fire(&event);
                }
 
                if (switch_event_create(&event, SWITCH_EVENT_CHANNEL_EXECUTE) == SWITCH_STATUS_SUCCESS) {
                        switch_channel_event_set_data(other_channel, event);
                        switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Application", "uuid_bridge");
-                       switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Application-Data", switch_core_session_get_uuid(session));
+                       switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Application-Data", "%s", switch_core_session_get_uuid(session));
                        switch_event_fire(&event);
                }
 
@@ -1912,7 +1912,7 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_originate(switch_core_session_t *sess
        }
  endfor1:
 
-       if (session) {
+       if (session && !switch_channel_test_flag(caller_channel, CF_NOMEDIA)) {
                switch_codec_t *read_codec = NULL;
 
                switch_channel_pre_answer(caller_channel);
@@ -1946,7 +1946,8 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_originate(switch_core_session_t *sess
                   check_channel_status(peer_channels, peer_sessions, argc, &idx, file, key) && ((time(NULL) - start) < (time_t)timelimit_sec)) {
 
                /* read from the channel while we wait if the audio is up on it */
-               if (session && (switch_channel_test_flag(caller_channel, CF_ANSWERED) || switch_channel_test_flag(caller_channel, CF_EARLY_MEDIA))) {
+               if (session && !switch_channel_test_flag(caller_channel, CF_NOMEDIA) && 
+                       (switch_channel_test_flag(caller_channel, CF_ANSWERED) || switch_channel_test_flag(caller_channel, CF_EARLY_MEDIA))) {
                        switch_status_t status = switch_core_session_read_frame(session, &read_frame, 1000, 0);
                        
                        if (!SWITCH_READ_ACCEPTABLE(status)) {
@@ -1964,7 +1965,7 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_originate(switch_core_session_t *sess
                
        }
 
-       if (session) {
+       if (session && !switch_channel_test_flag(caller_channel, CF_NOMEDIA)) {
                switch_core_session_reset(session);
        }
 
@@ -1987,6 +1988,11 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_originate(switch_core_session_t *sess
        }
 
        if (caller_channel && switch_channel_test_flag(peer_channel, CF_ANSWERED)) {
+               char *val;
+
+               if (switch_channel_test_flag(peer_channel, CF_NOMEDIA) && (val = switch_channel_get_variable(peer_channel, SWITCH_R_SDP_VARIABLE))) {
+                       switch_channel_set_variable(caller_channel, SWITCH_L_SDP_VARIABLE, val);
+               }
                switch_channel_answer(caller_channel);
        }
 
@@ -2042,6 +2048,100 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_originate(switch_core_session_t *sess
 }
 
 
+static switch_status_t signal_bridge_on_hangup(switch_core_session_t *session)
+{
+       char *uuid;
+       switch_channel_t *channel = NULL;
+    switch_core_session_t *other_session;
+       switch_event_t *event;
+
+    channel = switch_core_session_get_channel(session);
+    assert(channel != NULL);
+
+       if (switch_channel_test_flag(channel, CF_ORIGINATOR)) {
+               switch_channel_clear_flag(channel, CF_ORIGINATOR);
+               if (switch_event_create(&event, SWITCH_EVENT_CHANNEL_UNBRIDGE) == SWITCH_STATUS_SUCCESS) {
+                       switch_channel_event_set_data(channel, event);
+                       switch_event_fire(&event);
+               }
+       }
+
+
+       if ((uuid = switch_channel_get_variable(channel, SWITCH_SIGNAL_BRIDGE_VARIABLE)) && (other_session = switch_core_session_locate(uuid))) {
+               switch_channel_t *other_channel = NULL;
+
+               other_channel = switch_core_session_get_channel(other_session);
+               assert(other_channel != NULL);
+
+               switch_channel_hangup(other_channel, switch_channel_get_cause(channel));
+               switch_core_session_rwunlock(other_session);
+       }
+
+       return SWITCH_STATUS_SUCCESS;
+}
+
+static const switch_state_handler_table_t signal_bridge_state_handlers = {
+       /*.on_init */ NULL,
+       /*.on_ring */ NULL,
+       /*.on_execute */ NULL,
+       /*.on_hangup */ signal_bridge_on_hangup,
+       /*.on_loopback */ NULL,
+       /*.on_transmit */ NULL,
+       /*.on_hold */ NULL
+};
+
+
+
+SWITCH_DECLARE(switch_status_t) switch_ivr_signal_bridge(switch_core_session_t *session, switch_core_session_t *peer_session)
+{
+       switch_channel_t *caller_channel, *peer_channel;
+       switch_event_t *event;
+
+       caller_channel = switch_core_session_get_channel(session);
+       assert(caller_channel != NULL);
+
+       switch_channel_set_flag(caller_channel, CF_ORIGINATOR);
+
+       peer_channel = switch_core_session_get_channel(peer_session);
+       assert(peer_channel != NULL);
+
+       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_clear_state_handler(caller_channel, NULL);
+       switch_channel_clear_state_handler(peer_channel, NULL);
+
+       switch_channel_add_state_handler(caller_channel, &signal_bridge_state_handlers);
+       switch_channel_add_state_handler(peer_channel, &signal_bridge_state_handlers);
+
+
+       /* fire events that will change the data table from "show channels" */
+       if (switch_event_create(&event, SWITCH_EVENT_CHANNEL_EXECUTE) == SWITCH_STATUS_SUCCESS) {
+               switch_channel_event_set_data(caller_channel, event);
+               switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Application", "signal_bridge");
+               switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Application-Data", "%s", switch_core_session_get_uuid(peer_session));
+               switch_event_fire(&event);
+       }
+
+       if (switch_event_create(&event, SWITCH_EVENT_CHANNEL_EXECUTE) == SWITCH_STATUS_SUCCESS) {
+               switch_channel_event_set_data(peer_channel, event);
+               switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Application", "signal_bridge");
+               switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Application-Data", "%s", switch_core_session_get_uuid(session));
+               switch_event_fire(&event);
+       }
+
+       if (switch_event_create(&event, SWITCH_EVENT_CHANNEL_BRIDGE) == SWITCH_STATUS_SUCCESS) {
+               switch_channel_event_set_data(caller_channel, event);
+               switch_event_fire(&event);
+       }
+       
+       switch_channel_set_state(caller_channel, CS_TRANSMIT);
+       switch_channel_set_state(peer_channel, CS_TRANSMIT);
+
+       return SWITCH_STATUS_SUCCESS;
+}
+
+
 SWITCH_DECLARE(switch_status_t) switch_ivr_multi_threaded_bridge(switch_core_session_t *session, 
                                                                                                                                 switch_core_session_t *peer_session,
                                                                                                                                 switch_input_callback_function_t input_callback,
@@ -2102,18 +2202,32 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_multi_threaded_bridge(switch_core_ses
                        switch_event_fire(&event);
                }
                
-               msg.message_id = SWITCH_MESSAGE_INDICATE_BRIDGE;
-               msg.from = __FILE__;
-               msg.pointer_arg = session;
+               if (switch_core_session_read_lock(peer_session) == SWITCH_STATUS_SUCCESS) {
+                       switch_channel_set_variable(caller_channel, SWITCH_BRIDGE_VARIABLE, switch_core_session_get_uuid(peer_session));
+                       switch_channel_set_variable(peer_channel, SWITCH_BRIDGE_VARIABLE, switch_core_session_get_uuid(session));
 
-               switch_core_session_receive_message(peer_session, &msg);
-               msg.pointer_arg = peer_session;
-               switch_core_session_receive_message(session, &msg);
+                       msg.message_id = SWITCH_MESSAGE_INDICATE_BRIDGE;
+                       msg.from = __FILE__;
+                       msg.pointer_arg = session;
 
-               if (switch_core_session_read_lock(peer_session) == SWITCH_STATUS_SUCCESS) {
-                       switch_channel_set_variable(caller_channel, "BRIDGETO", switch_core_session_get_uuid(peer_session));
-                       switch_channel_set_variable(peer_channel, "BRIDGETO", switch_core_session_get_uuid(session));
+                       switch_core_session_receive_message(peer_session, &msg);
+
+                       if (!msg.pointer_arg) {
+                               status = SWITCH_STATUS_FALSE;
+                               switch_core_session_rwunlock(peer_session);
+                               goto done;
+                       }
+
+                       msg.pointer_arg = peer_session;
+                       switch_core_session_receive_message(session, &msg);
+
+                       if (!msg.pointer_arg) {
+                               status = SWITCH_STATUS_FALSE;
+                               switch_core_session_rwunlock(peer_session);
+                               goto done;
+                       }
 
+                       
                        switch_channel_set_private(peer_channel, "_bridge_", other_audio_thread);
                        switch_channel_set_state(peer_channel, CS_LOOPBACK);
                        audio_bridge_thread(NULL, (void *) this_audio_thread);
@@ -2164,6 +2278,7 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_multi_threaded_bridge(switch_core_ses
                switch_channel_hangup(peer_channel, SWITCH_CAUSE_NO_ANSWER);
        }
 
+ done:
        return status;
 }
 
@@ -2219,6 +2334,7 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_session_transfer(switch_core_session_
 {
        switch_channel_t *channel;
        switch_caller_profile_t *profile, *new_profile;
+       switch_core_session_message_t msg = {0};
 
        assert(session != NULL);
        assert(extension != NULL);
@@ -2245,6 +2361,11 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_session_transfer(switch_core_session_
                switch_channel_set_caller_profile(channel, new_profile);
                switch_channel_set_flag(channel, CF_TRANSFER);
                switch_channel_set_state(channel, CS_RING);
+
+               msg.message_id = SWITCH_MESSAGE_INDICATE_TRANSFER;
+               msg.from = __FILE__;
+               switch_core_session_receive_message(session, &msg);
+
                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Transfer %s to %s[%s@%s]\n", 
                                                  switch_channel_get_name(channel), dialplan, extension, context); 
                return SWITCH_STATUS_SUCCESS;
index 4aa667c5ad34553a9c7008b5d423225f7e9d2d99..c9a9f862134418f81d2eea373896c593233f375d 100644 (file)
@@ -329,6 +329,11 @@ SWITCH_DECLARE(switch_status_t) switch_rtp_set_local_address(switch_rtp_t *rtp_s
                return SWITCH_STATUS_SOCKERR;
        }
 
+       if (switch_socket_opt_set(rtp_session->sock, SWITCH_SO_REUSEADDR, 1) != SWITCH_STATUS_SUCCESS) {
+               *err = "Socket Error!";
+               return SWITCH_STATUS_FALSE;
+       }
+
        if (switch_socket_bind(rtp_session->sock, rtp_session->local_addr) != SWITCH_STATUS_SUCCESS) {
                *err = "Bind Error!";
                return SWITCH_STATUS_FALSE;
index ca5b54e08e5f778b7dcce0db30d1b0fa60872a8a..14f54d33a68d52cd251feeb3509c6491485e1e99 100644 (file)
@@ -72,6 +72,45 @@ SWITCH_DECLARE(unsigned char) switch_char_to_rfc2833(char key)
     return '\0';
 }
 
+SWITCH_DECLARE(char *) switch_escape_char(switch_memory_pool_t *pool, char *in, char *delim, char esc)
+{
+    char *data, *p, *d;
+    int count = 1, i = 0;
+
+    p = in;
+    while(*p) {
+        d = delim;
+        while (*d) {
+            if (*p == *d) {
+                count++;
+            }
+            d++;
+        }
+        p++;
+    }
+
+       if (count == 1) {
+               return in;
+       }
+
+       data = switch_core_alloc(pool, strlen(in) + count);
+       
+    p = in;
+    while(*p) {
+        d = delim;
+        while (*d) {
+            if (*p == *d) {
+                data[i++] = esc;
+            }
+            d++;
+        }
+        data[i++] = *p;
+        p++;
+    }
+    return data;
+}
+
+
 SWITCH_DECLARE(unsigned int) switch_separate_string(char *buf, char delim, char **array, int arraylen)
 {
        int argc;