sipproviderplugins/sipprovider/sipstatemachine/src/SipStateMachine.cpp
author Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Fri, 16 Apr 2010 15:18:54 +0300
changeset 15 8248b03a2669
parent 0 307788aac0a8
permissions -rw-r--r--
Revision: 201011 Kit: 201015

// Copyright (c) 2005-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:
// CSipStateMachine implementation file.
// 
//

/**
 @file
 @internalComponent
*/
 
#include <e32cons.h>
#include <e32base.h>

#include "SipStateMachine.h"
#include "StateIdle.h"
#include "StateSessionInitiation.h"
#include "StateSessionEstablished.h"
#include "StateSessionTerminate.h"

EXPORT_C CSipStateMachine * CSipStateMachine::NewL(CSIPTransitionEngine * aTe, MSIPStateMachineClient* aClient, TBool aSMDirection)
/**
 SIP State Machine Instantiation function
*/
	{
	CSipStateMachine * SipSm = new(ELeave) CSipStateMachine(aTe, aClient, aSMDirection);
	CleanupStack::PushL (SipSm);
	SipSm->ConstructL();
	CleanupStack::Pop (SipSm);
	return SipSm;
	}

void CSipStateMachine::ConstructL()
/**
 This Function will startup the state machine with a default
 state
 */
    {
    // Tell the TE there's another StateMachine wishing to speak to it.
    // Remek: Where do you remove it??? Cos i couldn't find !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
    iTe->AddStateMachineL(this);

    // Initialize booleans
    iClientStimulus = EFalse;
    iServerStimulus = EFalse;
    iServerErrorStimulus = EFalse;
    iCallTerminateCallback = ETrue;
    iDeleteMeNow = EFalse;
    isInviteSM = EFalse;
    isSubscribeSM = EFalse;

    iCallTerminateCode.iErrorCode = KErrNone;
    iCallTerminateCode.iSipCode = KErrNone;

    // Construct States
    iStateIdle = CStateIdle::NewL(this);

    iCommandCntx.iCommandState = iStateIdle;
    iCommandCntx.iClientTx = NULL;
    iCommandCntx.iCancelClientTx = NULL;
    iCommandCntx.iServerTx = NULL;
    iCommandCntx.iRegBinding = NULL;
    iCommandCntx.iDialogAssoc = NULL;

    iStateSessionInit = CStateSessionInitiation::NewL(this);
    iStateSessionEstablished = CStateSessionEstablished::NewL(this);
    iStateSessionTerminate = CStateSessionTerminate::NewL(this);

    iActiveState = iStateIdle;
	
    this->Start(&iStatus, NULL);
    // Maithra's fix : For stray signal
    MakeActive();
    }
	
CSipStateMachine::CSipStateMachine(CSIPTransitionEngine * aTe, MSIPStateMachineClient* aClient,TBool aSMDirection) 
:CActive(EPriorityStandard), 
 iTe(aTe),
 iClient(aClient),
 iIncomingStateMachine (aSMDirection)
/**
 constructor
*/
	{
	// Open Logs
	__FLOG_OPEN(_L8("SipStateMachine"), _L8("StateMachine"));
	__FLOG_1(_L("[SipStateMachine]:[%x]::CSipStateMachine() "), this);

	if(this->IsAdded() == EFalse)
		{
		CActiveScheduler::Add(this);
		}		
	}
	

CSipStateMachine::~CSipStateMachine()
/**
 destructor
*/
	{
	//Clean-up the iCommand Context
	Cleanup();
	iSipMsgBundle.Close();
	// delete States
	delete iStateIdle;
	delete iStateSessionInit;
	delete iStateSessionEstablished;	
	delete iStateSessionTerminate;
	// Close Logging
	__FLOG_0(_L("[SipStateMachine]: CSipStateMachine::~CSipStateMachine()"));
	__FLOG_CLOSE;
	}
	
EXPORT_C void CSipStateMachine::DeleteWhenReady()
/**
This function will mark the state machine that the CallTerminated callback
should not be called, and state machine should delete itself gracefully when
completed the operation
*/
	{
	__FLOG_1(_L("[SipStateMachine]: CSipStateMachine[%x]::DeleteWhenReady()"),this);
	iClient = NULL;
	iCallTerminateCallback = EFalse;
	iDeleteMeNow = ETrue;
	// send the signal to state machine 
	if(iActiveState == NULL)
		{
		MakeActive();
		MarkRequestComplete(KErrNone);
		}
	}
	
EXPORT_C TSipParams & CSipStateMachine::GetSipParams()
/**
Returns the SIP parameters
*/
 	{
 	return iSipParams;	
 	}

