RE: Re: Re: Rewriting E164 numbers after GW selection

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



To Jan Willamowius
And Michal Zigmuntowicz

Gentleman,
May we all ask you to implement this patch to 2.0.7
This is really necessary for all GNUGK users, especially for a VoIP
terminators and traders.

Thank you in advance,
Oleg
 

-----Original Message-----
From: openh323gk-users-admin@lists.sourceforge.net
[mailto:openh323gk-users-admin@lists.sourceforge.net] On Behalf Of
Ian.Campbell@band-x.com
Sent: Tuesday, December 16, 2003 1:23 PM
To: openh323gk-users@lists.sourceforge.net;
openh323gk-developer@lists.sourceforge.net
Cc: Justin.Wells@band-x.com
Subject:  Re: Re: Rewriting E164 numbers after GW
selection

Hello All,
	I have finally got round to implementing per gateway E164 number
rewriting as discussed in this thread in early November. Attached is a patch
providing it for version 2.0.6. The code provides triple stage rewriting:

per gw input E164 rewriting -> standard E164 rewriting -> (endpoint
selection) -> per gw output E164 rewriting 

This is configured in a new configuration section as follows:

[RasSrv::GWRewriteE164]
foo=out=1223=2323
foo=out=13=4444
foo=in=777=8888
bar=in=777=9999 

And so on. The first element in the line is the GW that the rule is being
applied to the second the direction (whether it is applied before the
standard rewriting and the endpoint selection or after) and finally the rule
itself in the same as the standard rewriting ([RasSrv::RewriteE164]). All
this allows much more sophisticated control of what is sent to the endpoint
for example an authentication prefix and per endpoint routing policies to be
constructed. The code has been tested by me, but should probably be
considered alpha quality for now. 

Jan et al. is there anything I need to do (beyond applying this to the 2.2
CVS archive) to get this included in a future release? 

Regards,

Ian Campbell
Band-X Ltd.

diff -r -U 3 openh323gk/ProxyChannel.cxx
openh323gk.gwrewrite/ProxyChannel.cxx
--- openh323gk/ProxyChannel.cxx	2003-09-24 10:19:44.000000000 +0000
+++ openh323gk.gwrewrite/ProxyChannel.cxx	2003-12-15
16:55:05.000000000 +0000
@@ -393,6 +393,8 @@
 
 ProxySocket::Result CallSignalSocket::ReceiveData()  {
+	PString in_rewrite_id,out_rewrite_id;
+
 	if (!ReadTPKT())
 		return NoData;
 
@@ -424,7 +426,7 @@
 			}
 			m_crv = (m_lastQ931->GetCallReference() | 0x8000u);
 			m_setupUUIE = new H225_H323_UserInformation(signal);
-			changed = OnSetup(body);
+			changed =
OnSetup(body,in_rewrite_id,out_rewrite_id);
 			break;
 		case H225_H323_UU_PDU_h323_message_body::e_callProceeding:
 			changed = OnCallProceeding(body);
