--- /usr/src/asterisk/include/asterisk/rtp.h	2004-07-08 13:46:15.000000000 +0200
+++ ./include/asterisk/rtp.h	2004-08-02 11:32:50.000000000 +0200
@@ -38,7 +38,12 @@
 struct ast_rtp_protocol {
 	struct ast_rtp *(*get_rtp_info)(struct ast_channel *chan);				/* Get RTP struct, or NULL if unwilling to transfer */
 	struct ast_rtp *(*get_vrtp_info)(struct ast_channel *chan);				/* Get RTP struct, or NULL if unwilling to transfer */
-	int (*set_rtp_peer)(struct ast_channel *chan, struct ast_rtp *peer, struct ast_rtp *vpeer, int codecs);	/* Set RTP peer */
+
+        /* Prepare the peer (hook inserted just before setting peer) 
+         * Used before set_rtp_peer_restart*/
+	int (*prepare_rtp_peer)(struct ast_channel *chan, struct sockaddr_in *them, struct ast_rtp *peer, struct ast_rtp *vpeer, int codecs);
+        int (*set_rtp_peer_restart)(struct ast_channel *chan, struct sockaddr_in *them, struct ast_rtp *peer, struct ast_rtp *vpeer, int codecs);
+        int (*set_rtp_peer)(struct ast_channel *chan, struct ast_rtp *peer, struct ast_rtp *vpeer, int codecs);	/* Set RTP peer */
 	int (*get_codec)(struct ast_channel *chan);
 	char *type;
 	struct ast_rtp_protocol *next;
--- /usr/src/asterisk/rtp.c	2004-08-01 01:02:55.000000000 +0200
+++ ./rtp.c	2004-08-02 12:37:12.000000000 +0200
@@ -1306,7 +1301,10 @@
 	struct sockaddr_in t0, t1;
 	struct sockaddr_in vt0, vt1;
 	char iabuf[INET_ADDRSTRLEN];
-	
+
+        struct ast_rtp _p0, _p1;
+        struct sockaddr_in _a0, _a1;
+
 	void *pvt0, *pvt1;
 	int to;
 	int codec0,codec1, oldcodec0, oldcodec1;
@@ -1370,22 +1368,45 @@
 			return -2;
 		}
 	}
-	if (pr0->set_rtp_peer(c0, p1, vp1, codec1)) 
-		ast_log(LOG_WARNING, "Channel '%s' failed to talk to '%s'\n", c0->name, c1->name);
-	else {
-		/* Store RTP peer */
-		ast_rtp_get_peer(p1, &ac1);
-		if (vp1)
-			ast_rtp_get_peer(vp1, &vac1);
-	}
-	if (pr1->set_rtp_peer(c1, p0, vp0, codec0))
-		ast_log(LOG_WARNING, "Channel '%s' failed to talk back to '%s'\n", c1->name, c0->name);
-	else {
-		/* Store RTP peer */
-		ast_rtp_get_peer(p0, &ac0);
-		if (vp0)
-			ast_rtp_get_peer(vp0, &vac0);
-	}
+
+        /* Preparing channels before bridging
+         * this is merely a hook added to work with ast_h323 
+         * TODO: has to be implemented in all channels or insert
+         * a check */
+
+        _a0 = p0->them;
+        _a1 = p1->them;
+
+        if(pr0->prepare_rtp_peer(c0, &_a0, p1, vp1, codec1))
+                ast_log(LOG_WARNING, "Failed to prepare channel '%s'\n", c0->name);
+        if(pr1->prepare_rtp_peer(c1, &_a1, p1, vp0, codec0))
+                ast_log(LOG_WARNING, "Failed to prepare second channel '%s'\n", c1->name);
+
+        _p0.them = _a0;
+        _p1.them = _a1;
+  
+
+        /* Tell both channels to start streaming !*/
+        
+        if (pr0->set_rtp_peer_restart(c0, &_a1, &_p1, vp1, codec1))
+                /*TODO: Retreive call without native bridging if failed*/
+                ast_log(LOG_WARNING, "Failed to restart first channel '%s'\n", c0->name);
+        else {
+                ast_rtp_get_peer(p1, &ac1);
+                if(vp1)
+                        ast_rtp_get_peer(vp1, &vac1);
+        }
+
+        if (pr1->set_rtp_peer_restart(c1, &_a0, &_p0, vp0, codec0))
+                /*TODO: Retreive call without native bridging if failed*/
+                ast_log(LOG_WARNING, "Failed to restart second channel '%s'\n", c1->name);
+        else {
+                ast_rtp_get_peer(p0, &ac0);
+                if (vp0)
+                        ast_rtp_get_peer(vp0, &vac0);
+        }
+
+
 	ast_mutex_unlock(&c0->lock);
 	ast_mutex_unlock(&c1->lock);
 	cs[0] = c0;
--- /usr/src/asterisk/channels/chan_mgcp.c	2004-08-02 06:32:37.000000000 +0200
+++ ./channels/chan_mgcp.c	2004-08-02 15:41:56.000000000 +0200
@@ -3772,9 +3726,42 @@
 	return -1;
 }
 