EXPORT_C TInt CSipStateMachine::AcceptCall()
/**
Accepts and incoming call
*/
	{
	__FLOG_1(_L("[SipStateMachine]: CSipStateMachine[%x]::AcceptCall()"),this);
	// This will always be invite as of now. The implementation of the function needs
	// changes when more functionality would be added onto this SM machine to handle more
	// SIp works
	isInviteSM = ETrue;
	return SendSIPResponse(TSipHLConsts::EResponseInvite);
	}

EXPORT_C TInt CSipStateMachine::StartCall()
/**
Start an outgoing call
*/
	{
	__FLOG_1(_L("[SipStateMachine]: CSipStateMachine[%x]::StartCall()"),this);
	if(iSipParams.iRequest == TSipHLConsts::ERequestInvite)
		{
		isInviteSM = ETrue;
		return SendSIPRequest(TSipHLConsts::ERequestInvite);			
		}
	else if(iSipParams.iRequest == TSipHLConsts::ERequestSubscribe)
		{
		isSubscribeSM = ETrue;
		return SendSIPRequest(TSipHLConsts::ERequestSubscribe);			
		}
	else
		{
		iActiveState = NULL;
		return KErrNotSupported;			
		}
	}

EXPORT_C TInt CSipStateMachine::StopCall()
/**
Terminate an established connection
*/
	{
	__FLOG_1(_L("[SipStateMachine]: CSipStateMachine[%x]::StopCall()"),this);
	if(isSubscribeSM)
		{
		return SendSIPRequest(TSipHLConsts::ERequestUnSubscribe);
		}
	else if(isInviteSM)
		{
		return SendSIPRequest(TSipHLConsts::ERequestBye);	
		}
	else
		{
		return KErrNotSupported;	
		}
	}

EXPORT_C TInt CSipStateMachine::RejectCall()
/**
Rejects an incoming call
*/
	{
	__FLOG_1(_L("[SipStateMachine]: CSipStateMachine[%x]::RejectCall()"),this);
	return SendSIPResponse(TSipHLConsts::EResponseInviteReject);	
	}
		
TInt CSipStateMachine::SendSIPRequest(TSipHLConsts::SIP_REQUESTS aRequest)
/**
Sends a SIP request of a particular type 
*/
	{
	if(iActiveState == NULL)
		return KErrNotReady;
	iActiveState->ResetRequestResponse();
	iActiveState->SetClientRequest(aRequest);
	iClientStimulus = ETrue;
	if (iSuspendRequest)
    	{
    	SetSuspendRequest(EFalse);   
    	}
		
	MakeActive();
	MarkRequestComplete(KErrNone);
	return KErrNone;
	}

TInt CSipStateMachine::SendSIPResponse(TSipHLConsts::SIP_RESPONSES aResponse)
/**
Sends a SIP response of a particular type
*/
	{
	if(iActiveState == NULL)
    	{
    	return KErrNotReady;    
    	}
		
	iActiveState->ResetRequestResponse();
	iActiveState->SetClientResponse(aResponse);
	iClientStimulus = ETrue;
	if (iSuspendRequest)
    	{
    	SetSuspendRequest(EFalse);  
    	}
		
	MakeActive();
	MarkRequestComplete(KErrNone);
	return KErrNone;
	}

	
void CSipStateMachine::Start( TRequestStatus* aClientStatus, CSipStateBase* aErrorState )
/** 
Starts the state machine
*/
	{
	__FLOG_1(_L("[SipStateMachine]: CSipStateMachine[%x]::Start()"),this);
	iClientStatus 	= 	aClientStatus;
	iErrorState 	= 	aErrorState;
	iSuspendRequest = 	EFalse;

	if (iClientStatus != NULL)
    	{
    	*iClientStatus = KRequestPending;    
    	}
	  
	// we will not call RunL explicitly over here, That means the SM will be 
	// created in suspended mode.	  
	}
	
void CSipStateMachine::IncomingResponse(TSipMsgBundle aMsgBundle)
/**
Handles the incoming response inside a dialog
*/
	{
	__FLOG_1(_L("[SipStateMachine]: CSipStateMachine[%x]::IncomingResponse()"),this);
	iActiveState->ResetRequestResponse();
	iActiveState->SetServerResponse(aMsgBundle.iResponse);
	// wake up the State Machine if suspended and pass the response back to the state
	if (iSuspendRequest)
    	{
    	SetSuspendRequest(EFalse);   
    	}
		
	iServerStimulus = ETrue;
	iSipMsgBundle.Append(aMsgBundle);
	MakeActive();
	MarkRequestComplete(KErrNone);	
	}