@@ -492,11 +494,28 @@
 	if (m_lastQ931->HasIE(Q931::CalledPartyNumberIE)) {
 		unsigned plan, type;
 		PString calledNumber;
+
+		// Do per GW inbound rewrite before global rewrite
+		if (m_lastQ931->GetCalledPartyNumber(calledNumber, &plan,
&type) &&
+
Toolkit::Instance()->GWRewritePString(in_rewrite_id,true,calledNumber)) {
+			m_lastQ931->SetCalledPartyNumber(calledNumber, plan,
type);
+			changed = true;
+		}
+
+		// Normal rewrite
 		if (m_lastQ931->GetCalledPartyNumber(calledNumber, &plan,
&type) &&
 		    Toolkit::Instance()->RewritePString(calledNumber)) {
 			m_lastQ931->SetCalledPartyNumber(calledNumber, plan,
type);
 			changed = true;
 		}
+
+		// Do per GW outbound rewrite after global rewrite
+		if (m_lastQ931->GetCalledPartyNumber(calledNumber, &plan,
&type) &&
+
Toolkit::Instance()->GWRewritePString(out_rewrite_id,false,calledNumber)) {
+			m_lastQ931->SetCalledPartyNumber(calledNumber, plan,
type);
+			changed = true;
+		}
+
 	}
 
 	if (m_lastQ931->HasIE(Q931::DisplayIE)) { @@ -687,6 +706,9 @@
 
 TCPProxySocket *CallSignalSocket::ForwardCall()  {
+
+	PString in_rewrite_id,out_rewrite_id;
+
 	// disconnect from forwarder
 
SendReleaseComplete(H225_ReleaseCompleteReason::e_facilityCallDeflection);
 	Close();
@@ -744,7 +766,7 @@
 	ret->m_h245handler = 0;
 
 	CallSignalSocket *result = 0;
-	if (ret->OnSetup(SetupUUIE)) {
+	if (ret->OnSetup(SetupUUIE,in_rewrite_id,out_rewrite_id)) {
 		SetUUIE(*Setup, suuie);
 		Setup->Encode(ret->buffer);
 		PrintQ931(5, "Forward Setup to " + ret->remote->Name(),
Setup, &suuie); @@ -774,7 +796,7 @@
 	return result;
 }
 
-bool CallSignalSocket::OnSetup(H225_Setup_UUIE & Setup)
+bool CallSignalSocket::OnSetup(H225_Setup_UUIE & Setup, PString
&in_rewrite_id, PString &out_rewrite_id)  {
 	const time_t setupTime = time(NULL);
 
@@ -791,8 +813,26 @@
 			H323SetAliasAddress(destination,
Setup.m_destinationAddress[0]);
 		}
 	}
-	if (Setup.HasOptionalField(H225_Setup_UUIE::e_destinationAddress))
+	if (Setup.HasOptionalField(H225_Setup_UUIE::e_destinationAddress)) {
+
+		// Do inbound per GWRewrite if we can before global rewrite
+		if (Setup.HasOptionalField(H225_Setup_UUIE::e_sourceAddress)
== true) {
+			PString source;
+			PStringArray tokenised_source;
+			source = AsString(Setup.m_sourceAddress);
+
+			// Chop up source to get the h323_ID or dialedDigits
+			tokenised_source = source.Tokenise(PString(":"));
+
+			if (tokenised_source.GetSize() == 2) {
+
Toolkit::Instance()->GWRewriteE164(tokenised_source[0],true,Setup.m_destinat
ionAddress);
+				in_rewrite_id = tokenised_source[0];
+			}
+		}
+
+		// Normal rewrite
 
Toolkit::Instance()->RewriteE164(Setup.m_destinationAddress);
+	}
 
 #if PTRACING
 	PString callid;
@@ -815,10 +855,11 @@
 	GkClient *gkClient = RasThread->GetGkClient();
 	Address fromIP;
 	GetPeerAddress(fromIP);
+
 	if (m_call) {
 #ifdef HAS_ACCT
 		if( m_call->GetCalledStationId().IsEmpty() )
-			if(
Setup.HasOptionalField(H225_Setup_UUIE::e_destinationAddress) 
+			if(
Setup.HasOptionalField(H225_Setup_UUIE::e_destinationAddress)
 				&& (Setup.m_destinationAddress.GetSize() >
0) )
 			{
 				const PString calledPartyNumber =
GetBestAliasAddressString(
@@ -830,10 +871,10 @@
 				if( !calledPartyNumber.IsEmpty() )
 
m_call->SetCalledStationId(calledPartyNumber);
 			}
-		
+
 #endif
 		m_call->SetSetupTime(setupTime);
-		
+
 		if (m_call->IsSocketAttached()) {
 			PTRACE(2, "Q931\tWarning: socket already attached
for callid " << callid);
 			return false;
@@ -866,7 +907,7 @@
 		*/
 		{
 			ReadLock cfgLock(ConfigReloadMutex);
-		
+
 			GkAuthenticatorList* authList =
RasThread->GetAuthList();
 			if( authList )
 			{
@@ -877,7 +918,7 @@
 					PTRACE(3,"GKAUTH\tH.225 Setup
authentication failed: "<<reason);
 					return false;
 				}
-			
+
 				if( limit > 0 )
 					m_call->SetDurationLimit( limit );
 			}
@@ -901,14 +942,16 @@
 				}
 #endif
 		}
+
 	} else {
 		bool fromParent;
 		if (!RasThread->AcceptUnregisteredCalls(fromIP, fromParent))
{
 			PTRACE(3, "Q931\tNo CallRec found in CallTable for
callid " << callid);
 			return false;
 		}
-		if (fromParent)
+		if (fromParent) {
 			gkClient->RewriteE164(*m_lastQ931, Setup, false);
+		}
 
 		endptr called;
 		PString destinationString;
@@ -934,14 +977,14 @@
 		// workaround for bandwidth, as OpenH323 library :p
 		CallRec *call = new CallRec(Setup.m_callIdentifier,
Setup.m_conferenceID, destinationString, sourceString, 100000, h245Routed);
 		call->SetCalled(called, m_crv);
-		
-		call->SetSetupTime(setupTime);		
-		
+
+		call->SetSetupTime(setupTime);
+
 		long durationLimit = -1;
-		
+
 		{
 			ReadLock cfgLock(ConfigReloadMutex);
-		
+
 			GkAuthenticatorList* authList =
RasThread->GetAuthList();
 			if( authList )
 			{
@@ -955,7 +998,7 @@
 			}
 
 #ifdef HAS_ACCT
-			if(
Setup.HasOptionalField(H225_Setup_UUIE::e_destinationAddress) 
+			if(
Setup.HasOptionalField(H225_Setup_UUIE::e_destinationAddress)
 				&& (Setup.m_destinationAddress.GetSize() >
0) ) {
 				const PString calledPartyNumber =
GetBestAliasAddressString(
 					Setup.m_destinationAddress,
@@ -966,7 +1009,7 @@
 				if( !calledPartyNumber.IsEmpty() )
 
call->SetCalledStationId(calledPartyNumber);
 			}
-				
+
 			GkAcctLoggers* acct =
Toolkit::Instance()->GetAcctList();
 			if( acct != NULL )
 				if( call->GetAcctEventsLogged() &
GkAcctLogger::AcctStart )
@@ -988,7 +1031,7 @@
 				}
 #endif
 		}
-		
+
 		if( durationLimit > 0 )
 			call->SetDurationLimit( durationLimit );
 
@@ -1000,6 +1043,26 @@
 		}
 	}
 
+	// Do outbound per GW rewrite
+	if (Setup.HasOptionalField(H225_Setup_UUIE::e_destinationAddress)) {
+		endptr rewriteEndPointOut = m_call->GetCalledParty();
+		if (rewriteEndPointOut != NULL) {
+			PString source;
+			PStringArray tokenised_source;
+
+			source =
AsString(rewriteEndPointOut->GetAliases()[0]);
+
+			// Chop up source to get the h323_ID or dialedDigits
+			tokenised_source = source.Tokenise(PString(":"));
+
+			if (tokenised_source.GetSize() == 2) {
+
Toolkit::Instance()->GWRewriteE164(tokenised_source[0],false,Setup.m_destina
tionAddress);
+				out_rewrite_id = tokenised_source[0];
+			}
+
+		}
+	}
+
 	const H225_TransportAddress *addr = m_call->GetCalledAddress();
 	if (!addr || !GetIPAndPortFromTransportAddr(*addr, peerAddr,
peerPort)) {
 		CallTable::Instance()->RemoveCall(m_call);
@@ -1067,7 +1130,7 @@
 {
 	if (m_call) // hmm... it should not be null
 		m_call->SetConnected();
-	
+
 #ifndef NDEBUG
 	if (!Connect.HasOptionalField(H225_Connect_UUIE::e_callIdentifier))
{
 		PTRACE(1, "Q931\tConnect_UUIE doesn't contain
CallIdentifier!"); diff -r -U 3 openh323gk/ProxyChannel.h
openh323gk.gwrewrite/ProxyChannel.h
--- openh323gk/ProxyChannel.h	2003-04-10 02:39:55.000000000 +0000
+++ openh323gk.gwrewrite/ProxyChannel.h	2003-12-15 16:46:50.000000000 +0000
@@ -94,7 +94,7 @@
 
 	LogicalChannel *FindLogicalChannel(WORD);
 	RTPLogicalChannel *FindRTPLogicalChannelBySessionID(WORD);
-	
+
 private:
 	// override from class H245Handler
 	virtual bool HandleRequest(H245_RequestMessage &); @@ -152,7 +152,7
@@
 	TCPProxySocket *InternalConnectTo();
 	TCPProxySocket *ForwardCall();
 
-	bool OnSetup(H225_Setup_UUIE &);
+	bool OnSetup(H225_Setup_UUIE &, PString &in_rewrite_id, PString
&out_rewrite_id);
 	bool OnCallProceeding(H225_CallProceeding_UUIE &);
 	bool OnConnect(H225_Connect_UUIE &);
 	bool OnAlerting(H225_Alerting_UUIE &); diff -r -U 3
openh323gk/RasSrv.cxx openh323gk.gwrewrite/RasSrv.cxx
--- openh323gk/RasSrv.cxx	2003-09-24 10:19:44.000000000 +0000
+++ openh323gk.gwrewrite/RasSrv.cxx	2003-12-16 12:27:21.000000000 +0000
@@ -20,7 +20,7 @@
 //
 //////////////////////////////////////////////////////////////////
 
-#if (_MSC_VER >= 1200)  
+#if (_MSC_VER >= 1200)
 #pragma warning( disable : 4800 ) // one performance warning off  #pragma
warning( disable : 4786 ) // warning about too long debug symbol off
#define snprintf _snprintf @@ -361,7 +361,7 @@
 		}
 	}
 }
- 
+
 #if HAS_WAITARQ
 BOOL H323RasSrv::RouteToAlias(PString TargetAlias, PString SourceEpId,
PString CallRef)  { @@ -374,7 +374,7 @@
 	return wArqList->RouteReject(SourceEpId, CallRef);  }  #endif
- 
+
 int NeighborList::SendLRQ(int seqNum, const H225_AdmissionRequest &
obj_arq, const endptr & e)  {
 	int nbCount = 0;
@@ -396,7 +396,7 @@
 			}
 		}
 	}
-	
+
 	eIter = List.end();
 	for(Iter = List.begin(); Iter != eIter; ++Iter) {
 		if (Iter->SendLRQ(seqNum, obj_arq, RasSrv, e)) @@ -428,7
+428,7 @@
 			}
 		}
 	}
-	
+
 	eIter = List.end();
 	for(Iter = List.begin(); Iter != eIter; ++Iter) {
 		if (Iter->ForwardLRQ(ip, obj_lrq, RasSrv)) @@ -470,7 +470,7
@@
       : PThread(10000, NoAutoDeleteThread), requestSeqNum(0)  {
 	GKHome = _GKHome;
-	
+
         GKRasPort = GkConfig()->GetInteger("UnicastRasPort",
GK_DEF_UNICAST_RAS_PORT);
 
 	EndpointTable = RegistrationTable::Instance(); //initialisation is
done in LoadConfig @@ -492,7 +492,7 @@  #if HAS_WAITARQ
 	wArqList = new WaitingARQlist();
 #endif
- 
+
 	LoadConfig();
 
 	arqPendingList = new NBPendingList(this,
GkConfig()->GetInteger(LRQFeaturesSection, "NeighborTimeout", 2)); @@ -536,7
+536,7 @@  #if HAS_WAITARQ
 	delete wArqList ;
 #endif
- 
+
 }
 
 void H323RasSrv::SetRoutedMode(bool routedSignaling, bool routedH245) @@
-638,7 +638,7 @@
 		const PStringArray tokens = altgks[idx].Tokenise(":",
FALSE);
 		if (tokens.GetSize() < 4) {
 			PTRACE(1,"GK\tFormat error in AlternateGKs");
-			continue; 
+			continue;
 		}
 
 		H225_AlternateGK & A = altGKs[idx];
@@ -679,19 +679,19 @@
         delete destAnalysisList;
 	destAnalysisList = new GkDestAnalysisList(GkConfig());
 	EndpointTable->Initialize(*destAnalysisList);
-	
+
 #if defined(HAS_LDAP)		// shall use LDAP
-	
+
 	// initialize LDAP
 	GkLDAP::Instance()->Initialize(*GkConfig());
-	
+
 #endif // HAS_LDAP
 
 #if defined(HAS_WAITARQ)		// supports VirtualQueues
 	// (re) load config
 	wArqList->LoadConfig();
 #endif
-	
+
 	// add neighbors
 	delete NeighborsGK;
 	NeighborsGK = new NeighborList(this, GkConfig()); @@ -729,7 +729,7
@@
 		delete GkStatusThread;
 		GkStatusThread = 0;
 	}
- 
+
 	PTRACE(1, "GK\tRasSrv closed");
 }
 
@@ -854,7 +854,7 @@
 
 	unsigned rsn = H225_GatekeeperRejectReason::e_securityDenial;
 	if ((redirectGK != e_noRedirect) || !authList->Check(obj_gr, rsn)) {
-		obj_rpl.SetTag(H225_RasMessage::e_gatekeeperReject); 
+		obj_rpl.SetTag(H225_RasMessage::e_gatekeeperReject);
 		H225_GatekeeperReject & obj_grj = obj_rpl;
 		obj_grj.m_protocolIdentifier = obj_gr.m_protocolIdentifier;
 		if (redirectGK != e_noRedirect) {
@@ -872,7 +872,7 @@
 			(const unsigned char *)
obj_grj.m_rejectReason.GetTagName()
 			);
 	} else {
-		obj_rpl.SetTag(H225_RasMessage::e_gatekeeperConfirm); 
+		obj_rpl.SetTag(H225_RasMessage::e_gatekeeperConfirm);
 		H225_GatekeeperConfirm & obj_gcf = obj_rpl;
 
 		obj_gcf.m_requestSeqNum = obj_gr.m_requestSeqNum; @@ -900,11
+900,11 @@
 		}
 */
 		SelectH235Capability( obj_gr, obj_gcf  );
-		
+
 		//if (bShellSendReply)cw	  need to forward GRQ?
 		//	ForwardRasMsg(obj_grq);
 
-		msg = PString(PString::Printf, "GCF|%s|%s|%s;\r\n", 
+		msg = PString(PString::Printf, "GCF|%s|%s|%s;\r\n",
 			inet_ntoa(rx_addr),
 			(const unsigned char *) aliasListString,
 			(const unsigned char *)
AsString(obj_gr.m_endpointType) );
@@ -912,13 +912,13 @@
 
 	PTRACE(2, msg);
 	GkStatusThread->SignalStatus(msg);
-		
+
 	return bShellSendReply;
 }
 
 void H323RasSrv::BuildRCF(H225_RasMessage & obj_ras, const
H225_RegistrationRequest & rrq, const endptr & ep, const PIPSocket::Address
& rx_addr)  {
-	obj_ras.SetTag(H225_RasMessage::e_registrationConfirm); 
+	obj_ras.SetTag(H225_RasMessage::e_registrationConfirm);
 	H225_RegistrationConfirm & rcf = obj_ras;
 	rcf.m_requestSeqNum = rrq.m_requestSeqNum;
 	rcf.m_protocolIdentifier = rrq.m_protocolIdentifier; @@ -990,7
+990,7 @@
 			if (bShellSendReply)
 				BuildRCF(obj_rpl, obj_rr, ep, rx_addr);
 			// forward lightweights, too
-			if (bShellForwardRequest) 
+			if (bShellForwardRequest)
 				ForwardRasMsg(obj_rrq);
 
 			ep->Update(obj_rrq);
@@ -1040,7 +1040,7 @@
 			rejectReason =
H225_RegistrationRejectReason::e_securityDenial;
 		}
 	}
-	
+
 	if (!bReject) {
 		unsigned rsn =
H225_RegistrationRejectReason::e_securityDenial;
 		if (!authList->Check(obj_rr, rsn)) {
@@ -1065,7 +1065,7 @@
 				} else {
 					bReject = TRUE;
 					rejectReason =
H225_RegistrationRejectReason::e_duplicateAlias;
-				}	
+				}
 			}
 
 			// reject the empty string