+static int mgcp_prepare_rtp_peer(struct ast_channel *chan, struct sockaddr_in * our_addr,
+                                 struct ast_rtp *rtp, struct ast_rtp *vrtp, int codecs)
+{
+        return 0;
+}
+
+static int mgcp_set_rtp_peer_restart(struct ast_channel *chan, struct sockaddr_in * them_sock,
+                                     struct ast_rtp *rtp, struct ast_rtp *vrtp, int codecs)
+{
+
+       const char * them_addr;
+       uint16_t them_port;
+       char iabuf[INET_ADDRSTRLEN];
+       struct sockaddr_in them;
+       struct mgcp_subchannel *sub;
+       
+       ast_rtp_get_peer(rtp, &them);
+       sub = chan->pvt->pvt;
+
+       them_addr = ast_inet_ntoa(iabuf, sizeof(iabuf), them.sin_addr);
+       them_port =  ntohs(them.sin_port);
+                        
+       ast_log(LOG_DEBUG, "About to perform forwarding with addr: %s port %d\n", them_addr, them_port);
+       
+       /* we do want to get control on DTMFs */       
+       mgcp_set_rtp_peer(chan, rtp, vrtp, codecs); 
+       return transmit_notify_request(sub, "L/hu(N), L/hf(N), D/[0-9#*](N)");
+       
+}
+
+
 static struct ast_rtp_protocol mgcp_rtp = {
 	get_rtp_info: mgcp_get_rtp_peer,
 	set_rtp_peer: mgcp_set_rtp_peer,
+        prepare_rtp_peer: mgcp_prepare_rtp_peer,
+        set_rtp_peer_restart: mgcp_set_rtp_peer_restart,
 };
 
 static int mgcp_do_debug(int fd, int argc, char *argv[])
--- /usr/src/asterisk/channels/chan_h323.c	2004-07-30 22:01:58.000000000 +0200
+++ ./channels/chan_h323.c	2004-08-02 15:44:42.000000000 +0200
@@ -753,7 +745,8 @@
 		ch->pvt->write = oh323_write;
 		ch->pvt->indicate = oh323_indicate;
 		ch->pvt->fixup = oh323_fixup;
-	     /*	ch->pvt->bridge = ast_rtp_bridge; */
+                /*XXX: Experimental feature - comment if you get troubles*/
+	     	ch->pvt->bridge = ast_rtp_bridge; 
 
 		/*  Set the owner of this channel */
 		i->owner = ch;
@@ -1456,7 +1419,7 @@
 	if (argc != 3) {
 		return RESULT_SHOWUSAGE;
 	}
-	h323_debug(1, atoi(argv[2]));
+	h323_trace(1, atoi(argv[2]));
 	ast_cli(fd, "H.323 trace set to level %s\n", argv[2]);
 	return RESULT_SUCCESS;
 }
@@ -1466,19 +1429,24 @@
 	if (argc != 3) {
 		return RESULT_SHOWUSAGE;
 	}
-	h323_debug(0,0);
+	h323_trace(0,0);
 	ast_cli(fd, "H.323 trace disabled\n");
 	return RESULT_SUCCESS;
 }
 
 static int h323_do_debug(int fd, int argc, char *argv[])
 {
-	if (argc != 2) {
-		return RESULT_SHOWUSAGE;
-	}
-	h323debug = 1;
-	ast_cli(fd, "H323 debug enabled\n");
-	return RESULT_SUCCESS;
+        if (argc == 2) {
+                h323debug = 1;
+                ast_cli(fd, "H323 deubg enabled\n");
+                return RESULT_SUCCESS;
+        } else if (argc == 3) {
+                h323_debug(1, atoi(argv[2]));
+                ast_cli(fd, "H.323 debug set to level %s\n", argv[2]);
+                return RESULT_SUCCESS;
+        } else {
+                return RESULT_SHOWUSAGE;
+        }
 }
 
 static int h323_no_debug(int fd, int argc, char *argv[])
@@ -1487,6 +1455,7 @@
 		return RESULT_SHOWUSAGE;
 	}
 	h323debug = 0;
+        h323_debug(0,0);
 	ast_cli(fd, "H323 Debug disabled\n");
 	return RESULT_SUCCESS;
 }
@@ -1887,6 +1853,68 @@
 
 }
 