void CSipStateMachine::IncomingRequestInsideDialog(TSipMsgBundle aMsgBundle)
/**
Incoming Request inside established dialog
*/
	{
	__FLOG_1(_L("[SipStateMachine]: CSipStateMachine[%x]::IncomingResponseInsideDialog()"),this);
	iActiveState->ResetRequestResponse();
	iActiveState->SetServerRequest(aMsgBundle.iRequest);
	// Delete the earlier server transaction if any as earlier transaction comes on outside a
	// dialog and not needed as new server transaction that comes with ACK / or inside dialoog
	// will be used
	if(iCommandCntx.iServerTx != NULL)
		{
		delete iCommandCntx.iServerTx;
		iCommandCntx.iServerTx = NULL;
		}
	// Set the server Transaction
	iCommandCntx.iServerTx = aMsgBundle.iServTransaction;
	if (iSuspendRequest)
    	{
    	SetSuspendRequest(EFalse);   
    	}
		
	iServerStimulus = ETrue;
	iSipMsgBundle.Append(aMsgBundle);
	MakeActive();
	MarkRequestComplete(KErrNone);
	}
	
void CSipStateMachine::ErrorOccured(TSipMsgBundle aErrBundle)	
/**
Handle the error from TE
*/
	{
	__FLOG_1(_L("[SipStateMachine]: CSipStateMachine[%x]::ErrorOccurred()"),this);
	iActiveState->ResetRequestResponse();
	if (iSuspendRequest)
    	{
    	SetSuspendRequest(EFalse);   
    	}
		
	iServerErrorStimulus = ETrue;
	iSipMsgBundle.Append(aErrBundle);
	MakeActive();
	MarkRequestComplete(KErrNone);
	}
	
void CSipStateMachine::InviteCompleted(CSIPClientTransaction& /*aTransaction*/)
/**
This callback is called to maek the completion of invite 
*/
	{
	__FLOG_1(_L("[SipStateMachine]: CSipStateMachine[%x]::InviteCompleted()"),this);
	// we will not match and delete the client transaction as it will be anyway
	// deleted when a BYE is being sent or received.
	}
	
void CSipStateMachine::IncomingRequest(TSipMsgBundle aMsgBundle)
/**
New Incoming request Inside established dialog
*/
	{
	__FLOG_1(_L("[SipStateMachine]: CSipStateMachine[%x]::IncomingRequest()"),this);
	iActiveState->ResetRequestResponse();
	iActiveState->SetServerRequest(aMsgBundle.iRequest);
	iSipMsgBundle.Append(aMsgBundle);
	iServerStimulus = ETrue;
	if (iSuspendRequest)
    	{
    	SetSuspendRequest(EFalse);    
    	}
		
	MakeActive();
	MarkRequestComplete(KErrNone);
	}

void CSipStateMachine::IncomingRequestOutsideDialog(TSipMsgBundle & aMsgBundle)
/**
New Incoming request outside any established dialog
*/
	{
	__FLOG_1(_L("[SipStateMachine]: CSipStateMachine[%x]::IncomingRequestOutsideDialog()"),this);
	// set the command context
	iCommandCntx.iDialogAssoc	= (CSIPInviteDialogAssoc*)aMsgBundle.iDialog;
	iCommandCntx.iServerTx  	= aMsgBundle.iServTransaction;
	iActiveState->ResetRequestResponse();
	iActiveState->SetServerRequest(aMsgBundle.iRequest);
	iSipMsgBundle.Append(aMsgBundle);
	iServerStimulus = ETrue;
	if (iSuspendRequest)
    	{
    	SetSuspendRequest(EFalse);    
    	}
		
	MakeActive();
	MarkRequestComplete(KErrNone);
	}
	
void CSipStateMachine::GenerateInviteResponseL(
						CSIPServerTransaction *& aTransaction,
						TSipHLConsts::SIP_RESPONSE_TYPE aType)
