[Freeswitch-svn] [commit] r2992 - in freeswitch/trunk/src: . include mod/applications/mod_bridgecall mod/endpoints/mod_sofia

Freeswitch SVN anthm at freeswitch.org
Fri Oct 6 18:39:51 EDT 2006


Author: anthm
Date: Fri Oct  6 18:39:49 2006
New Revision: 2992

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

Log:

Insane amounts of yucky satanic code to make transfer and that kind of thing work.
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 at 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!



Modified: freeswitch/trunk/src/include/switch_ivr.h
==============================================================================
--- freeswitch/trunk/src/include/switch_ivr.h	(original)
+++ freeswitch/trunk/src/include/switch_ivr.h	Fri Oct  6 18:39:49 2006
@@ -223,6 +223,13 @@
 																 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

Modified: freeswitch/trunk/src/include/switch_types.h
==============================================================================
--- freeswitch/trunk/src/include/switch_types.h	(original)
+++ freeswitch/trunk/src/include/switch_types.h	Fri Oct  6 18:39:49 2006
@@ -72,6 +72,11 @@
 #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 @@
 	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 @@
 	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_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 @@
 	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;
 
 

Modified: freeswitch/trunk/src/include/switch_utils.h
==============================================================================
--- freeswitch/trunk/src/include/switch_utils.h	(original)
+++ freeswitch/trunk/src/include/switch_utils.h	Fri Oct  6 18:39:49 2006
@@ -193,6 +193,16 @@
 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
   \param sock the socket to add

Modified: freeswitch/trunk/src/mod/applications/mod_bridgecall/mod_bridgecall.c
==============================================================================
--- freeswitch/trunk/src/mod/applications/mod_bridgecall/mod_bridgecall.c	(original)
+++ freeswitch/trunk/src/mod/applications/mod_bridgecall/mod_bridgecall.c	Fri Oct  6 18:39:49 2006
@@ -51,22 +51,31 @@
 		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,

Modified: freeswitch/trunk/src/mod/endpoints/mod_sofia/mod_sofia.c
==============================================================================
--- freeswitch/trunk/src/mod/endpoints/mod_sofia/mod_sofia.c	(original)
+++ freeswitch/trunk/src/mod/endpoints/mod_sofia/mod_sofia.c	Fri Oct  6 18:39:49 2006
@@ -62,6 +62,7 @@
 #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 @@
 	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 @@
 	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 @@
 	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 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 @@
 	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 @@
 
 	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 @@
 													 ))) {
 
 		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 @@
 {
 	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 @@
 	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 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 @@
 	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 @@
 	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 @@
 {
 	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 @@
 	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 @@
 	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 @@
 
 
 		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 @@
 
 	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 @@
 	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 @@
 	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 @@
 		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 @@
 	 
 {
 	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 @@
 		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 @@
 	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 @@
 	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);
+						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;
+						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_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Processing Attended Transfer\n");
-						while (switch_channel_get_state(channel) < CS_EXECUTE) {
-							switch_yield(10000);
-						}
+							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 ((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);
+							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);
+								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,77 +2025,104 @@
 		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 @@
 
 	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 @@
 				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 @@
 					}
 					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 @@
 
 								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 @@
 														 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 @@
 						} 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 @@
 			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 @@
 						 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 @@
 						   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 @@
 		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 @@
 		}
 
 		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");

Modified: freeswitch/trunk/src/switch_caller.c
==============================================================================
--- freeswitch/trunk/src/switch_caller.c	(original)
+++ freeswitch/trunk/src/switch_caller.c	Fri Oct  6 18:39:49 2006
@@ -145,55 +145,55 @@
 
 	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);
 	}
 
 }

Modified: freeswitch/trunk/src/switch_console.c
==============================================================================
--- freeswitch/trunk/src/switch_console.c	(original)
+++ freeswitch/trunk/src/switch_console.c	Fri Oct  6 18:39:49 2006
@@ -88,7 +88,7 @@
 			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;
 		}

Modified: freeswitch/trunk/src/switch_core.c
==============================================================================
--- freeswitch/trunk/src/switch_core.c	(original)
+++ freeswitch/trunk/src/switch_core.c	Fri Oct  6 18:39:49 2006
@@ -2456,8 +2456,8 @@
 		
 		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);

Modified: freeswitch/trunk/src/switch_ivr.c
==============================================================================
--- freeswitch/trunk/src/switch_ivr.c	(original)
+++ freeswitch/trunk/src/switch_ivr.c	Fri Oct  6 18:39:49 2006
@@ -1372,7 +1372,7 @@
 	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 @@
 		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 @@
 	}
  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 @@
 		   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 @@
 		
 	}
 
-	if (session) {
+	if (session && !switch_channel_test_flag(caller_channel, CF_NOMEDIA)) {
 		switch_core_session_reset(session);
 	}
 
@@ -1987,6 +1988,11 @@
 	}
 
 	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 @@
 }
 
 
+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_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_channel_hangup(peer_channel, SWITCH_CAUSE_NO_ANSWER);
 	}
 
+ done:
 	return status;
 }
 
@@ -2219,6 +2334,7 @@
 {
 	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_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;

Modified: freeswitch/trunk/src/switch_rtp.c
==============================================================================
--- freeswitch/trunk/src/switch_rtp.c	(original)
+++ freeswitch/trunk/src/switch_rtp.c	Fri Oct  6 18:39:49 2006
@@ -329,6 +329,11 @@
 		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;

Modified: freeswitch/trunk/src/switch_utils.c
==============================================================================
--- freeswitch/trunk/src/switch_utils.c	(original)
+++ freeswitch/trunk/src/switch_utils.c	Fri Oct  6 18:39:49 2006
@@ -72,6 +72,45 @@
     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;



More information about the Freeswitch-svn mailing list