+static int oh323_prepare_rtp_peer(struct ast_channel *chan, struct sockaddr_in * our_addr,
+                                  struct ast_rtp *rtp, struct ast_rtp *vrtp, int codecs)
+{
+
+        struct oh323_pvt *p;
+        char noi_addr[INET_ADDRSTRLEN];
+        in_port_t port;
+        //char iabuf[INET_ADDRSTRLEN]
+
+        p = chan->pvt->pvt;
+        if (!p) {
+                ast_log(LOG_ERROR, "No Private Structure, this is bad\n");
+                return -1;
+        }
+        
+        if(h323_prepare_forwarding(p->cd.call_token, noi_addr, &port)) {
+                ast_log(LOG_WARNING, "Unable to prepare call '%s' for forwarding", p->cd.call_token);
+                return 1;
+        }
+
+        if(!inet_aton(noi_addr, &our_addr->sin_addr)) {
+                ast_log(LOG_WARNING, "Unable to set new us.sin_addr\n");
+                return 1;
+        }
+        our_addr->sin_port = htons(port); 
+        
+        ast_log(LOG_DEBUG, "Call '%s' prepared, addr = %s, port = %d\n", p->cd.call_token, noi_addr, ntohs(our_addr->sin_port));
+        
+        return 0;
+        
+}
+
+static int oh323_set_rtp_peer_restart(struct ast_channel *chan, struct sockaddr_in * them,
+                                      struct ast_rtp *rtp, struct ast_rtp *vrtp, int codecs)
+{
+
+        struct oh323_pvt *p;
+        const char * them_addr;
+        uint16_t them_port;
+        char iabuf[INET_ADDRSTRLEN];
+
+        them_addr = ast_inet_ntoa(iabuf, sizeof(iabuf), them->sin_addr);
+        them_port =  ntohs(them->sin_port);
+        
+        p = chan->pvt->pvt;
+        if (!p) {
+                ast_log(LOG_ERROR, "No Private Structure, this is bad\n");
+                return -1;
+        }
+        
+        ast_log(LOG_DEBUG, "About to perform forwarding with addr: %s port %d\n", them_addr, them_port);
+        
+        if (h323_perform_forwarding(p->cd.call_token, them_addr, &them_port)) {
+                ast_log(LOG_WARNING, "Unable to perform forwarding for call '%s'\n", p->cd.call_token);
+                return 1;
+        }
+        
+        return 0;
+        
+}  
+
+
 static int oh323_set_rtp_peer(struct ast_channel *chan, struct ast_rtp *rtp, struct ast_rtp *vrtp, int codecs)
 {
 	/* XXX Deal with Video */
@@ -1911,7 +1939,8 @@
 	ast_rtp_get_peer(rtp, &them);	
 	ast_rtp_get_us(rtp, &us);
 
-	h323_native_bridge(p->cd.call_token, ast_inet_ntoa(iabuf, sizeof(iabuf), them.sin_addr), mode);
+        /*XXX: Native bridge is implemented through prepare and restart functions
+	h323_native_bridge(p->cd.call_token, ast_inet_ntoa(iabuf, sizeof(iabuf), them.sin_addr), mode);*/
 	
 	return 0;
 	
@@ -1921,6 +1950,8 @@
 	get_rtp_info: oh323_get_rtp_peer,
 	get_vrtp_info: oh323_get_vrtp_peer,
 	set_rtp_peer: oh323_set_rtp_peer,
+        prepare_rtp_peer: oh323_prepare_rtp_peer,
+        set_rtp_peer_restart: oh323_set_rtp_peer_restart,
 };
 
 int load_module()
--- /usr/src/asterisk/channels/h323/chan_h323.h	2004-07-22 06:24:50.000000000 +0200
+++ ./channels/h323/chan_h323.h	2004-08-02 14:56:25.000000000 +0200
@@ -171,6 +171,7 @@
 	int  h323_end_point_exist(void);
     
 	void h323_debug(int, unsigned);
+        void h323_trace(int, unsigned);
 
 	/* callback function handler*/
 	void h323_callback_register(setup_incoming_cb,  
@@ -194,7 +195,11 @@
 	/* H323 listener related funcions */
 	int h323_start_listener(int, struct sockaddr_in);
 
-	void h323_native_bridge(const char *, const char *, char *);
+	void h323_native_bridge(const char *, const char *, char *);
+
+        //used when native bridging
+        int h323_prepare_forwarding(const char *token, char *, unsigned int *);
+        int h323_perform_forwarding(const char *, char *, unsigned int *);
 
 	/* Send a DTMF tone to remote endpoint */
 	void h323_send_tone(const char *call_token, char tone);
--- /usr/src/asterisk/channels/h323/ast_h323.cpp	2004-07-22 06:24:50.000000000 +0200
+++ ./channels/h323/ast_h323.cpp	2004-08-02 15:48:45.000000000 +0200
@@ -37,6 +37,9 @@
 #include <mediafmt.h>
 #include <lid.h>
 
+//Required to act on logicalChannels
+#include <h323neg.h>
+
 #ifdef __cplusplus
 extern "C" {
 #endif   
@@ -260,6 +263,10 @@
 	}
 	
 	*callReference = connection->GetCallReference();
+
+	//TODO: it's awful ! (implementing a Getter etc.)
+
+	connection->isLocalInitiated = TRUE;
 	
 	if (callerid)
 		connection->SetLocalPartyName(PString(callerid));
@@ -472,6 +479,106 @@
 }
 
 