/**
 */
	{
	__FLOG_1(_L("[SipStateMachine]: CSipStateMachine[%x]::GenerateInviteResponseL()"),this);
	switch(aType)
		{
		case TSipHLConsts::EResponseRinging:
			{
			__FLOG_1(_L("[SipStateMachine]: CSipStateMachine[%x]::GenerateInviteResponseL() <<180 Ringing>>"),this);
			CSIPResponseElements *ResElem = CSIPResponseElements::NewLC(
							180, SIPStrings::StringF(SipStrConsts::EPhraseRinging));
			aTransaction->SendResponseL(ResElem);
			CleanupStack::Pop(ResElem);	
			}
			break;
		case TSipHLConsts::EResponse200OK:
			{
			__FLOG_1(_L("[SipStateMachine]: CSipStateMachine[%x]::GenerateInviteResponseL() <<200 OK>>"),this);
			CSIPResponseElements *ResElem = CSIPResponseElements::NewLC(
							200, SIPStrings::StringF(SipStrConsts::EPhraseOk));
			aTransaction->SendResponseL(ResElem);
			CleanupStack::Pop(ResElem);		
			}
			break;
		case TSipHLConsts::EResponseReject:
			{
			__FLOG_1(_L("[SipStateMachine]: CSipStateMachine[%x]::GenerateInviteResponseL() <<488 Reject>>"),this);
			CSIPResponseElements *ResElem = CSIPResponseElements::NewLC(
							488, SIPStrings::StringF(SipStrConsts::EPhraseNotAcceptableHere));
			aTransaction->SendResponseL(ResElem);
			CleanupStack::Pop(ResElem);			
			}
			break;
		default:
			{
			__FLOG_1(_L("[SipStateMachine]: CSipStateMachine[%x]::GenerateInviteResponseL() <<No Response Generated>>"),this);
			}
		}
	
	}
	
void CSipStateMachine::GenerateSubscribeResponseL
						(CSIPServerTransaction *& aTransaction,
						TSipHLConsts::SIP_RESPONSE_TYPE aType)
/**
 */
	{
	__FLOG_1(_L("[SipStateMachine]: CSipStateMachine[%x]::GenerateSubscribeResponseL()"),this);
	switch(aType)
		{
		case TSipHLConsts::EResponse200OK:
			{
			__FLOG_1(_L("[SipStateMachine]: CSipStateMachine[%x]::GenerateSubscribeResponseL() <<200 OK>>"),this);
			CSIPResponseElements *ResElem = CSIPResponseElements::NewLC(
						200, SIPStrings::StringF(SipStrConsts::EPhraseOk));
			aTransaction->SendResponseL(ResElem);
			CleanupStack::Pop(ResElem);		
			// We will not delete this here , this will be deleted after giving notification
			// to the client
			/*
			delete aTransaction;
			aTransaction = NULL;
			*/
			}
			break;
		default:
			{
			__FLOG_1(_L("[SipStateMachine]: CSipStateMachine[%x]::GenerateSubscribeResponseL() <<No Response Generated>>"),this);
			}
		}
	}
	
HBufC8 * CSipStateMachine::GenerateNotificationData()
/**
*/
	{
	// Generate the notification parameter from the incoming server Transaction	
	CSIPServerTransaction *sTran = iCommandCntx.iServerTx;
	// get the request elements
	const CSIPRequestElements *reqElems = sTran->RequestElements();
	// Get the contents of the request elements
	// Get the Message Elements
	const CSIPMessageElements & msgElems = reqElems->MessageElements();
	// Get the content
	TPtrC8 content = msgElems.Content();
	HBufC8 * notificationData = NULL;
	TRAPD(err,notificationData = content.AllocL());
	if(err != KErrNone)
		{
		return NULL;
		}
	return notificationData;
	}
	
void CSipStateMachine::RunL()
/** 
 * Called on completion of one active event
 */
	{
	if (iStatus.Int() != KErrNone)
		{
		OnError();
		}
	
	if (iActiveState)
		{
		if (iSuspendRequest)
			{
			// do nothing wait for somebody to enable the state machine
			return;	
			}
		else if (iClientStimulus)
			{
			iClientStimulus = EFalse;
			MakeActive();
			iActiveState = iActiveState->ProcessClientL(iStatus);
			}
		else if (iServerStimulus)
			{
			iServerStimulus = EFalse;
			MakeActive();
			iActiveState = iActiveState->ProcessServerL(iStatus);
			}
		else if(iServerErrorStimulus)
			{
			iServerErrorStimulus = EFalse;
			MakeActive();
			iActiveState = iActiveState->ProcessServerErrorL(iStatus);
			}
		else
			{
			iSuspendRequest = ETrue;	
			MakeActive();
			TRequestStatus *stat = &iStatus;
			User::RequestComplete(stat,KErrNone);
			}
		}
	else if (iActiveState == NULL && iDeleteMeNow )
		{
		// Ask the state machine to delete itself
		OnCompletion();
		}
	else
		{
		//do nothing	
		}
	}

void CSipStateMachine::OnError()
/** 
 * Called from ::RunL when an error occures
 */
	{
	// Put the state machine in suspended mode , and return. 
	SetSuspendRequest(ETrue);
	TRequestStatus *stat = &iStatus;
	User::RequestComplete(stat,KErrNone);
	}

