realtimenetprots/sipfw/SIP/TransactionUser/src/TransactionInfo.cpp
changeset 0 307788aac0a8
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/realtimenetprots/sipfw/SIP/TransactionUser/src/TransactionInfo.cpp	Tue Feb 02 01:03:15 2010 +0200
@@ -0,0 +1,575 @@
+// Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
+// All rights reserved.
+// This component and the accompanying materials are made available
+// under the terms of "Eclipse Public License v1.0"
+// which accompanies this distribution, and is available
+// at the URL "http://www.eclipse.org/legal/epl-v10.html".
+//
+// Initial Contributors:
+// Nokia Corporation - initial contribution.
+//
+// Contributors:
+//
+// Description:
+// Name          : TransactionInfo.cpp
+// Part of       : TransactionUser
+// Version       : SIP/6.0
+//
+
+
+
+#include "SipAssert.h"
+#include "uricontainer.h"
+#include "siptoheader.h"
+#include "sipfromheader.h"
+#include "sipviaheader.h"
+#include "sipcallidheader.h"
+#include "sipcseqheader.h"
+#include "siprecordrouteheader.h"
+#include "sipcontactheader.h"
+#include "siprequest.h"
+#include "sipstrings.h"
+#include "sipstrconsts.h"
+
+#include "CUserAgent.h"
+#include "TransactionInfo.h"
+#include "CTransactionHeaders.h"
+#include "SIPMessageUtility.h"
+
+// -----------------------------------------------------------------------------
+// CTransactionInfo::NewL
+// -----------------------------------------------------------------------------
+//
+CTransactionInfo*
+CTransactionInfo::NewL(CTransactionBase::TTransactionType aType, TUint32 aIapId)
+	{
+	return new (ELeave) CTransactionInfo(aType, aIapId);	
+	}
+
+// -----------------------------------------------------------------------------
+// CTransactionInfo::CTransactionInfo
+// -----------------------------------------------------------------------------
+//
+CTransactionInfo::CTransactionInfo(CTransactionBase::TTransactionType aType,
+                                   TUint32 aIapId) :
+	iTransactionType(aType),
+    iIapId(aIapId)
+#ifdef CPPUNIT_TEST
+    , iViaHeaders(1),
+    iRecordRoute(1),
+    iContact(1)
+#endif
+	{
+	}
+
+// -----------------------------------------------------------------------------
+// CTransactionInfo::~CTransactionInfo
+// -----------------------------------------------------------------------------
+//
+CTransactionInfo::~CTransactionInfo()
+	{
+	ClearMessageHeaders();	
+	}
+
+// -----------------------------------------------------------------------------
+// CTransactionInfo::FreeContents
+// UA owns transaction. Delete it only if it is detached from UA, or it differs
+// from UA's transaction (=should be impossible).
+// -----------------------------------------------------------------------------
+//
+void CTransactionInfo::FreeContents()
+	{
+	if (!iUserAgent || (iUserAgent->Transaction() != iTransaction))
+		{
+		delete iTransaction;
+		iTransaction = NULL;
+		}
+
+	delete iUserAgent;
+	iUserAgent = NULL;
+	}
+
+// -----------------------------------------------------------------------------
+// CTransactionInfo::ClearMessageHeaders
+// -----------------------------------------------------------------------------
+//
+void CTransactionInfo::ClearMessageHeaders()
+	{
+	delete iRequestURI;
+	iRequestURI = NULL;
+
+	delete iTo;
+	iTo = NULL;
+
+	delete iFrom;
+	iFrom = NULL;
+
+	delete iCallID;
+	iCallID = NULL;
+
+	iMethod.Close();
+	iCSeq = 0;
+    iViaHeaders.ResetAndDestroy();
+	iRecordRoute.ResetAndDestroy();
+	iContact.ResetAndDestroy();
+	}
+
+// -----------------------------------------------------------------------------
+// CTransactionInfo::Receiver
+// -----------------------------------------------------------------------------
+//
+MTransactionReceiver* CTransactionInfo::Receiver()
+	{
+	if (iTransaction)
+		{
+		return iTransaction;
+		}
+	return iUserAgent;
+	}
+
+// -----------------------------------------------------------------------------
+// CTransactionInfo::UserAgent
+// -----------------------------------------------------------------------------
+//
+CUserAgent* CTransactionInfo::UserAgent()
+	{
+	return iUserAgent;
+	}
+
+// -----------------------------------------------------------------------------
+// CTransactionInfo::SetUserAgent
+// -----------------------------------------------------------------------------
+//
+void CTransactionInfo::SetUserAgent(CUserAgent* aUserAgent)
+	{
+	iUserAgent = aUserAgent;
+	}
+
+// -----------------------------------------------------------------------------
+// CTransactionInfo::SetTransaction
+// -----------------------------------------------------------------------------
+//
+void CTransactionInfo::SetTransaction(CTransactionBase* aTransaction)
+	{
+	iTransaction = aTransaction;
+	}
+
+// -----------------------------------------------------------------------------
+// CTransactionInfo::TransactionId
+// -----------------------------------------------------------------------------
+//
+TTransactionId CTransactionInfo::TransactionId() const
+	{
+	return iTransactionId;
+	}
+
+// -----------------------------------------------------------------------------
+// CTransactionInfo::SetTransactionId
+// -----------------------------------------------------------------------------
+//
+void CTransactionInfo::SetTransactionId(TTransactionId aTransactionId)
+	{
+	iTransactionId = aTransactionId;
+	}
+
+// -----------------------------------------------------------------------------
+// CTransactionInfo::IapId
+// -----------------------------------------------------------------------------
+//
+TUint32 CTransactionInfo::IapId() const
+    {
+    return iIapId;
+    }
+
+// -----------------------------------------------------------------------------
+// CTransactionInfo::TopVia
+// -----------------------------------------------------------------------------
+//
+CSIPViaHeader& CTransactionInfo::TopVia() const
+	{
+	__ASSERT_ALWAYS(iViaHeaders.Count() > 0,
+					User::Panic(_L("TaInfo:TopVia"), KErrNotFound));
+	return *iViaHeaders[0];
+	}
+
+// -----------------------------------------------------------------------------
+// CTransactionInfo::UpdateMessageHeadersL
+// -----------------------------------------------------------------------------
+//
+void CTransactionInfo::UpdateMessageHeadersL(CSIPMessage* aMsg)
+	{
+	if (aMsg)
+		{
+		ClearMessageHeaders();
+
+		if (aMsg->IsRequest())
+			{
+			CURIContainer* uri = static_cast<CSIPRequest*>(aMsg)->RequestURI();
+			if (uri)
+				{
+				iRequestURI = CURIContainer::NewL(*uri);
+				}
+			}
+
+		iMethod.Close();
+		iMethod = CSIPMessageUtility::MessageMethod(*aMsg).Copy();
+
+		iTo = static_cast<CSIPToHeader*>
+			(CSIPMessageUtility::CopyHeaderFromMsgL(*aMsg,
+				SIPStrings::StringF(SipStrConsts::EToHeader)));
+		iFrom = static_cast<CSIPFromHeader*>
+			(CSIPMessageUtility::CopyHeaderFromMsgL(*aMsg,
+                SIPStrings::StringF(SipStrConsts::EFromHeader)));
+		iCallID = static_cast<CSIPCallIDHeader*>
+			(CSIPMessageUtility::CopyHeaderFromMsgL(*aMsg,
+				SIPStrings::StringF(SipStrConsts::ECallIDHeader)));
+
+		if (aMsg->HasHeader(SIPStrings::StringF(SipStrConsts::ECSeqHeader)))
+			{
+        	iCSeq = aMsg->CSeq()->Seq();
+			}
+
+		CopyViaHeadersFromMsgL(*aMsg);
+		}
+	}
+
+// -----------------------------------------------------------------------------
+// CTransactionInfo::UpdateToTagL
+// Server transaction has checked there is no To-tag yet.
+// -----------------------------------------------------------------------------
+//
+void CTransactionInfo::UpdateToTagL(RStringF aTag)
+	{
+	__SIP_ASSERT_LEAVE(iTo, KErrNotFound);
+
+	RStringF tag = SIPStrings::StringF(SipStrConsts::ETag);
+    __SIP_ASSERT_LEAVE(!iTo->HasParam(tag), KErrAlreadyExists);
+
+	iTo->SetParamL(tag, aTag);
+	}
+
+// -----------------------------------------------------------------------------
+// CTransactionInfo::CopyViaHeadersFromMsgL
+// Sent requests have empty host part, but response matching won't use sent-by.
+// -----------------------------------------------------------------------------
+//
+void CTransactionInfo::CopyViaHeadersFromMsgL(CSIPMessage& aMsg)
+	{
+	const RStringF KVia = SIPStrings::StringF(SipStrConsts::EViaHeader);
+	if (aMsg.HasHeader(KVia))
+		{
+		iViaHeaders.ResetAndDestroy();
+
+		TSglQueIter<CSIPHeaderBase> iter = aMsg.Headers(KVia);
+		for (CSIPHeaderBase* header = iter++; header; header = iter++)
+			{
+			CSIPViaHeader* via = dynamic_cast<CSIPViaHeader*>(header->CloneL());
+			CleanupStack::PushL(via);
+			iViaHeaders.AppendL(via);
+			CleanupStack::Pop(via);
+			}
+		}
+	}
+
+// -----------------------------------------------------------------------------
+// CTransactionInfo::StoreRecordRouteHeadersL
+// -----------------------------------------------------------------------------
+//
+void CTransactionInfo::StoreRecordRouteHeadersL(CSIPRequest& aReq)
+	{
+    __SIP_ASSERT_LEAVE(iRecordRoute.Count() == 0, KErrAlreadyExists);
+	
+	const RStringF KRecordRoute =
+		SIPStrings::StringF(SipStrConsts::ERecordRouteHeader);
+	if (aReq.HasHeader(KRecordRoute))
+		{
+		TSglQueIter<CSIPHeaderBase> iter = aReq.Headers(KRecordRoute);
+		for (CSIPHeaderBase* header = iter++; header; header = iter++)
+			{
+			CSIPRecordRouteHeader* rr =
+				static_cast<CSIPRecordRouteHeader*>(header->CloneL());
+			CleanupStack::PushL(rr);
+			iRecordRoute.AppendL(rr);
+			CleanupStack::Pop(rr);
+			}
+		}
+	}
+
+// -----------------------------------------------------------------------------
+// CTransactionInfo::FreeRecordRouteHeaders
+// -----------------------------------------------------------------------------
+//
+void CTransactionInfo::FreeRecordRouteHeaders()
+	{
+	iRecordRoute.ResetAndDestroy();
+	}
+
+// -----------------------------------------------------------------------------
+// CTransactionInfo::StoreContactHeadersL
+// -----------------------------------------------------------------------------
+//
+void CTransactionInfo::StoreContactHeadersL(CSIPRequest& aReq)
+	{
+    __SIP_ASSERT_LEAVE(iContact.Count() == 0, KErrAlreadyExists);
+
+	const RStringF KContact = SIPStrings::StringF(SipStrConsts::EContactHeader);
+	if (aReq.HasHeader(KContact))
+		{
+		TSglQueIter<CSIPHeaderBase> iter = aReq.Headers(KContact);
+		for (CSIPHeaderBase* header = iter++; header; header = iter++)
+			{
+			CSIPContactHeader* contact =
+				dynamic_cast<CSIPContactHeader*>(header->CloneL());
+			CleanupStack::PushL(contact);
+			iContact.AppendL(contact);
+			CleanupStack::Pop(contact);
+			}
+		}
+	}
+
+// -----------------------------------------------------------------------------
+// CTransactionInfo::FreeContactHeaders
+// -----------------------------------------------------------------------------
+//
+void CTransactionInfo::FreeContactHeaders()
+	{
+	iContact.ResetAndDestroy();
+	}
+
+// -----------------------------------------------------------------------------
+// CTransactionInfo::RequiredHeadersPresent
+// -----------------------------------------------------------------------------
+//
+TBool CTransactionInfo::RequiredHeadersPresent() const
+	{
+	return iViaHeaders.Count() > 0 && iFrom && iTo && iCallID && MethodExists();
+	}
+
+// -----------------------------------------------------------------------------
+// CTransactionInfo::MethodExists
+// -----------------------------------------------------------------------------
+//
+TBool CTransactionInfo::MethodExists() const
+	{
+	return iMethod.DesC().Length() > 0;
+	}
+	
+// -----------------------------------------------------------------------------
+// CTransactionInfo::CompareType
+// -----------------------------------------------------------------------------
+//
+TBool
+CTransactionInfo::CompareType(CTransactionBase::TTransactionType aType) const
+	{
+	return aType == iTransactionType;
+	}
+
+// -----------------------------------------------------------------------------
+// CTransactionInfo::CompareMethod
+// If the received message is ACK, iMethod should be INVITE.
+// -----------------------------------------------------------------------------
+//
+TBool CTransactionInfo::CompareMethod(RStringF aMsgMethod) const
+	{
+	if (aMsgMethod == SIPStrings::StringF(SipStrConsts::EAck))
+		{
+		return iMethod == SIPStrings::StringF(SipStrConsts::EInvite);
+		}
+
+	return aMsgMethod == iMethod;
+	}
+
+// -----------------------------------------------------------------------------
+// CTransactionInfo::CompareRequestLine
+// Don't compare ACK's Request-URI, as it can be different than in INVITE.
+// -----------------------------------------------------------------------------
+//
+TBool CTransactionInfo::CompareRequestLine(const CURIContainer& aReqUri,
+										   RStringF aMethod,
+										   TBool aSearchCanceledUas) const
+	{
+	if (iRequestURI)
+		{
+		if (aMethod == SIPStrings::StringF(SipStrConsts::EAck))
+			{
+			return CompareMethod(aMethod);
+			}
+
+		if (aReqUri == *iRequestURI)
+			{
+			return (aSearchCanceledUas || CompareMethod(aMethod));
+			}
+		}
+
+	return EFalse;
+	}
+
+// -----------------------------------------------------------------------------
+// CTransactionInfo::CompareHeaders
+// If ACK, don't compare top Via.
+// -----------------------------------------------------------------------------
+//
+TBool CTransactionInfo::CompareHeaders(CSIPRequest& aReq) const
+	{
+	__ASSERT_DEBUG(aReq.RequestURI() != NULL &&
+		aReq.HasHeader(SIPStrings::StringF(SipStrConsts::EViaHeader)) &&
+		aReq.HasHeader(SIPStrings::StringF(SipStrConsts::EFromHeader)) &&
+		aReq.HasHeader(SIPStrings::StringF(SipStrConsts::EToHeader)) &&
+		aReq.HasHeader(SIPStrings::StringF(SipStrConsts::ECSeqHeader)) &&
+    	aReq.HasHeader(SIPStrings::StringF(SipStrConsts::ECallIDHeader)),
+		User::Panic(_L("CTaInfo:Compare aReq"), KErrArgument));
+	__ASSERT_DEBUG(RequiredHeadersPresent(),
+		User::Panic(_L("CTaInfo:Compare headers not stored"), KErrArgument));
+
+	
+		
+	if (CSIPMessageUtility::CompareTags(*iTo, *aReq.To()) &&
+		    CSIPMessageUtility::CompareTags(*iFrom, *aReq.From()) &&
+		    *iCallID == *aReq.CallID() &&
+		    iCSeq == aReq.CSeq()->Seq())
+		{
+		if(CSIPMessageUtility::IsAck(aReq))
+		    return ETrue;
+		 else
+		 	{
+			 CSIPViaHeader* topvia = CSIPMessageUtility::TopVia(aReq);
+		     if (topvia) 
+			     return(*topvia == TopVia());		     
+	         }
+	    }
+		 return EFalse;
+	}
+	
+
+// -----------------------------------------------------------------------------
+// CTransactionInfo::IsMergedRequest
+// aCSeqMethod can't be ACK, as stray ACKs are dropped.
+// -----------------------------------------------------------------------------
+//
+TBool CTransactionInfo::IsMergedRequest(const CUserAgent& aUserAgent,
+										CSIPFromHeader& aFrom,
+										CSIPCallIDHeader& aCallID,
+										TUint aCSeqNbr,
+										RStringF aCSeqMethod) const
+	{
+	__ASSERT_DEBUG(aCSeqMethod != SIPStrings::StringF(SipStrConsts::EAck),
+		User::Panic(_L("CTaInfo:IsMergedRequest"), KErrArgument));
+	return (iUserAgent != &aUserAgent) &&
+		   iFrom &&
+		   iCallID &&
+		   MethodExists() &&
+		   CSIPMessageUtility::CompareTags(aFrom, *iFrom) &&
+		   (aCallID == *iCallID) &&
+		   (aCSeqNbr == iCSeq) &&
+		   iUserAgent->IsUAS() && // Allow application to send request to itself
+		   // Allow receiving CANCEL
+		   (iMethod != SIPStrings::StringF(SipStrConsts::EInvite) ||
+		    aCSeqMethod != SIPStrings::StringF(SipStrConsts::ECancel));
+	}
+
+// -----------------------------------------------------------------------------
+// CTransactionInfo::TransactionHeadersL
+// -----------------------------------------------------------------------------
+//
+MTransactionHeaders* CTransactionInfo::TransactionHeadersL()
+	{
+	return CTransactionHeaders::NewL(iRequestURI,
+                                     iTo,
+									 iFrom,
+									 iCallID,
+									 iCSeq,
+									 iRecordRoute,
+									 iContact);
+	}
+
+// -----------------------------------------------------------------------------
+// CTransactionInfo::CopyToFromCallIDCSeqToMsgL
+// Copy headers only if they don't exist.
+// -----------------------------------------------------------------------------
+//
+void CTransactionInfo::CopyToFromCallIDCSeqToMsgL(CSIPMessage& aMsg) const
+	{
+	if (iTo && !aMsg.HasHeader(SIPStrings::StringF(SipStrConsts::EToHeader)))
+		{
+		CSIPToHeader* to = CSIPToHeader::NewLC(*iTo);
+		aMsg.AddHeaderL(to);
+		CleanupStack::Pop(to);
+		}
+
+	if (iFrom &&
+		!aMsg.HasHeader(SIPStrings::StringF(SipStrConsts::EFromHeader)))
+		{
+		CSIPFromHeader* from = CSIPFromHeader::NewLC(*iFrom);
+		aMsg.AddHeaderL(from);
+		CleanupStack::Pop(from);
+		}
+
+	if (iCallID &&
+		!aMsg.HasHeader(SIPStrings::StringF(SipStrConsts::ECallIDHeader)))
+		{
+		CSIPCallIDHeader* callID =
+			static_cast<CSIPCallIDHeader*>(iCallID->CloneL());
+		CleanupStack::PushL(callID);
+		aMsg.AddHeaderL(callID);
+		CleanupStack::Pop(callID);
+		}
+
+	CSIPMessageUtility::FillCSeqL(aMsg,
+		iCSeq,
+		aMsg.IsRequest() ? static_cast<CSIPRequest&>(aMsg).Method() : iMethod);
+	}
+
+// -----------------------------------------------------------------------------
+// CTransactionInfo::CopyViaHeadersToMsgL
+// -----------------------------------------------------------------------------
+//
+void CTransactionInfo::CopyViaHeadersToMsgL(CSIPMessage& aMsg) const
+	{
+	for (TInt i = 0; i < iViaHeaders.Count(); ++i)
+		{
+		CSIPViaHeader* via =
+			static_cast<CSIPViaHeader*>(iViaHeaders[i]->CloneL());
+		CleanupStack::PushL(via);
+		aMsg.AddHeaderL(via);
+		CleanupStack::Pop(via);
+		}
+	}
+
+// -----------------------------------------------------------------------------
+// CTransactionInfo::CopyRequestUriToRequestL
+// -----------------------------------------------------------------------------
+//
+void CTransactionInfo::CopyRequestUriToRequestL(CSIPRequest& aReq) const
+	{
+    __SIP_ASSERT_LEAVE(iRequestURI, KErrNotFound);
+
+	CURIContainer* reqUri = CURIContainer::NewLC(*iRequestURI);
+	aReq.SetRequestURIL(reqUri);
+	CleanupStack::Pop(reqUri);
+	}
+
+// -----------------------------------------------------------------------------
+// CTransactionInfo::BuildRequestFromStoredInfoL
+// -----------------------------------------------------------------------------
+//
+CSIPRequest* CTransactionInfo::BuildRequestFromStoredInfoL() const
+	{
+	CSIPRequest* req(NULL);
+	if (iRequestURI && iTo && iFrom && MethodExists())
+		{
+		req = CSIPRequest::NewLC(iMethod);
+		CopyToFromCallIDCSeqToMsgL(*req);
+		CopyRequestUriToRequestL(*req);
+		CleanupStack::Pop(req);
+		}
+	return req;
+	}
+
+// -----------------------------------------------------------------------------
+// CTransactionInfo::RequestMethod
+// -----------------------------------------------------------------------------
+//
+RStringF CTransactionInfo::RequestMethod() const
+	{
+	return iMethod;
+	}