+int MyH323EndPoint::H245HoldCall(const PString & token0, PString & newToken, unsigned int *callReference,
+                                  unsigned int port, char *callerid)
+{
+
+        MyH323Connection *con0 = (MyH323Connection *)endPoint->FindConnectionWithLock(token0);
+        if (!con0){
+                cout << "ERROR: No connection found for token" << token0 << " call: " << token0 << "cannot be redirected" << endl;
+                return 1;
+        }
+
+        con0->Unlock(); 
+        if(!con0->H245HoldCall(FALSE)) {
+                AST_LOG(1, "ERROR:[EndPoint::H245HoldCall] Could not Hold Call from remote");
+                return 1;
+        }
+        if (!con0->IsH245RemoteHold()) {
+                AST_LOG(1, "ERROR:[EndPoint::H245HoldCall] Remote is not on hold !");
+		return 1;
+	}
+
+        if(!con0->H245HoldCall(TRUE)) {
+                AST_LOG(1, "ERROR:[EndPoint::H245HoldCall] Could not hold call from local");
+                return 1;
+        }
+
+        if (!con0->IsH245LocalHold()) {
+                AST_LOG(1, "ERROR:[EndPoint::H245HoldCall] Local is not on hold !");
+		return 1;
+	}
+
+        return 0;
+
+}
+
+
+int MyH323EndPoint::H245WakeUpCall(const PString & token0, PString & rtpAddr, unsigned int *port,
+                                  unsigned int caca, char *callerid)
+{
+
+        MyH323Connection *con0 = (MyH323Connection *)endPoint->FindConnectionWithLock(token0);
+        if (!con0) {
+                AST_LOG(1,"ERROR:[EndPoint::WakeUpCall] Unable To get connection from token: " << token0);
+                return 1;
+        }
+        AST_LOG(2, "[EndPoint::WakeUpCall] Waking up Call" << con0->GetCallToken());
+        con0->Unlock();
+
+        if (!con0->H245WakeUpCall(rtpAddr, port)) {
+                AST_LOG(1, "ERROR:[EndPoint::WakeUpCall] Unable to wake up call: " << token0 << " from connection");
+                return 1;
+        }
+
+        return 0;
+}
+
+
+int MyH323EndPoint::H245GetUpCall(const PString & token, PString & destAddr, WORD & destPort)
+{
+
+        PIPSocket::Address them = PIPSocket::Address(destAddr);
+        MyH323Connection *connection = (MyH323Connection *)endPoint->FindConnectionWithLock(token);
+
+        if (!connection) {
+                AST_LOG(1, "ERROR:[EndPoint::GetUpCall] Unable To get connection from token: " << token);
+                return 1;
+        }
+        AST_LOG(2, "[EndPoint::GetUpCall] Raising Up Call" << connection->GetCallToken());
+        connection->Unlock();
+
+        if (!connection->H245GetUpCall(them, destPort)) {
+                AST_LOG(1, "ERROR:[EndPoint::GetUpCall] Unable to make lazy call " << token << " get up !");
+                return 1;
+        }
+
+        return 0;
+
+}
+
+
+int MyH323EndPoint::H245RetreiveCall(const PString & token0, PString & dest, unsigned int *callReference,
+                                  unsigned int port, char *callerid)
+{
+
+        /*MyH323Connection *con0 = (MyH323Connection *)endPoint->FindConnectionWithLock(token0);
+
+        cout << "Retreiving Call " << con0->GetCallToken() << "to destination " << dest << endl;
+        con0->Unlock();
+
+        if (!con0->H245RetreiveCall(dest)) {
+                cout << "Unable to retreive call to destination: " << dest << endl;
+                return 1;
+        }*/
+
+        return 0;
+
+}
+
+
+//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
 H323Connection * MyH323EndPoint::CreateConnection(unsigned callReference, void *outbound)
 {
 	unsigned options = 0;
@@ -490,6 +597,12 @@
 							unsigned options)
 	: H323Connection(ep, callReference, options)
 {
+	remoteIpAddress = 0;    // IP Address of remote endpoint
+	remotePort      = 0;    // remote endpoint Data port (control is dataPort+1)
+	h245HoldState = NoHold;
+	isLocalInitiated = FALSE;
+	bridging = FALSE;
+
 	if (h323debug) {
 		cout << "	== New H.323 Connection created." << endl;
 	}
@@ -718,8 +831,30 @@
 		return NULL;
 	}
 
-	GetControlChannel().GetLocalAddress().GetIpAndPort(externalIpAddress, port);
-	externalPort = info->port;
+        if (!bridging) {
+                GetControlChannel().GetLocalAddress().GetIpAndPort(externalIpAddress, port);
+                externalPort = info->port;
+                if (h245HoldState == LocalHold) {
+			AST_LOG(1, "ERROR: State is LocalHold, no external Channel should be spawned");
+                        return NULL;
+                } else if (h245HoldState == WakingUp) {
+                        if (dir == H323Channel::IsTransmitter) {
+                                if (h323debug)
+					cout << "Connection is WakingUp - creating T channel to stimulate peer" << endl;
+                        } else if (dir == H323Channel::IsReceiver) {
+				//OLC should have been intercepted before
+				AST_LOG(1, "[OnCreateRTLC] ERROR: No Receiver should be spawned while Waking Up");
+                        } else {
+                                cout << "Something wrong occured in creating RTP channel" << endl;
+                        }
+                } else {
+                        GetControlChannel().GetLocalAddress().GetIpAndPort(externalIpAddress, port);
+                        externalPort = info->port;
+                }
+        } else {
+		if (h323debug)
+                	cout << "	=*= Redirecting RTP" << endl;
+        }
 	
 	if (h323debug) {
 		cout << "	=*= In CreateRealTimeLogicalChannel for call " << GetCallReference() << endl;
@@ -745,6 +880,22 @@
 	/* adjust the count of channels we have open */
 	channelsOpen++;
 
+
+	//FIXME: I needed those entries :)
+
+        if (h323debug) {
+                cout <<  "              -- channelsOpen = " << channelsOpen << endl;
+        }
+        H323_ExternalRTPChannel & external = (H323_ExternalRTPChannel &)channel;
+        external.GetRemoteAddress(remoteIpAddress, remotePort);
+
+        if (h323debug) {
+                cout << "               -- remoteIpAddress: " << remoteIpAddress << endl;
+                cout << "               -- remotePort: " << remotePort << endl;
+                cout << "               -- ExternalIpAddress: " << externalIpAddress << endl;
+                cout << "               -- ExternalPort: " << externalPort << endl;
+        }
+
 	if (h323debug) {
 		cout <<  "		-- channelsOpen = " << channelsOpen << endl;
 	}
@@ -752,6 +903,258 @@
 	return TRUE;	
 }
 