void CSipStateMachine::OnCompletion()
/** 
 * Called by RunL when it is needed to delete the state machine
 */
	{
	__FLOG_1(_L("[SipStateMachine]: CSipStateMachine[%x]::OnCompletion() <<delete this>>"),this);
	delete this;
	}

TInt CSipStateMachine::RunError(TInt aError)
/** 
 */
	{
	TRequestStatus * Stat = &iStatus;
	User::RequestComplete( Stat , aError );
	return KErrNone; 
	}

void CSipStateMachine::DoCancel()
/** 
 */
	{
	OnCompletion();
	}

void CSipStateMachine::MakeActive()
/**
 Function call to wake State Machine from Suspended
 state
*/	{
	if(!IsActive())
    	{
    	SetActive();   
    	}
	}
	
void CSipStateMachine::MarkRequestComplete(TInt aErrCode)
/**
This function will mimic implicitly calling of the 
Runl function of the State Machine base
*/	
	{
	TRequestStatus * ThisStat = &iStatus;
	User::RequestComplete ( ThisStat, aErrCode);
	}
	
CSIPTransitionEngine * CSipStateMachine::GetTe()
/**
returns the current instance of TE
*/
	{	
	return iTe;
	}
	
CSipStateBase * CSipStateMachine::GetActiveState()	
/**
Return the Currently active state
*/
	{
	return iActiveState;
	}
	
void  CSipStateMachine::CallTerminateCallback()
/**
Varifies and call the terminate call back with appropriate values
*/
	{
	__FLOG_2(_L("[SipStateMachine]: CSipStateMachine[%x]::CallTerminateCallback() <<Callback Flag = %d>>"),this,iCallTerminateCallback);
	if(iCallTerminateCallback)
		{
		iClient->CallTerminated(iCallTerminateCode.iErrorCode, iCallTerminateCode.iSipCode);
		}
	}
	
void CSipStateMachine::CallIncomingCallback()
/**
Calls the client with incoming call parameters
*/
	{
	__FLOG_1(_L("[SipStateMachine]: CSipStateMachine[%x]::CallIncomingCallback()"),this);
	TIncomingCallParameters inParam;
	GenerateIncomingCallParameters(inParam);	
	iClient->IncomingCall(inParam);
	}
	
void CSipStateMachine::CallEstablishedCallback()
/**
Notifies the client about the established call
*/
	{
	__FLOG_1(_L("[SipStateMachine]: CSipStateMachine[%x]::CallEstablishedCallback()"),this);
	iClient->CallEstablished();
	}
	
void CSipStateMachine::CallNotificationCallback(TPtrC8 aNotifyData)
/**
Notifies the client about the incoming notification
*/
	{
	__FLOG_1(_L("[SipStateMachine]: CSipStateMachine[%x]::CallNotificationCallback()"),this);
	iClient->ReceiveNotification(aNotifyData);
	}
	
void CSipStateMachine::GenerateIncomingCallParameters(TIncomingCallParameters & aParam)
/**
Store the incoming call parameters
*/
	{
	__FLOG_1(_L("[SipStateMachine]: CSipStateMachine[%x]::GenerateIncomingCallParameters()"),this);
	_LIT8(KAtTheRate,"@");
	
	CSIPServerTransaction *sTran = iCommandCntx.iServerTx;
	const CSIPRequestElements *reqElems = sTran->RequestElements();
	// Get Request Uri
	const CUri8 & uri = reqElems->RemoteUri();
	TPtr8 ptrUri = iUriValues.iReqUri.Des();
		
	ptrUri.Append(uri.Uri().Extract(EUriUserinfo));
	ptrUri.Append(KAtTheRate);
	ptrUri.Append(uri.Uri().Extract(EUriHost));
	// Set Request Uri
	aParam.iReqUri.Set(iUriValues.iReqUri);
	
	
	// Get from 
	const CSIPFromHeader *fromHdr = reqElems->FromHeader();
	const CUri8 & uriFrom = fromHdr->SIPAddress().Uri8();
	
	TPtr8 ptrFrom = iUriValues.iFrom.Des();
	ptrFrom.Append(uriFrom.Uri().Extract(EUriUserinfo));
	ptrFrom.Append(KAtTheRate);
	ptrFrom.Append(uriFrom.Uri().Extract(EUriHost));
	// Set from
	aParam.iFrom.Set(iUriValues.iFrom);
	
	// Get To
	const CSIPToHeader *toHdr = reqElems->ToHeader();
	const CUri8 & uriTo = toHdr->SIPAddress().Uri8();
	
	TPtr8 ptrTo = iUriValues.iTo.Des();
	ptrTo.Append(uriTo.Uri().Extract(EUriUserinfo));
	ptrTo.Append(KAtTheRate);
	ptrTo.Append(uriTo.Uri().Extract(EUriHost));
	// Set To
	aParam.iTo.Set(iUriValues.iTo);
	
	// Get the Message Elements
	const CSIPMessageElements & msgElems = reqElems->MessageElements();
	aParam.iContent.Set(msgElems.Content());
	}
	