@@ -1089,7 +1089,7 @@
 				rejectReason =
H225_RegistrationRejectReason::e_invalidAlias;
 				break;
 			/* only while debugging
-			default:  
+			default:
 				bReject = TRUE;
 
rejectReason.SetTag(H225_RegistrationRejectReason::e_invalidAlias);
 				break;
@@ -1112,9 +1112,9 @@
 			else
 				ep->SetNAT(false);
 			if (bShellSendReply) {
-				//	
+				//
 				// OK, now send RCF
-				//	
+				//
 				BuildRCF(obj_rpl, obj_rr, ep, rx_addr);
 				H225_RegistrationConfirm & rcf = obj_rpl;
 
rcf.IncludeOptionalField(H225_RegistrationConfirm::e_terminalAlias);
@@ -1148,7 +1148,7 @@
 
 			// Note that the terminalAlias is not optional here
as we pass the auto generated alias if not were provided from
 			// the endpoint itself
-			PString msg(PString::Printf, "RCF|%s|%s|%s|%s;\r\n",

+			PString msg(PString::Printf, "RCF|%s|%s|%s|%s;\r\n",
 				    (const unsigned char *)
AsDotString(ep->GetCallSignalAddress()),
 				    (const unsigned char *)
AsString(ep->GetAliases()),
 				    (const unsigned char *)
AsString(obj_rr.m_terminalType),
@@ -1167,7 +1167,7 @@
 	//
 	// final rejection handling
 	//
-	obj_rpl.SetTag(H225_RasMessage::e_registrationReject); 
+	obj_rpl.SetTag(H225_RasMessage::e_registrationReject);
 	H225_RegistrationReject & rrj = obj_rpl;
 
 	rrj.m_requestSeqNum = obj_rr.m_requestSeqNum; @@ -1185,8 +1185,8 @@
 		aliasListString = AsString(obj_rr.m_terminalAlias);
 	else
 		aliasListString = " ";
-	
-	PString msg(PString::Printf, "RRJ|%s|%s|%s|%s;\r\n", 
+
+	PString msg(PString::Printf, "RRJ|%s|%s|%s|%s;\r\n",
 		    inet_ntoa(rx_addr),
 		    (const unsigned char *) aliasListString,
 		    (const unsigned char *) AsString(obj_rr.m_terminalType),
@@ -1284,18 +1284,18 @@  BOOL H323RasSrv::DoARQ(const PIPSocket::Address &
rx_addr, const H225_RasMessage & obj_arq)  {
 	H225_RasMessage obj_rpl;
-	const H225_AdmissionRequest & obj_rr = obj_arq; 
-	
+	const H225_AdmissionRequest & obj_rr = obj_arq;
+
 	// find the caller
 	const endptr RequestingEP =
EndpointTable->FindByEndpointId(obj_rr.m_endpointIdentifier);
 	if (!RequestingEP) {
 		// TODO: signal error on status thread
 		return false;
 	};
-	 
+
 	BOOL ShallSendReply = OnARQ(rx_addr, obj_arq, obj_rpl);
 
-	if (ShallSendReply) { 
+	if (ShallSendReply) {
 		const H225_TransportAddress_ipAddress & ip =
RequestingEP->GetRasAddress();
 		PIPSocket::Address ipaddress(ip.m_ip[0], ip.m_ip[1],
ip.m_ip[2], ip.m_ip[3]);
 		PTRACE(1, "GK\tDoARQ  sendReply " << ipaddress << " " <<
ip.m_port ); @@ -1304,14 +1304,14 @@
 	return true;
 }
 
- 
+
 /* Admission Request */
 BOOL H323RasSrv::OnARQ(const PIPSocket::Address & rx_addr, const
H225_RasMessage & obj_arq, H225_RasMessage & obj_rpl)
-{    
+{
 	PTRACE(1, "GK\tARQ Received");
 
 	const H225_AdmissionRequest & obj_rr = obj_arq;
- 
+
 	BOOL bReject = FALSE;
 	long callDurationLimit = -1;
 	unsigned rejectReason = 0;
@@ -1321,15 +1321,32 @@
 	const endptr RequestingEP =
EndpointTable->FindByEndpointId(obj_rr.m_endpointIdentifier);
 
 	endptr CalledEP(0);
- 
+
 	if (CallTbl->Size() >= callLimit && !obj_rr.m_answerCall) {
 		bReject = TRUE;
 		rejectReason =
H225_AdmissionRejectReason::e_resourceUnavailable;
 		PTRACE(1, "GK\tWarning: Exceed call limit!!");
 	} else if (RequestingEP) { // Is the ARQ from a registered endpoint?
 		bool bHasDestInfo =
(obj_rr.HasOptionalField(H225_AdmissionRequest::e_destinationInfo) &&
obj_rr.m_destinationInfo.GetSize() >= 1);
-		if (bHasDestInfo) // apply rewriting rules
+		// apply rewriting rules
+		if (bHasDestInfo) {
+
+			PString source;
+			PStringArray tokenised_source;
+
+			// Do inbound per GW rewriting first
+			source = AsString(RequestingEP->GetAliases()[0]);
+
+			// Chop up source to get the h323_ID or dialedDigits
+			tokenised_source = source.Tokenise(PString(":"));
+
+			if (tokenised_source.GetSize() == 2) {
+
Toolkit::Instance()->GWRewriteE164(tokenised_source[0],true,obj_rr.m_destina
tionInfo[0]);
+			}
+
+			// Normal rewriting
 
Toolkit::Instance()->RewriteE164(obj_rr.m_destinationInfo[0]);
+		}
 
 		if (!authList->Check(obj_rr,rsn,callDurationLimit)) {
 			bReject = TRUE;
@@ -1344,7 +1361,7 @@
 				PString alias = H323GetAliasAddressString
(obj_rr.m_destinationInfo[0]);
 				if
(wArqList->IsDestinationVirtualQueue(alias)) {
 					PString src = (RequestingEP) ?
AsDotString(RequestingEP->GetCallSignalAddress()) : PString(" ");
-					PString msg(PString::Printf,
"RouteRequest|%s|%s|%u|%s|%s;\r\n", 
+					PString msg(PString::Printf,
"RouteRequest|%s|%s|%u|%s|%s;\r\n",
 							(const unsigned char
*) src,
 							(const unsigned char
*) RequestingEP->GetEndpointIdentifier().GetValue(),
 							(unsigned)
obj_rr.m_callReferenceValue,
@@ -1372,7 +1389,7 @@
 			if (!CalledEP && bHasDestInfo) {
 #if WITH_DEST_ANALYSIS_LIST
 				CalledEP =
EndpointTable->getMsgDestination(obj_rr, rsn);
-				if (!CalledEP && 
+				if (!CalledEP &&
 						rsn ==
H225_AdmissionRejectReason::e_incompleteAddress) {
 					bReject = TRUE;
 					rejectReason = rsn;
@@ -1402,12 +1419,29 @@
 		}
 	}
 	if (bReject) {
-		obj_rpl.SetTag(H225_RasMessage::e_admissionReject); 
-		H225_AdmissionReject & arj = obj_rpl; 
+		obj_rpl.SetTag(H225_RasMessage::e_admissionReject);
+		H225_AdmissionReject & arj = obj_rpl;
 		arj.m_rejectReason.SetTag(rejectReason);
 		if (rejectReason ==
H225_AdmissionRejectReason::e_resourceUnavailable)
 			SetAltGKInfo(arj);
 	}
+
+	// Per GW outbound
+	if (CalledEP && (RequestingEP != CalledEP)) {
+		PString source;
+		PStringArray tokenised_source;
+
+		source = AsString(CalledEP->GetAliases()[0]);
+
+		// Chop up source to get the h323_ID or dialedDigits
+		tokenised_source = source.Tokenise(PString(":"));
+
+		if (tokenised_source.GetSize() == 2) {
+
Toolkit::Instance()->GWRewriteE164(tokenised_source[0],false,obj_rr.m_destin
ationInfo[0]);
+		}
+
+	}
+
 	ProcessARQ(rx_addr, RequestingEP, CalledEP, obj_rr, obj_rpl,
bReject);
 	if( callDurationLimit > 0 ) {
 		callptr pExistingCallRec =
(obj_rr.HasOptionalField(H225_AdmissionRequest::e_callIdentifier)) ?
@@ -1451,16 +1485,16 @@
 
 #ifdef ARJREASON_ROUTECALLTOSCN
  	//
- 	// call from one GW to itself? 
+ 	// call from one GW to itself?
  	// generate ARJ-reason: 'routeCallToSCN'
  	//
- 	if(!bReject && 
+ 	if(!bReject &&
  	   Toolkit::AsBool(GkConfig()->GetString("RasSrv::ARQFeatures",
"ArjReasonRouteCallToSCN", "1")))
  	{
  		// are the endpoints the same (GWs of course)?
- 		if( (CalledEP) && (RequestingEP) && (CalledEP ==
RequestingEP) && 
+ 		if( (CalledEP) && (RequestingEP) && (CalledEP ==
RequestingEP) &&
  			(!obj_arq.m_answerCall) // only first ARQ may be
rejected with with 'routeCallToSCN'
- 			) 
+ 			)
  		{
  			// we have to extract the SCN from the destination.
only EP-1 will be rejected this way
  			if ( obj_arq.m_destinationInfo.GetSize() >= 1 ) { @@
-1471,14 +1505,14 @@
  				// set defaults
 
PPN.m_publicTypeOfNumber.SetTag(H225_PublicTypeOfNumber::e_unknown);
  				PPN.m_publicNumberDigits = "";
- 				
+
  				// there can be diffent information in the
destination info
 
switch(obj_arq.m_destinationInfo[0].GetTag()) {
- 				case H225_AliasAddress::e_dialedDigits: 
+ 				case H225_AliasAddress::e_dialedDigits:
  					// normal number, extract only the
digits
  					PPN.m_publicNumberDigits =
AsString(obj_arq.m_destinationInfo[0], FALSE);
  					break;
- 				case H225_AliasAddress::e_partyNumber: 
+ 				case H225_AliasAddress::e_partyNumber:
  					// ready-to-use party number
  					PN = obj_arq.m_destinationInfo[0];
  					break;
@@ -1486,7 +1520,7 @@
  					PTRACE(1,"Unsupported AliasAdress
for ARQ reason 'routeCallToSCN': "
  						   <<
obj_arq.m_destinationInfo[0]);
  				}
- 				
+
  				// set the ARJ reason
  				bReject = TRUE;
  				rejectReason =
H225_AdmissionRejectReason::e_routeCallToSCN;
@@ -1494,7 +1528,7 @@
  				APN.SetSize(1);
  				APN[0] = PN;
  			}
- 			else { 
+ 			else {
  				// missing destination info. is this
possible at this point?
  			}
  		}
@@ -1533,7 +1567,7 @@
 	}
 
 	//
-	// Bandwidth 
+	// Bandwidth
 	// and GkManager admission
 	//
 	int BWRequest = 1280;
@@ -1565,7 +1599,7 @@
 		arj.m_rejectReason.SetTag(rejectReason);
 		arj.m_requestSeqNum = obj_arq.m_requestSeqNum;
 		SetCryptoTokens(obj_arq, arj);
-		PString msg(PString::Printf, "ARJ|%s|%s|%s|%s|%s;\r\n", 
+		PString msg(PString::Printf, "ARJ|%s|%s|%s|%s|%s;\r\n",
 			    (const unsigned char *) srcInfoString,
 			    (const unsigned char *) destinationInfoString,
 			    (const unsigned char *)
AsString(obj_arq.m_srcInfo),
@@ -1573,7 +1607,7 @@
 			    (const unsigned char *)
arj.m_rejectReason.GetTagName() );
 		PTRACE(2, msg);
 		GkStatusThread->SignalStatus(msg);
- 
+
 		if (CalledEP && CalledEP->IsFromParent()) {
 			H225_RasMessage drq_ras;
 			drq_ras.SetTag(H225_RasMessage::e_disengageRequest);
@@ -1599,8 +1633,8 @@
 			// else this may be a duplicate ARQ, ignore!
 			PTRACE(3, "GK\tACF: found existing call no " <<
pExistingCallRec->GetCallNumber());
 		} else {
-			// the call is not in the table		
-			CallRec *pCallRec = new
CallRec(obj_arq.m_callIdentifier, obj_arq.m_conferenceID, 
+			// the call is not in the table
+			CallRec *pCallRec = new
CallRec(obj_arq.m_callIdentifier, obj_arq.m_conferenceID,
 				destinationInfoString,
AsString(obj_arq.m_srcInfo), BWRequest, GKRoutedH245);
 
 			pCallRec->SetCalled(CalledEP,
obj_arq.m_callReferenceValue);
@@ -1611,7 +1645,7 @@
 				pCallRec->SetConnected();
 			CallTbl->Insert(pCallRec);
 		}
-			
+
 		if ( GKRoutedSignaling ) {
 			acf.m_callModel.SetTag(
H225_CallModel::e_gatekeeperRouted );
 			acf.m_destCallSignalAddress =
GetCallSignalAddress(rx_addr);
@@ -1657,7 +1691,7 @@
 		if (destinationInfoString.IsEmpty())
 			destinationInfoString = "unknown destination alias";
 		// always signal ACF
-		PString msg(PString::Printf, "ACF|%s|%s|%u|%s|%s|%s;\r\n", 
+		PString msg(PString::Printf, "ACF|%s|%s|%u|%s|%s|%s;\r\n",
 				(const unsigned char *) srcInfoString,
 				(const unsigned char *)
RequestingEP->GetEndpointIdentifier().GetValue(),
 				(unsigned) obj_arq.m_callReferenceValue, @@
-1729,25 +1763,25 @@
 
 	PString msg;
 	if (bReject) {
-		obj_rpl.SetTag(H225_RasMessage::e_disengageReject); 
+		obj_rpl.SetTag(H225_RasMessage::e_disengageReject);
 		H225_DisengageReject & drj = obj_rpl;
 		drj.m_requestSeqNum = obj_rr.m_requestSeqNum;
 		drj.m_rejectReason.SetTag(rsn);
 		SetCryptoTokens(obj_rr, drj);
 
-		msg = PString(PString::Printf, "DRJ|%s|%s|%u|%s;\r\n", 
+		msg = PString(PString::Printf, "DRJ|%s|%s|%u|%s;\r\n",
 				inet_ntoa(rx_addr),
 				(const unsigned char *)
obj_rr.m_endpointIdentifier.GetValue(),
 				(unsigned) obj_rr.m_callReferenceValue,
 				(const unsigned char *)
drj.m_rejectReason.GetTagName());
 	} else {
-		obj_rpl.SetTag(H225_RasMessage::e_disengageConfirm); 
+		obj_rpl.SetTag(H225_RasMessage::e_disengageConfirm);
 		H225_DisengageConfirm & dcf = obj_rpl;
-		dcf.m_requestSeqNum = obj_rr.m_requestSeqNum;    
+		dcf.m_requestSeqNum = obj_rr.m_requestSeqNum;
 		SetCryptoTokens(obj_rr, dcf);
 
 		// always signal DCF
-		msg = PString(PString::Printf, "DCF|%s|%s|%u|%s;\r\n", 
+		msg = PString(PString::Printf, "DCF|%s|%s|%u|%s;\r\n",
 				inet_ntoa(rx_addr),
 				(const unsigned char *)
obj_rr.m_endpointIdentifier.GetValue(),
 				(unsigned) obj_rr.m_callReferenceValue, @@
-1765,7 +1799,7 @@
 
 /* Unregistration Request */
 BOOL H323RasSrv::OnURQ(const PIPSocket::Address & rx_addr, const
H225_RasMessage &obj_urq, H225_RasMessage &obj_rpl) -{ 
+{
 	PTRACE(1, "GK\tURQ Received");
 
 	const H225_UnregistrationRequest & obj_rr = obj_urq; @@ -1804,18
+1838,18 @@
 		CopyNonStandardData(obj_rr, ucf);
 		SetCryptoTokens(obj_rr, ucf);
 
-		msg = PString(PString::Printf, "UCF|%s|%s;", 
+		msg = PString(PString::Printf, "UCF|%s|%s;",
 			inet_ntoa(rx_addr),
 			(const unsigned char *) endpointIdentifierString) ;
 	} else {
-		// Return URJ	
+		// Return URJ
 		obj_rpl.SetTag(H225_RasMessage::e_unregistrationReject);
 		H225_UnregistrationReject & urj = obj_rpl;
 		urj.m_requestSeqNum = obj_rr.m_requestSeqNum;
 
urj.m_rejectReason.SetTag(H225_UnregRejectReason::e_notCurrentlyRegistered);
 		CopyNonStandardData(obj_rr, urj);
 
-		msg = PString(PString::Printf, "URJ|%s|%s|%s;", 
+		msg = PString(PString::Printf, "URJ|%s|%s|%s;",
 			inet_ntoa(rx_addr),
 			(const unsigned char *) endpointIdentifierString,
 			(const unsigned char *)
urj.m_rejectReason.GetTagName() );
@@ -1824,7 +1858,7 @@
 	PTRACE(2, msg);
 	GkStatusThread->SignalStatus(msg + "\r\n");
 
-	if (bShellForwardRequest) 
+	if (bShellForwardRequest)
 		ForwardRasMsg(obj_urq);
 
 	return bShellSendReply;
@@ -1833,7 +1867,7 @@
 
 /* Bandwidth Request */
 BOOL H323RasSrv::OnBRQ(const PIPSocket::Address & rx_addr, const
H225_RasMessage & obj_rr, H225_RasMessage & obj_rpl) -{ 
+{
 	PTRACE(1, "GK\tBRQ Received");
 
 	const H225_BandwidthRequest & obj_brq = obj_rr; @@ -1868,7 +1902,7
@@
 	if (bReject) {
 		brj.m_rejectReason.SetTag(rsn);
 		CopyNonStandardData(obj_brq, brj);
-		msg = PString(PString::Printf, "BRJ|%s|%s|%u|%s;\r\n", 
+		msg = PString(PString::Printf, "BRJ|%s|%s|%u|%s;\r\n",
 			inet_ntoa(rx_addr),
 			(const unsigned char
*)obj_brq.m_endpointIdentifier.GetValue(),
 			bandwidth,
@@ -1880,7 +1914,7 @@
 		bcf.m_requestSeqNum = obj_brq.m_requestSeqNum;
 		bcf.m_bandWidth = bandwidth;
 		CopyNonStandardData(obj_brq, bcf);
-		msg = PString(PString::Printf, "BCF|%s|%s|%u;\r\n", 
+		msg = PString(PString::Printf, "BCF|%s|%s|%u;\r\n",
 			inet_ntoa(rx_addr),
 			(const unsigned char
*)obj_brq.m_endpointIdentifier.GetValue(),
 			bandwidth);
@@ -1898,11 +1932,33 @@
 	PTRACE(1, "GK\tLRQ Received");
 
 	PString msg;
-	endptr WantedEndPoint;
+	endptr WantedEndPoint,rewriteEndPoint;
 
 	const H225_LocationRequest & obj_lrq = obj_rr;
-	if (obj_lrq.m_destinationInfo.GetSize() > 0)
+	if (obj_lrq.m_destinationInfo.GetSize() > 0) {
+
+		// per GW rewrite first
+		rewriteEndPoint =
EndpointTable->FindByEndpointId(obj_lrq.m_endpointIdentifier);
+		if (rewriteEndPoint) {
+
+			PString source;
+			PStringArray tokenised_source;
+
+			source = AsString(rewriteEndPoint->GetAliases()[0]);
+
+			// Chop up source to get the h323_ID or dialedDigits
+			tokenised_source = source.Tokenise(PString(":"));
+
+			if (tokenised_source.GetSize() == 2) {
+
Toolkit::Instance()->GWRewriteE164(tokenised_source[0],true,obj_lrq.m_destin
ationInfo[0]);
+			}
+
+		}
+
+		// Normal rewrite
 
Toolkit::Instance()->RewriteE164(obj_lrq.m_destinationInfo[0]);
+	}
+
 
 	unsigned rsn = H225_LocationRejectReason::e_securityDenial;
 	PIPSocket::Address ipaddr;
@@ -1938,7 +1994,7 @@
 				lcf.m_rasAddress = GetRasAddress(rx_addr);
 			}
 
-			msg = PString(PString::Printf,
"LCF|%s|%s|%s|%s;\r\n", 
+			msg = PString(PString::Printf,
"LCF|%s|%s|%s|%s;\r\n",
 					inet_ntoa(rx_addr),
 					(const unsigned char *)
WantedEndPoint->GetEndpointIdentifier().GetValue(),
 					(const unsigned char *)
AsString(obj_lrq.m_destinationInfo),
@@ -1958,7 +2014,7 @@
 		lrj.m_rejectReason.SetTag(rsn);
 		CopyNonStandardData(obj_lrq, lrj);
 
-		msg = PString(PString::Printf, "LRJ|%s|%s|%s|%s;\r\n", 
+		msg = PString(PString::Printf, "LRJ|%s|%s|%s|%s;\r\n",
 			     inet_ntoa(rx_addr),
 			     (const unsigned char *)
AsString(obj_lrq.m_destinationInfo),
 			     (const unsigned char *) sourceInfoString, @@
-2003,7 +2059,7 @@
 
 /* Information Request Response */
 BOOL H323RasSrv::OnIRR(const PIPSocket::Address & rx_addr, const
H225_RasMessage &obj_rr, H225_RasMessage &obj_rpl) -{ 
+{
 	PTRACE(1, "GK\tIRR Received");
 
 	const H225_InfoRequestResponse & obj_irr = obj_rr; @@ -2029,7
+2085,7 @@
 
 /* Resource Availability Indicate */
 BOOL H323RasSrv::OnRAI(const PIPSocket::Address & rx_addr, const
H225_RasMessage &obj_rr, H225_RasMessage &obj_rpl) -{ 
+{
 	PTRACE(1, "GK\tRAI Received");
 
 	const H225_ResourcesAvailableIndicate & obj_rai = obj_rr; @@ -2040,7
+2096,7 @@
 	rac.m_requestSeqNum = obj_rai.m_requestSeqNum;
 	rac.m_protocolIdentifier =  obj_rai.m_protocolIdentifier;
 	CopyNonStandardData(obj_rai, rac);
-    
+
 	return TRUE;
 }
 
@@ -2050,13 +2106,13 @@
 	PTRACE(1, "GK\tSCI Received");
 	return FALSE;
 }
- 
+
 BOOL H323RasSrv::OnSCR(const PIPSocket::Address & rx_addr, const
H225_RasMessage & obj_rr, H225_RasMessage & obj_rpl)  {
 	PTRACE(1, "GK\tSCR Received");
 	return FALSE;
 }
- 
+
 BOOL H323RasSrv::OnIgnored(const PIPSocket::Address &, const
H225_RasMessage & obj_rr, H225_RasMessage &)  {
 	PTRACE(2, "GK\t" << obj_rr.GetTagName() << " received and safely
ignored"); @@ -2079,7 +2135,7 @@  #if HAS_WAITARQ
 	wArqList->CheckWaitingARQ();
 #endif
- 
+
 	return !IsTerminated();
 }
 
@@ -2137,7 +2193,7 @@
 
 	PTRACE(1, "GK\tRasThread " << getpid() << " started");
 
-	PString err_msg("ERROR: Request received by gatekeeper: ");   
+	PString err_msg("ERROR: Request received by gatekeeper: ");
 	PTRACE(2, "GK\tEntering connection handling loop");
 
 	// queueSize is useless for UDPSocket
@@ -2150,9 +2206,9 @@
 	gkClient = new GkClient(this);
 	loadLock.Signal(); // OK, the thread is ready
 
-	while (listener.IsOpen()) { 
+	while (listener.IsOpen()) {
 		PIPSocket::Address rx_addr;
-		H225_RasMessage obj_req;   
+		H225_RasMessage obj_req;
 		H225_RasMessage obj_rpl;
 
 		// large mutex! only allow the reloadhandler be executed @@
-2184,7 +2240,7 @@
 			PTRACE(3, "GK\n" << setprecision(2) << obj_req);
 		else
 			PTRACE(2, "GK\tReceived " << obj_req.GetTagName());
-#endif          
+#endif
 
 		if (obj_req.GetTag() <=
H225_RasMessage::e_serviceControlResponse) {
 			if ((this->*rasHandler[obj_req.GetTag()])(rx_addr,
obj_req, obj_rpl))
@@ -2201,14 +2257,14 @@
 	PTRACE(1, "GK\tRasThread terminated!");  }
 
-void H323RasSrv::SelectH235Capability( 
+void H323RasSrv::SelectH235Capability(
 	const H225_GatekeeperRequest& grq,
 	H225_GatekeeperConfirm& gcf
 	)
 {
 	if( authList == NULL )
 		return;
-		
+
 	// if GRQ does not contain a list of authentication mechanisms
simply return
 	if(
!(grq.HasOptionalField(H225_GatekeeperRequest::e_authenticationCapability)
 			&&
grq.HasOptionalField(H225_GatekeeperRequest::e_algorithmOIDs)
@@ -2220,12 +2276,12 @@
 	H225_ArrayOf_PASN_ObjectId algorithmOIDs;
 
 	authList->GetH235Capabilities(mechanisms,algorithmOIDs);
-	
+
 	// And now match H.235 capabilities found with those from GRQ
-	// to find the one to be returned in GCF		
+	// to find the one to be returned in GCF
 	for( int i = 0; i < grq.m_authenticationCapability.GetSize(); i++ )
-		for( int j = 0; j < mechanisms.GetSize(); j++ )	
-			if( grq.m_authenticationCapability[i].GetTag() 
+		for( int j = 0; j < mechanisms.GetSize(); j++ )
+			if( grq.m_authenticationCapability[i].GetTag()
 				== mechanisms[j].GetTag() )
 				for( int l = 0; l < algorithmOIDs.GetSize();
l++ )
 					for( int k = 0; k <
grq.m_algorithmOIDs.GetSize(); k++ )
@@ -2234,7 +2290,7 @@
 							GkAuthenticator*
authenticator = authList ? authList->GetHead() : NULL;
 							while( authenticator
)
 							{
-								if(
authenticator->IsH235Capable()
+								if(
authenticator->IsH235Capable()
 									&&
authenticator->IsH235Capability(
 
mechanisms[j], algorithmOIDs[l]
 
) )
@@ -2243,7 +2299,7 @@
 
gcf.m_authenticationMode = mechanisms[j];
 
gcf.IncludeOptionalField(H225_GatekeeperConfirm::e_algorithmOID);
 
gcf.m_algorithmOID = algorithmOIDs[l];
-									
+
 
PTRACE(4,"GK\tGCF will select authentication mechanism: "
 
<<mechanisms[j]<<" and algorithm OID: "<<algorithmOIDs[l]
 
);
@@ -2251,7 +2307,7 @@
 								}
 
authenticator = authenticator->GetNext();
 							}
-							
+
 
PTRACE(5,"GK\tAuthentication mechanism: "
 
<<mechanisms[j]<<" and algorithm OID: "
 
<<algorithmOIDs[l]<<" dropped"
diff -r -U 3 openh323gk/Toolkit.cxx openh323gk.gwrewrite/Toolkit.cxx
--- openh323gk/Toolkit.cxx	2003-06-19 15:37:59.000000000 +0000
+++ openh323gk.gwrewrite/Toolkit.cxx	2003-12-16 12:22:48.000000000 +0000
@@ -276,9 +276,9 @@
 			break;
 		}
 	}
-	
-	// 
-	// Do the rewrite. 
+
+	//
+	// Do the rewrite.
 	// @param #t# will be written to #s#
 	//
 	if (do_rewrite) {
@@ -286,10 +286,220 @@
 		s = t;
 		changed = true;
 	}
-	
+
 	return changed;
 }
 
+// class Toolkit::GWRewriteTool
+
+static const char *GWRewriteSection = "RasSrv::GWRewriteE164";
+
+Toolkit::GWRewriteTool::~GWRewriteTool() {
+	for (PINDEX i = 0; i < m_GWRewrite.GetSize(); ++i) {
+		delete &(m_GWRewrite.GetDataAt(i));
+	}
+	m_GWRewrite.RemoveAll();
+}
+
+bool Toolkit::GWRewriteTool::RewritePString(PString gw, bool direction,
PString &data) {
+
+	GWRewriteEntry *gw_entry;
+	std::vector<std::pair<PString,PString> >::iterator rule_iterator;
+	PString key,value;
+	bool inverted;
+	int striplen;
+
+	// First lookup the GW in the dictionary
+	gw_entry = m_GWRewrite.GetAt(gw);
+
+	if (gw_entry == NULL) {
+		return false;
+	}
+
+	// True is "in" direction
+	if (direction == true) {
+		for (rule_iterator = gw_entry->m_entry_data.first.begin();
rule_iterator != gw_entry->m_entry_data.first.end(); ++rule_iterator) {
+			key = (*rule_iterator).first;
+			inverted = false;
+
+			// Inverted match sense
+			if (key.GetLength() !=0 && key[0] == '!') {
+				inverted = true;
+				key = key.Mid(1);
+			}
+
+			// Attempt match
+			if ((strncmp(data, key, key.GetLength()) == 0) ^
inverted) {
+
+				// Start rewrite
+				value = (*rule_iterator).second;
+				striplen = (inverted) ? 0 : key.GetLength();
+				value += data.Mid(striplen);
+
+				// Log
+				PTRACE(2, "\tGWRewriteTool::RewritePString:
" << data << " to " << value);
+
+				// Finish rewrite
+				data = value;
+
+				break;
+			}
+
+		}
+
+	}
+	else {
+		for (rule_iterator = gw_entry->m_entry_data.second.begin();
rule_iterator != gw_entry->m_entry_data.second.end(); ++rule_iterator) {
+			key = (*rule_iterator).first;
+			inverted = false;
+
+			// Inverted match sense
+			if (key.GetLength() !=0 && key[0] == '!') {
+				inverted = true;
+				key = key.Mid(1);
+			}
+
+			// Attempt match
+			if ((strncmp(data, key, key.GetLength()) == 0) ^
inverted) {
+
+				// Start rewrite
+				value = (*rule_iterator).second;
+				striplen = (inverted) ? 0 : key.GetLength();
+				value += data.Mid(striplen);
+
+				// Log
+				PTRACE(2, "\tGWRewriteTool::RewritePString:
" << data << " to " << value);
+
+				// Finish rewrite
+				data = value;
+
+				break;
+			}
+
+		}
+
+	}
+
+
+	return true;
+
+}
+
+void Toolkit::GWRewriteTool::PrintData() {
+
+	std::vector<std::pair<PString,PString> >::iterator rule_iterator;
+
+	PTRACE(2, "GK\tLoaded per GW rewrite data:");
+
+	if (m_GWRewrite.GetSize() == 0) {
+		PTRACE(2, "GK\tNo per GW data loaded");
+		return;
+	}
+
+	for (PINDEX i = 0; i < m_GWRewrite.GetSize(); ++i) {
+
+		// In
+		for (rule_iterator =
m_GWRewrite.GetDataAt(i).m_entry_data.first.begin(); rule_iterator !=
m_GWRewrite.GetDataAt(i).m_entry_data.first.end(); ++rule_iterator) {
+			PTRACE(3, "GK\t" << m_GWRewrite.GetKeyAt(i) << "
(in): " << (*rule_iterator).first << " = " << (*rule_iterator).second);
+		}
+
+		// Out
+		for (rule_iterator =
m_GWRewrite.GetDataAt(i).m_entry_data.second.begin(); rule_iterator !=
m_GWRewrite.GetDataAt(i).m_entry_data.second.end(); ++rule_iterator) {
+			PTRACE(3, "GK\t" << m_GWRewrite.GetKeyAt(i) << "
(out): " << (*rule_iterator).first << " = " << (*rule_iterator).second);
+		}
+
+	}
+
+	PTRACE(2, "GK\tLoaded " << m_GWRewrite.GetSize() << " GW entries
with rewrite info");
+
+}
+
+
+void Toolkit::GWRewriteTool::LoadConfig(PConfig *config) {
+
+	PINDEX gw_size, i, j, lines_size;
+	PString key, cfg_value;
+	PStringArray lines, tokenised_line;
+	GWRewriteEntry *gw_entry;
+	std::map<PString,PString> in_strings, out_strings;
+	std::vector<std::pair<PString,PString> > sorted_in_strings,
sorted_out_strings;
+	std::map<PString,PString>::reverse_iterator strings_iterator;
+	std::pair<PString,PString> rule;
+
+	PStringToString cfgs(config->GetAllKeyValues(GWRewriteSection));
+
+	// Clear old config
+	for (PINDEX i = 0; i < m_GWRewrite.GetSize(); ++i) {
+		delete &(m_GWRewrite.GetDataAt(i));
+	}
+	m_GWRewrite.RemoveAll();
+
+	gw_size = cfgs.GetSize();
+	if (gw_size > 0) {
+		for (i = 0; i < gw_size; ++i) {
+
+			// Get the config keys
+			key = cfgs.GetKeyAt(i);
+			cfg_value = cfgs[key];
+
+			in_strings.clear();
+			out_strings.clear();
+			sorted_in_strings.clear();
+			sorted_out_strings.clear();
+
+			// Split the config data into seperate lines
+			lines = cfg_value.Tokenise(PString("\n"));
+
+			lines_size = lines.GetSize();
+
+			for (j = 0; j < lines_size; ++j) {
+
+				// Split the config line into three strings,
direction, from string, to string
+				tokenised_line =
lines[j].Tokenise(PString("="));
+
+				if (tokenised_line.GetSize() < 3) {
+					continue;
+				}
+
+				// Put into appropriate std::map
+
+				if (tokenised_line[0] == "in") {
+					in_strings[tokenised_line[1]] =
tokenised_line[2];
+
+				}
+				if (tokenised_line[0] == "out") {
+					out_strings[tokenised_line[1]] =
tokenised_line[2];
+				}
+
+			}
+
+			// Put the map contents into reverse sorted vectors
+			for (strings_iterator = in_strings.rbegin();
strings_iterator != in_strings.rend(); ++strings_iterator) {
+				rule = *strings_iterator;
+				sorted_in_strings.push_back(rule);
+			}
+			for (strings_iterator = out_strings.rbegin();
strings_iterator != out_strings.rend(); ++strings_iterator) {
+				rule = *strings_iterator;
+				sorted_out_strings.push_back(rule);
+			}
+
+
+			// Create the entry
+			gw_entry = new GWRewriteEntry();
+			gw_entry->m_entry_data.first = sorted_in_strings;
+			gw_entry->m_entry_data.second = sorted_out_strings;
+
+
+			// Add to PDictionary hash table
+			m_GWRewrite.Insert(key,gw_entry);
+
+		}
+	}
+
+	PrintData();
+}
+
+
 Toolkit::Toolkit() : m_Config(0), m_ConfigDirty(false)  #ifdef HAS_ACCT
 	, m_acctList(NULL)
@@ -307,7 +517,7 @@
 			callptr dummycall;
 			m_acctList->LogAcctEvent( GkAcctLogger::AcctOff,
dummycall );
 		}
-		delete m_acctList;	
+		delete m_acctList;
 	} catch( ... ) {
 		PTRACE(0,"GKACCT\tException caught during Accounting-Off
event logging");
 	}
@@ -333,7 +543,7 @@
 }
 
 PConfig* Toolkit::SetConfig(const PFilePath &fp, const PString &section) -{

+{
 	m_ConfigFilePath = fp;
 	m_ConfigDefaultSection = section;
 
@@ -401,11 +611,12 @@
 	m_RouteTable.InitTable();
 	m_ProxyCriterion.LoadConfig(m_Config);
 	m_Rewrite.LoadConfig(m_Config);
+	m_GWRewrite.LoadConfig(m_Config);
 
 #ifdef HAS_ACCT
 	const BOOL nasStart = (m_acctList == NULL);
-	try { 
-		delete m_acctList; 
+	try {
+		delete m_acctList;
 	} catch( ... ) {
 		PTRACE(0,"GKACCT\tException caught during accounting modules
cleanup");
 	}
@@ -420,7 +631,7 @@
 		PTRACE(0,"GKACCT\tException caught during Accounting-On
event logging");
 	}
 #endif
-	return m_Config; 
+	return m_Config;
 }
 
 BOOL Toolkit::MatchRegex(const PString &str, const PString &regexStr) @@
-441,16 +652,16 @@
 
 
 bool Toolkit::RewriteE164(H225_AliasAddress &alias) -{ 
-	if (alias.GetTag() != H225_AliasAddress::e_dialedDigits) 
+{
+	if (alias.GetTag() != H225_AliasAddress::e_dialedDigits)
 		return FALSE;
-	
+
 	PString E164 = H323GetAliasAddressString(alias);
 
 	bool changed = RewritePString(E164);
 	if (changed)
 		H323SetAliasAddress(E164, alias);
-	
+
 	return changed;
 }
 
@@ -462,8 +673,42 @@
 	return changed;
 }
 
-const PString
-Toolkit::GKName() 
+
+bool Toolkit::GWRewriteE164(PString gw, bool direction, 
+H225_AliasAddress
&alias) {
+
+	PString E164;
+	bool changed;
+
+	if (alias.GetTag() != H225_AliasAddress::e_dialedDigits) {
+		return false;
+	}
+
+	E164 = H323GetAliasAddressString(alias);
+	changed = GWRewritePString(gw,direction,E164);
+
+	if (changed) {
+		H323SetAliasAddress(E164, alias);
+	}
+
+	return changed;
+}
+
+bool Toolkit::GWRewriteE164(PString gw, bool direction,
H225_ArrayOf_AliasAddress &aliases) {
+
+	bool changed;
+	PINDEX n;
+
+	changed = false;
+	for (n = 0; n < aliases.GetSize(); ++n) {
+		changed |= GWRewriteE164(gw,direction,aliases[n]);
+	}
+
+	return changed;
+}
+
+
+const PString
+Toolkit::GKName()
 {
   return GkConfig()->GetString("Name", "OpenH323GK"); //use default section
(MM 06.11.01)  } @@ -477,8 +722,8 @@  static const int INT_PTHREADS = 0;
#endif
 
-const PString
-Toolkit::GKVersion() 
+const PString
+Toolkit::GKVersion()
 {
 	return PString(PString::Printf,
 				   "Gatekeeper(%s) Version(%s)
Ext(pthreads=%d) Build(%s, %s) Sys(%s %s %s)\r\n", @@ -495,12 +740,12 @@
 
 
 int
-Toolkit::GetInternalExtensionCode( const unsigned &country, 
-								   const
unsigned &extension, 
-								   const
unsigned &manufacturer) const 
+Toolkit::GetInternalExtensionCode( const unsigned &country,
+								   const
unsigned &extension,
+								   const
unsigned &manufacturer) const
 {
 	switch(country) {
-	case t35cOpenOrg: 
+	case t35cOpenOrg:
 		switch(manufacturer) {
 		case t35mOpenOrg:
 			switch(extension) {
@@ -514,7 +759,7 @@
 }
 
 
-bool Toolkit::AsBool(const PString & str) 
+bool Toolkit::AsBool(const PString & str)
 {
 	if (str.IsEmpty())
 		return false;
diff -r -U 3 openh323gk/Toolkit.h openh323gk.gwrewrite/Toolkit.h
--- openh323gk/Toolkit.h	2003-06-19 15:37:59.000000000 +0000
+++ openh323gk.gwrewrite/Toolkit.h	2003-12-15 11:40:50.000000000 +0000
@@ -15,6 +15,7 @@
 #ifndef _toolkit_h__
 #define _toolkit_h__
 
+#include <vector>
 #include <ptlib.h>
 #include <ptlib/sockets.h>
 #include "h225.h"
@@ -124,16 +125,46 @@
 
 	bool RewritePString(PString & s) { return
m_Rewrite.RewritePString(s); }
 
+	// Class to allow correct use of STL inside PDictionary type
+	class GWRewriteEntry : public PObject {
+		PCLASSINFO(GWRewriteEntry, PObject);
+		public:
+			std::pair<std::vector<std::pair<PString,PString>
>,std::vector<std::pair<PString,PString> > > m_entry_data;
+	};
+
+
+	// per GW RewriteTool
+	class GWRewriteTool {
+		public:
+
+			GWRewriteTool() {
+				m_GWRewrite.AllowDeleteObjects(false);
+			}
+			~GWRewriteTool();
+			void LoadConfig(PConfig *);
+			void PrintData();
+			bool RewritePString(PString gw, bool direction,
PString &data);
+
+		private:
+			PDictionary<PString, GWRewriteEntry> m_GWRewrite;
+
+	};
+
+	// Equivalent functions to RewriteE164 group
+	bool GWRewriteE164(PString gw, bool direction, H225_AliasAddress
&alias);
+	bool GWRewriteE164(PString gw, bool direction,
H225_ArrayOf_AliasAddress &aliases);
+	bool GWRewritePString(PString gw, bool direction, PString &data) {
return m_GWRewrite.RewritePString(gw,direction,data); }
+
 
 	// accessors
-	/** Accessor and 'Factory' to the static Toolkit. 
+	/** Accessor and 'Factory' to the static Toolkit.
 	 * If you want to use your own Toolkit class you have to
-	 * overwrite this method and ensure that your version is 
+	 * overwrite this method and ensure that your version is
 	 * called first -- before any other call to #Toolkit::Instance#.
-	 * Example: 
+	 * Example:
 	 * <pre>
 	 * class MyToolkit: public Toolkit {
-	 *  public: 
+	 *  public:
 	 *   static Toolkit& Instance() {
 	 *	   if (m_Instance == NULL) m_Instance = new MyToolkit();
 	 *     return m_Instance;
@@ -145,16 +176,16 @@
 	 * </pre>
 	 */
 
-	/** Accessor and 'Factory' for the global (static) configuration. 
-	 * With this we are able to implement out own Config-Loader 
-	 * in the same way as #Instance()#. And we can use #Config()# 
+	/** Accessor and 'Factory' for the global (static) configuration.
+	 * With this we are able to implement out own Config-Loader
+	 * in the same way as #Instance()#. And we can use #Config()#
 	 * in the constructor of #Toolkit# (and its descentants).
 	 */
-	PConfig* Config(); 
-	PConfig* Config(const char *); 
+	PConfig* Config();
+	PConfig* Config(const char *);
 
 	/** Sets the config that the toolkit uses to a given config.
-	 *  A prior loaded Config is discarded. 
+	 *  A prior loaded Config is discarded.
 	 */
 	PConfig* SetConfig(const PFilePath &fp, const PString &section);
 
@@ -179,7 +210,7 @@
 	 */
 	static BOOL MatchRegex(const PString &str, const PString &regexStr);
 
-	/** returns the #BOOL# that #str# represents. 
+	/** returns the #BOOL# that #str# represents.
 	 * Case insensitive, "t...", "y...", "a...", "1" are #TRUE#, all
other values are #FALSE#.
 	 */
 	static bool AsBool(const PString & str); @@ -199,10 +230,10 @@
 	enum {
 		t35cOpenOrg = 255,       /// country code for the "Open
Source Organisation" Country
 		t35mOpenOrg = 4242,     /// manufacurers code for the "Open
Source Organisation"
-		t35eFailoverRAS = 255  /// Defined HERE! 
+		t35eFailoverRAS = 255  /// Defined HERE!
 	};
-	/** If the triple #(country,extension,manufacturer)# represents an 
-	 * extension known to the GnuGK this method returns its 'internal
extension code' 
+	/** If the triple #(country,extension,manufacturer)# represents an
+	 * extension known to the GnuGK this method returns its 'internal
extension code'
 	 # #iecXXX' or #iecUnknow# otherwise.
 	 *
 	 * Overwriting methods should use a simlilar scheme and call @@
-215,10 +246,10 @@
 	 * </code>
 	 * This results in 'cascading' calls until a iec!=iecUnkown is
returned.
 	 */
-	virtual int GetInternalExtensionCode(const unsigned &country, 
-
const unsigned &extension, 
+	virtual int GetInternalExtensionCode(const unsigned &country,
+
const unsigned &extension,
 
const unsigned &manufacturer) const;
-	
+
 
 	int GetInternalExtensionCode(const H225_H221NonStandard& data) const
{
 		return GetInternalExtensionCode(data.m_t35CountryCode,
@@ -249,6 +280,11 @@
 	RouteTable m_RouteTable;
 	ProxyCriterion m_ProxyCriterion;
 
+	/* GW Based RewriteTool */
+	GWRewriteTool m_GWRewrite;
+
+
+
 #ifdef HAS_ACCT
 	GkAcctLoggers* m_acctList;
 #endif
@@ -258,7 +294,7 @@
 
 
 inline unsigned long
-Toolkit::HashCStr(const unsigned char *name) 
+Toolkit::HashCStr(const unsigned char *name)
 {
 	register unsigned long h = 0, g;
 	while (*name) {



-------------------------------------------------------
This SF.net email is sponsored by: SF.net Giveback Program.
Does SourceForge.net help you be more productive?  Does it help you create
better code?  SHARE THE LOVE, and help us help YOU!  Click Here:
http://sourceforge.net/donate/
_______________________________________________
List: Openh323gk-users@lists.sourceforge.net
Archive: http://sourceforge.net/mailarchive/forum.php?forum_id=8549
Homepage: http://www.gnugk.org/




-------------------------------------------------------
This SF.net email is sponsored by: Perforce Software.
Perforce is the Fast Software Configuration Management System offering
advanced branching capabilities and atomic changes on 50+ platforms.
Free Eval! http://www.perforce.com/perforce/loadprog.html
_______________________________________________
List: Openh323gk-users@lists.sourceforge.net
Archive: http://sourceforge.net/mailarchive/forum.php?forum_id=8549
Homepage: http://www.gnugk.org/

[Index of Archives]     [SIP]     [Open H.323]     [Gnu Gatekeeper]     [Asterisk PBX]     [ISDN Cause Codes]     [Yosemite News]

  Powered by Linux