+
+BOOL MyH323Connection::OnH245Request(const H323ControlPDU& pdu)
+{
+        const H245_RequestMessage & request = pdu;
+
+	AST_LOG(4, "Received Request: " << request.GetTagName());
+
+        if (request.GetTag() == H245_RequestMessage::e_openLogicalChannel) {
+                if (h245HoldState == Retreiving) {
+			SetH245HoldState(NoHold);
+                } else if (h245HoldState == WakingUp) {
+			AST_LOG(3, "[OnH245Request]: Received OLC while connection is WakingUp");
+                }
+        }
+        else if (request.GetTag() == H245_RequestMessage::e_closeLogicalChannel) {
+                if (h245HoldState == AwaitingRemoteCloseChannel) {
+			AST_LOG(3, "[OnH245Request]: Remote Party successfuly accepted channel removal");
+			SetH245HoldState(RemoteHold);
+                        myHoldSyncPoint.Signal();
+                }
+        }
+        
+        return H323Connection::OnH245Request(pdu);
+}
+
+BOOL MyH323Connection::OnH245Response(const H323ControlPDU& pdu)
+{
+        const  H245_ResponseMessage & response = pdu;
+
+	AST_LOG(4, "Received Response: " << response.GetTagName());
+
+        if(response.GetTag() == H245_ResponseMessage::e_closeLogicalChannelAck){
+                if (h245HoldState == AwaitingRemoteCloseChannelAck) {
+                        AST_LOG(3,"[OnH245Response] Local closing successfuly accepted");
+			SetH245HoldState(LocalHold);
+                        myHoldSyncPoint.Signal();
+                }
+        }
+
+        return H323Connection::OnH245Response(pdu);
+}
+
+BOOL MyH323Connection::OnOpenLogicalChannel(const H245_OpenLogicalChannel & openPDU,
+                                      H245_OpenLogicalChannelAck & ackPDU,
+                                       unsigned & errorCode)
+{
+        if (h245HoldState == WakingUp) {
+		AST_LOG(3, "[OnOpenLogicalChannel] Received OLC while waking up\n" 
+                             << "Retreiving info from OLC Pdu");
+
+                H245_H2250LogicalChannelParameters params = openPDU.m_forwardLogicalChannelParameters.m_multiplexParameters;
+                bridgingTransport = params.m_mediaControlChannel;
+
+                myHoldSyncPoint.Signal();
+                AST_LOG(2, "Unlocking connection - Waiting for infos before sending OLCack...");
+                Unlock();
+                receiverSyncPoint.Wait();
+                Lock();  
+        }
+
+        return H323Connection::OnOpenLogicalChannel(openPDU, ackPDU, errorCode);
+}
+
+BOOL MyH323Connection::H245HoldCall(BOOL localhold)
+{
+
+
+        if (localhold && (h245HoldState == RemoteHold)) {
+
+		//TODO: find a way to retreive session_ID properly
+                H323Channel * _chan = logicalChannels->FindChannelBySession(1, FALSE);
+                if (_chan == NULL) {
+			AST_LOG(1, "Chan session_ID 1 is NULL");
+                        return FALSE;
+                }
+
+		if (h323debug) {
+			cout << "Trying to Hold local Logical Channel" << endl;
+                	_chan->PrintOn(cout);
+		}
+
+                const H323ChannelNumber _chanNum = _chan->GetNumber();
+                if (!logicalChannels->Close(_chanNum, FALSE)) {
+			AST_LOG(1, "ERROR: [H245HoldCall] Unable to close channel " << _chanNum <<" from local");
+                        return FALSE;
+                }
+
+		SetH245HoldState(AwaitingRemoteCloseChannelAck);
+                //FIXME: inserting a timeout value ?
+                myHoldSyncPoint.Wait();
+                return TRUE;
+        }
+        else if (localhold && (h245HoldState != RemoteHold)) {
+		AST_LOG(1, "ERROR: [H245HoldState] Trying to hold local channel while remote not hold");
+                return FALSE;
+        }
+        else if (!localhold && (h245HoldState != LocalHold)) {
+                if (!capabilityExchangeProcedure->Start(TRUE, TRUE)) {
+                        cout << "Problems in sending Empty Capability Set to restart negotiation" << endl;
+                        return FALSE;
+                }
+		SetH245HoldState(AwaitingRemoteCloseChannel);
+                myHoldSyncPoint.Wait();
+                return TRUE;
+        }
+        else if (!localhold && (h245HoldState == LocalHold)) {
+                AST_LOG(1, "ERROR: [H245HoldState] LocalHold must be done AFTER remote removal");
+                return FALSE;
+        }
+
+	AST_LOG(1, "[H245HoldCall] ERROR: Something strange occured");
+        return FALSE;
+}
+
+BOOL MyH323Connection::H245WakeUpCall(PString& rtpAddr, unsigned int *port)
+{
+
+	AST_LOG(4, "[H245WakeUpCall] Waking up call "<< GetCallToken()); 
+
+        Lock();
+        h245HoldState = WakingUp;
+        Unlock();
+
+        if (!capabilityExchangeProcedure->Start(TRUE, FALSE)) {
+		AST_LOG(1, "ERROR: Failed to restart Caps Procedure");
+                return FALSE;
+        }
+
+        if (!masterSlaveDeterminationProcedure->Start(TRUE)) {
+		AST_LOG(1, "ERROR: Failed to restart MSDSE procedure");
+                return FALSE;
+        }
+
+	//OnSelectLogicalChannels();
+
+	AST_LOG(2, "[H245WakeUpCall] Awaiting remote OLC");
+        myHoldSyncPoint.Wait();
+	//OnSelectLogicalChannels();
+	AST_LOG(4, "Transport is: " << bridgingTransport);
+
+        H245_UnicastAddress& _addr = bridgingTransport;
+        H245_UnicastAddress_iPAddress& __addr = _addr;
+        *port =__addr.m_tsapIdentifier.GetValue();
+        //FIXME: Retreive from OLC request, PBYTEArray::AsString() method ain't work
+        rtpAddr = remoteIpAddress.AsString();
+        //FIXME: retreive from OLCAck
+        (*port)--;
+
+        return TRUE;
+
+}
+
+BOOL MyH323Connection::H245GetUpCall(PIPSocket::Address & rtpAddr, WORD & rtpPort)
+{
+
+        Lock();
+        externalPort = rtpPort;
+        externalIpAddress = rtpAddr;
+        h245HoldState = NoHold;
+        bridging = TRUE;
+        Unlock();
+
+        receiverSyncPoint.Signal();
+	OnSelectLogicalChannels();
+
+	/* XXX: sometimes needed to prevent asterisk
+	   main core from streaming on the peer. If peer's
+           udp socket have not been initialized by his forward
+           party
+	AST_LOG(2, "[H245GetUpCall] waiting 100ms");
+	transmitterSyncPoint.Wait(PTimeInterval(100,0));
+	AST_LOG(2, "[H245GetUpCall] timer expired");*/
+
+        return TRUE;
+}
+
+BOOL MyH323Connection::H245RetreiveCall(const PString& dest)
+{
+	//TODO: "Rescue" function to be implemented here
+	return TRUE;
+}
+
+void MyH323Connection::OnSelectLogicalChannels()
+{
+
+        if (h245HoldState == LocalHold) {
+		AST_LOG(2, "Local Channel is on Hold, no transmitter respawned");
+                return;
+        }
+        else if (h245HoldState == BothHold) {
+		AST_LOG(2, "Both Local and remote channels are on hold, no transmitter respawned");
+                return;
+        } else if (h245HoldState == Retreiving) {
+		AST_LOG(2, "Retreiving channels, waiting for Open Logical Channel request to respawn transimitter");
+                return;
+        } else if (h245HoldState == AwaitingRemoteCloseChannelAck) {
+		AST_LOG(2,"Awaiting Remote CloseChannelAck to put channel on hold");
+                return;
+        }
+
+        H323Connection::OnSelectLogicalChannels();
+}
+
+BOOL MyH323Connection::IsH245RemoteHold()
+{
+        return (h245HoldState == RemoteHold || BothHold) ? TRUE : FALSE;
+}
+
+BOOL MyH323Connection::IsH245LocalHold()
+{
+        return (h245HoldState == LocalHold || BothHold) ? TRUE : FALSE;
+}
+
+void MyH323Connection::SetH245HoldState(H245HoldStates state)
+{
+	OnSetH245HoldState(state);
+	h245HoldState = state;
+	return;
+}
+
+void MyH323Connection::OnSetH245HoldState(H245HoldStates state)
+{
+	AST_LOG(3, "[H245Holding] Connection " << GetCallToken() << " is " << state);
+	return;
+}
+
+ostream & operator<<(ostream & out, MyH323Connection::H245HoldStates state)
+{ 
+  static const char * const StateNames[MyH323Connection::NumStates] = {
+                "NoHold",
+                "AwaitingRemoteCloseChannel",
+                "RemoteHold",
+                "AwaitingRemoteCloseChannelAck",
+                "LocalHold",
+                "BothHold",
+                "WakingUp",
+                "Retreiving"
+  };
+  
+  if (state < MyH323Connection::NumStates && StateNames[state] != NULL)
+    out << StateNames[state];
+  else
+    out << "H245HoldState<" << (unsigned)state << '>';
+  
+  return out;
+}
+
+
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
 /* MyH323_ExternalRTPChannel */
 MyH323_ExternalRTPChannel::MyH323_ExternalRTPChannel(MyH323Connection & connection,
 						     const H323Capability & capability,
@@ -761,6 +1164,10 @@
 		  				     WORD dataPort)
 	: H323_ExternalRTPChannel(connection, capability, direction, sessionID, ip, dataPort)
 {
+
+	//used to access MyH323Connection specific parameters
+	_connection = &connection;
+
 }
 
 MyH323_ExternalRTPChannel::MyH323_ExternalRTPChannel(MyH323Connection & connection,
@@ -769,6 +1176,9 @@
                                                      unsigned id)
  : H323_ExternalRTPChannel::H323_ExternalRTPChannel(connection, capability, direction, id)
 {   
+
+	_connection = &connection;
+
 } 
 
 MyH323_ExternalRTPChannel::MyH323_ExternalRTPChannel(MyH323Connection & connection, 
@@ -779,6 +1189,9 @@
                                                      const H323TransportAddress & control) 
  : H323_ExternalRTPChannel::H323_ExternalRTPChannel(connection, capability, direction, id, data, control)
 {
+
+	_connection = &connection;
+
 } 
 
 MyH323_ExternalRTPChannel::~MyH323_ExternalRTPChannel()