TBool CSipStateMachine::GetIncomingStatus()
/**
Sets whether the state machine is for incoming call
*/
	{
	return iIncomingStateMachine;
	}

TBool CSipStateMachine::GetOutgoingStatus()
/**
sets whether an active outgoing is pending or not
*/
	{
	return isActiveOutgoingSession;
	}
	
void CSipStateMachine::SetOutgoingStatus(TBool aStatus)	
/**
Resets the status of active outgoing pending
*/
	{
	isActiveOutgoingSession = aStatus;
	}
	
CSipStateBase * CSipStateMachine::GetNextState (TSipHLConsts::SIP_STATES aNextState)
	{
	switch (aNextState)
		{
		case TSipHLConsts::EStateSessionIdle:
			return iStateIdle;
		case TSipHLConsts::EStateSessionInitiation:
			return iStateSessionInit;
		case TSipHLConsts::EStateSessionEstablished:
			return iStateSessionEstablished;
		case TSipHLConsts::EStateSessionTerminated:
			return iStateSessionTerminate;
		case TSipHLConsts::EStateNone:
		default:
			return NULL;
		}	
	
	}
void CSipStateMachine::Cleanup()
	{
	__FLOG_1(_L("[SipStateMachine]: CSipStateMachine[%x]::Cleanup()"),this);
	// Cleanup everything in Command Context
	delete iCommandCntx.iClientTx;
	iCommandCntx.iClientTx = NULL;
	
	delete iCommandCntx.iCancelClientTx;
	iCommandCntx.iCancelClientTx = NULL;
	
	delete iCommandCntx.iRegBinding;
	iCommandCntx.iRegBinding = NULL;
	
	delete iCommandCntx.iClientTx;
	iCommandCntx.iClientTx = NULL;
	
	delete iCommandCntx.iServerTx;
	iCommandCntx.iServerTx = NULL;
	
	delete iCommandCntx.iDialogAssoc;
	iCommandCntx.iDialogAssoc = NULL;
	
	delete iCommandCntx.iSubsDialogAssoc;
	iCommandCntx.iSubsDialogAssoc = NULL;
	}
	
	
void CSipStateMachine::SendRegisterMessageL()
	{
	__FLOG_1(_L("[SipStateMachine]: CSipStateMachine[%x]::SendRegisterMessageL()"),this);
	// create all the necessary ingredients to send Register Message
	CSIPRefresh * refresh = CSIPRefresh::NewLC();
	CSIPToHeader * to 	  = CreateToHeaderLC(iSipParams.iRegParams.iTo);
	CSIPFromHeader *from  = CreateFromHeaderLC (iSipParams.iRegParams.iFrom);
	CSIPAddress * addr 	  = CSIPAddress::DecodeL(iSipParams.iRegParams.iContact);
	CSIPContactHeader * contact = CSIPContactHeader::NewL(addr);
	CleanupStack::PushL(contact);
	TUriParser8 parser;
	User::LeaveIfError(parser.Parse(iSipParams.iRegParams.iRegistrar));
    CUri8* remoteUri 	  = CUri8::NewLC(parser);   	
    // Send Registration
    CSIPConnection * sipConn = GetTe()->GetSipConnection();
    iCommandCntx.iRegBinding 	= CSIPRegistrationBinding::NewL(
    							  *sipConn, to, contact,
    							  refresh,0, remoteUri, from);
	iCommandCntx.iClientTx		= iCommandCntx.iRegBinding->RegisterL();
	CleanupStack::Pop(5, refresh);
	}
	
void CSipStateMachine::SendUnRegisterMessageL()	
	{
	__FLOG_1(_L("[SipStateMachine]: CSipStateMachine[%x]::SendUnRegisterMessageL()"),this);
	if (iCommandCntx.iClientTx != NULL)
		{
		delete iCommandCntx.iClientTx;
		iCommandCntx.iClientTx = NULL;
		}
	iCommandCntx.iClientTx = iCommandCntx.iRegBinding->DeregisterL();
	}