@@ -793,7 +1206,15 @@
         if (H323_ExternalRTPChannel::OnReceivedAckPDU(param)) {
                H323_ExternalRTPChannel::GetRemoteAddress(remoteIpAddress, remotePort);
                /* Notify Asterisk of remote RTP information */
-               on_start_logical_channel(connection.GetCallReference(), (const char *)remoteIpAddress.AsString(), remotePort);
+		//Due to the strange rtp polling in openh323
+		//Prevent Asterisk main core from streaming RTP data to 
+		//native bridged peer.
+		//TODO: cleaning up that mess and doing it properly
+		if (GetDirection()==H323Channel::IsTransmitter && !_connection->isLocalInitiated && _connection->bridging) {
+			AST_LOG(2, "[MyH323_ExternalRTPChannel] Connection is bridging - not advising PBX on transmitter creation");
+			return TRUE;
+		}
+                on_start_logical_channel(connection.GetCallReference(), (const char *)remoteIpAddress.AsString(), remotePort);
                 return TRUE;
         }
         return FALSE;
@@ -844,14 +1265,25 @@
 	delete localProcess;
 }
 
-void h323_debug(int flag, unsigned level)
+void h323_trace(int flag, unsigned level)
 {
+
 	if (flag) {
 		PTrace:: SetLevel(level); 
 	} else { 
 		PTrace:: SetLevel(0); 
 	}
 }
+
+void h323_debug(int flag, unsigned level)
+{
+
+	if (flag) {
+		AstLog::SetLevel(level);
+	} else {
+		AstLog::SetLevel(0);
+	}
+}
 	
 /** Installs the callback functions on behalf of the PBX application  */
 void h323_callback_register(setup_incoming_cb  	ifunc,
@@ -1232,5 +1667,62 @@
 
 }
 
+int h323_prepare_forwarding(const char *token, char *us_addr, unsigned int *us_port)
+{
+        unsigned int roro;
+        PString newToken;
+        unsigned int port;
+        const PString token0 = PString(token);
+
+        if (endPoint->H245HoldCall(token0, newToken, &roro, 0, NULL) != 0) {
+		AST_LOG(1, "ERROR: [h323_prepare_forwarding] Failed to put " << token0 << " on hold");
+                return 1;
+        }
+
+        PString rtpAddr = PString("",80);
+
+        if (endPoint->H245WakeUpCall(token0, rtpAddr, &port, 0, NULL) != 0) {
+		AST_LOG(1, "ERROR: [h323_prepare_forwarding] Failed to wake up call " << token0);
+                return 1;
+        }
+
+        AST_LOG(4, "Call: " << token << "successfully waken up\n"
+                      << "Assigned values are:\n " 
+                      <<"  -- rtpAddr = " << rtpAddr << "\n"
+                      <<"  -- port = " << port);
+
+	const char * sarass = (const char *)rtpAddr;
+	*us_port = port;
+
+	if (strlen(sarass) > 16) {
+		AST_LOG(1, "ERROR: [h323_prepare_forwarding] char size exceeded");
+		return 1;
+	}
+
+	if(strcpy(us_addr, sarass) == NULL) {
+		AST_LOG(1, "Error: [h323_prepare_forwarding] copying strings failed");
+		return 1;
+	}
+
+        return 0;
+}
+
+int h323_perform_forwarding(const char *token, char *them_addr, unsigned int *them_port)
+{
+
+        PString themAddress = PString(them_addr);
+        WORD port = *them_port;
+
+        const PString token0 = PString(token);
+
+        if (endPoint->H245GetUpCall(token0, themAddress, port)) {
+		AST_LOG(1, "Endpoint::H245 GetUpCall failed");
+                return 1;
+        }
+
+        return 0;
+}
+
+
 } /* extern "C" */
 