void CSipStateMachine::SendInviteMessageL()
/**
Send an invitation to remote phone
*/
	{
	__FLOG_1(_L("[SipStateMachine]: CSipStateMachine[%x]::SendInviteMessageL()"),this);
	// set the active outgoing session
	isActiveOutgoingSession = ETrue;
	// Get Invite Parameters
	CSIPToHeader 	* to 	= CreateToHeaderLC(iSipParams.iInvParams.iTo);
	CSIPFromHeader	* from 	= CreateFromHeaderLC(iSipParams.iInvParams.iFrom);
	CSIPAddress		* addr 	= CSIPAddress::DecodeL(iSipParams.iInvParams.iContact);
	CSIPContactHeader * contact = CSIPContactHeader::NewLC(addr);
	TUriParser8		parser;
	User::LeaveIfError(parser.Parse(iSipParams.iInvParams.iReqUri));
	CUri8 *	remoteUri	=	CUri8::NewLC(parser);	
	CSIPMessageElements* msgElements = NULL;

	// Check whether the content is provided or not, if not no SDP will be genrated	
	if((iSipParams.iInvParams.iContentType.Length() != 0) &&
		(iSipParams.iInvParams.iContentSubType.Length() != 0) &&
		(iSipParams.iInvParams.iContent.Length() != 0))
		{
	   // Generate the SDP 
		SdpCodecStringPool::OpenL();
		
		 msgElements = CSIPMessageElements::NewLC();
		CSIPContentTypeHeader* ct = CSIPContentTypeHeader::NewLC( 
				iSipParams.iInvParams.iContentType, iSipParams.iInvParams.iContentSubType );
		CSdpDocument * sdp = CSdpDocument::DecodeLC(iSipParams.iInvParams.iContent);
		HBufC8* content = GetContentBodyL( sdp );
		CleanupStack::PushL( content );
		msgElements->SetContentL( content, ct );
		CleanupStack::Pop();
		CleanupStack::Check(sdp);
		CleanupStack::PopAndDestroy();// for the sdp document.
		SdpCodecStringPool::Close();
		}
	// Create Invite Dialog Association
	CSIPConnection * sipConn = GetTe()->GetSipConnection();
	iCommandCntx.iDialogAssoc = CSIPInviteDialogAssoc::NewLC(
					*sipConn, from, remoteUri, to, contact );
	iCommandCntx.iClientTx	= iCommandCntx.iDialogAssoc->SendInviteL(msgElements);

	if(msgElements)
		{
		CleanupStack::Pop(7, to);
		}
	else
		{
		CleanupStack::Pop(5, to);
		}
	}

void CSipStateMachine::SendAckForInviteL()
/**
Send in response to the response of Initial invite request
*/
	{
	__FLOG_1(_L("[SipStateMachine]: CSipStateMachine[%x]::SendAckForInvite()"),this);
	iCommandCntx.iDialogAssoc->SendAckL(*(iCommandCntx.iClientTx),NULL);
	}
	
void CSipStateMachine::SendCancelL()
/**
Cancels the ongoing session
*/
	{
	__FLOG_1(_L("[SipStateMachine]: CSipStateMachine[%x]::SendCancelL()"),this);
	iCommandCntx.iCancelClientTx = iCommandCntx.iClientTx->CancelL();	
	}

void CSipStateMachine::SendByeL()
/** 
Terminates the ongoing session associated with a dialog
*/
	{
	__FLOG_1(_L("[SipStateMachine]: CSipStateMachine[%x]::SendByeL()"),this);
	if (iCommandCntx.iClientTx != NULL)
		{
		delete iCommandCntx.iClientTx;
		iCommandCntx.iClientTx = NULL;	
		}
	iCommandCntx.iClientTx = iCommandCntx.iDialogAssoc->SendByeL(NULL);
	}

void CSipStateMachine::SendByeResponseL()
/**
Acknoweldge the bye
*/
	{
	__FLOG_1(_L("[SipStateMachine]: CSipStateMachine[%x]::SendByeResponseL() <<200 OK>>"),this);
	CSIPResponseElements* RespElem =  CSIPResponseElements::NewLC( 
            200, SIPStrings::StringF( SipStrConsts::EPhraseOk ) );
	iCommandCntx.iServerTx->SendResponseL(RespElem);
	CleanupStack::Pop(RespElem);	
	}

HBufC8* CSipStateMachine::GetContentBodyL( CSdpDocument* aContent )
	{
	HBufC8* contentBuf = NULL;
	if ( aContent->IsValid() )
		{
		CBufFlat* enBuf = CBufFlat::NewL( 1000 );
		CleanupStack::PushL( enBuf );
		RBufWriteStream writeStream;
		writeStream.Open( *enBuf, 0 );
		aContent->EncodeL( writeStream );
		writeStream.Close();
		TPtr8 ptr = enBuf->Ptr( 0 );
		contentBuf = ptr.AllocL();
		CleanupStack::PopAndDestroy( enBuf );
		writeStream.Close();
		}
	return contentBuf;
	}	
	