--- /usr/src/asterisk/channels/h323/ast_h323.h	2004-06-26 05:50:14.000000000 +0200
+++ ./channels/h323/ast_h323.h	2004-08-02 14:56:25.000000000 +0200
@@ -191,6 +191,12 @@
 	int MakeCall(const PString &, PString &, unsigned int *, unsigned int, char *, char *s);
 	BOOL ClearCall(const PString &);
 
+        //H245 Call holding and restarting functions, used when native bridging
+        int H245HoldCall(const PString &, PString &, unsigned int *, unsigned int, char *);
+        int H245WakeUpCall(const PString &, PString &, unsigned int *, unsigned int, char *);
+        int H245GetUpCall(const PString &, PString &, WORD &);
+        int H245RetreiveCall(const PString &, PString &, unsigned int *, unsigned int, char *);
+                                
 	void OnClosedLogicalChannel(H323Connection &, const H323Channel &);
 	void OnConnectionEstablished(H323Connection &, const PString &);
 	void OnConnectionCleared(H323Connection &, const PString &);
@@ -232,6 +238,22 @@
 	void OnUserInputTone(char, unsigned, unsigned, unsigned);
 	void OnUserInputString(const PString &value);
 
+       
+        void OnSelectLogicalChannels();
+        BOOL OnOpenLogicalChannel(const H245_OpenLogicalChannel & openPDU, H245_OpenLogicalChannelAck & ackPDU,
+                                                          unsigned & errorCode);
+        BOOL OnH245Response(const H323ControlPDU & pdu);
+        BOOL OnH245Request(const H323ControlPDU & pdu);
+        
+        //H245 Call Holding and restarting functions, used when native bridging
+        BOOL H245HoldCall(BOOL localhold);
+        BOOL H245WakeUpCall(PString&, unsigned int *);
+        BOOL H245GetUpCall(PIPSocket::Address &, WORD &);
+        BOOL H245RetreiveCall(const PString& destination);
+        BOOL IsH245LocalHold();
+        BOOL IsH245RemoteHold();
+        
+        
 	PString sourceAliases;
 	PString destAliases;
 	PString sourceE164;
@@ -240,7 +262,48 @@
 	PIPSocket::Address externalIpAddress;	
 	WORD externalPort;
 	WORD sessionId;
-	BOOL bridging;			
+	BOOL bridging;	
+        //True when the connection is initiated from this driver       
+        BOOL isLocalInitiated; 
+
+
+        //When modifing a state do not forget to modify operator<< 
+        //definition too
+        
+        enum H245HoldStates {
+                NoHold,
+                AwaitingRemoteCloseChannel,
+                RemoteHold,
+                AwaitingRemoteCloseChannelAck,
+                LocalHold,
+                BothHold,
+                WakingUp,
+                Retreiving,
+                NumStates
+        };
+
+        void SetH245HoldState(H245HoldStates  state);
+        void OnSetH245HoldState(H245HoldStates state);
+        
+        friend ostream & operator<<(ostream & out, H245HoldStates state);
+
+        //Used by channel bridging functions
+   
+        PIPSocket::Address remoteIpAddress; 
+        WORD remotePort;
+
+        protected:
+
+        H245HoldStates h245HoldState;
+                
+        private:
+
+        PSyncPoint myHoldSyncPoint;
+        PSyncPoint receiverSyncPoint;
+        PSyncPoint transmitterSyncPoint;
+
+        H245_TransportAddress bridgingTransport;
+        
 };
 
 class MyH323_ExternalRTPChannel : public H323_ExternalRTPChannel {
@@ -278,8 +341,36 @@
 
      	PIPSocket::Address externalIpAddress;   
      	WORD externalPort;               
+
+        protected:
+
+        /*Used to deal with on_start_logical_channel removal from MyH323Connection*/
+        MyH323Connection *  _connection;
 }; 
 
+/* ast_log-like debuging functions
+ * debug is activated throught the cli
+ * Usage:  AST_LOG(level, args)
+ */
+
+static unsigned Ast_TraceLevelThreshold = 0;
+
+class AstLog : public PTrace {
+
+        public:
+        
+        static BOOL CanTrace(unsigned level) { return level <= Ast_TraceLevelThreshold; }
+        static void SetLevel(unsigned level) { Ast_TraceLevelThreshold = level; }
+};
+
+#define AST_LOG(level, args) \
+    if (!AstLog::CanTrace(level)) ; else \
+          AstLog::Begin(level, __FILE__, __LINE__) << args << AstLog::End
+
+#define AST_LOG_IF(level, cond, args) \
+              if (!(AstLog::CanTrace(level)  && (cond))) ; else \
+                    AstLog::Begin(level, __FILE__, __LINE__) << args << PTrace::End
+                    
 /**
  * The MyProcess is a necessary descendant PProcess class so that the H323EndPoint 
  * objected to be created from within that class. (Who owns main() problem). 