void CSipStateMachine::SendSubscribeMessageL()
	{
	__FLOG_1(_L("[SipStateMachine]: CSipStateMachine[%x]::SendSubscribeMessageL()"),this);
	// set the active outgoing session
	isActiveOutgoingSession = ETrue;
	// get Refresh
	CSIPRefresh* refresh = NULL;
	if (iSipParams.iSubsParams.iAutoRefresh)
    	{
    	refresh = CSIPRefresh::NewLC();
    	}
	
	// SIP Message Elements required for Subscribe
	CSIPMessageElements* message = CSIPMessageElements::NewLC();
    RPointerArray<CSIPHeaderBase> headers;
    CSIPHeaderBase::PushLC(&headers);
    // Add Expires
    CSIPExpiresHeader* expires = new(ELeave)CSIPExpiresHeader(iSipParams.iSubsParams.iExpires);
    CleanupStack::PushL(expires);
    headers.AppendL(expires);
    CleanupStack::Pop(expires);
    // Add Accept 
    CSIPAcceptHeader* accept = CSIPAcceptHeader::NewLC(
    				iSipParams.iSubsParams.iAcceptType,iSipParams.iSubsParams.iAcceptSubType);
    headers.AppendL(accept);
    CleanupStack::Pop(accept); 
    // add user headers
    message->SetUserHeadersL(headers);
    CleanupStack::Pop(1); // headers
    headers.Close();
        
	
	CSIPToHeader 	* to 	= CreateToHeaderLC(iSipParams.iSubsParams.iTo);
	CSIPFromHeader	* from 	= CreateFromHeaderLC(iSipParams.iSubsParams.iFrom);
	CSIPAddress		* addr 	= CSIPAddress::DecodeL(iSipParams.iSubsParams.iContact);
	CSIPContactHeader * contact = CSIPContactHeader::NewLC(addr);
	TUriParser8		parser;
	User::LeaveIfError(parser.Parse(iSipParams.iSubsParams.iReqUri));
	CUri8 *	remoteUri	=	CUri8::NewLC(parser);
	CSIPEventHeader	*evtHdr	= 	CSIPEventHeader::DecodeL(iSipParams.iSubsParams.iEventType);
	CleanupStack::PushL(evtHdr);
	CSIPConnection * sipConn = GetTe()->GetSipConnection();
	// Create subscription to send
	iCommandCntx.iSubsDialogAssoc = CSIPSubscribeDialogAssoc::NewLC(
									*sipConn,from,remoteUri,evtHdr,to,contact);
	iCommandCntx.iClientTx = iCommandCntx.iSubsDialogAssoc->SendSubscribeL(message,refresh);
	if (refresh)
    	{
    	CleanupStack::Pop(8, refresh);   
    	}
    else
        {
        CleanupStack::Pop(7, message); 
        }			

	}

void CSipStateMachine::SendUnSubscribeMessageL()
	{
	__FLOG_1(_L("[SipStateMachine]: CSipStateMachine[%x]::SendUnSubscribeMessageL()"),this);
	if (iCommandCntx.iClientTx != NULL)
		{
		delete iCommandCntx.iClientTx;
		iCommandCntx.iClientTx = NULL;
		}
	iCommandCntx.iClientTx = iCommandCntx.iSubsDialogAssoc->SendUnsubscribeL(NULL);
	}
	
CSIPToHeader* CSipStateMachine::CreateToHeaderLC( const TDesC8& aSipUri )
	{
		CSIPAddress* addr = CSIPAddress::DecodeL( aSipUri );
		CleanupStack::PushL( addr );
	
		CSIPToHeader* to = CSIPToHeader::NewL( addr );
		CleanupStack::Pop( addr );
		CleanupStack::PushL( to );
		return to;
	}

CSIPFromHeader* CSipStateMachine::CreateFromHeaderLC( const TDesC8& aSipUri )
	{
		CSIPAddress* addr = CSIPAddress::DecodeL( aSipUri );
		CleanupStack::PushL( addr );
	
		CSIPFromHeader* from = CSIPFromHeader::NewL( addr );
		CleanupStack::Pop( addr );
		CleanupStack::PushL( from );
		return from;
	}
	
	
void	CSipStateMachine::ChallengeIgnored(const TDesC8& aRealm)
	{
	__FLOG_1(_L("[SipStateMachine]: CSipStateMachine[%x]::ChallengeIgnored()"),this);
	//Notify SIPSCPR that challenge has been ignored
	//and credentials need to be set
	iClient->CredentialsRequired(aRealm);
	}