multimediacommsengine/mmcesrv/mmceserver/src/mcestateoffering.cpp
changeset 0 1bce908db942
child 3 513a8b745b2f
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/multimediacommsengine/mmcesrv/mmceserver/src/mcestateoffering.cpp	Tue Feb 02 01:04:58 2010 +0200
@@ -0,0 +1,956 @@
+/*
+* Copyright (c) 2005 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:  
+*
+*/
+
+
+
+
+#include <sipdialogassocbase.h>
+#include <sipdialog.h>
+#include <sipclienttransaction.h>
+#include <sipresponseelements.h>
+#include <sipcseqheader.h>
+#include "mcestateoffering.h"
+#include "mcesipsession.h"
+#include "mcesipextensions.h"
+#include "mceactionset.h"
+#include "mcefcactionset.h"
+#include "mceclientserver.h"
+#include "mcesip.h"
+#include "mcesipsession.h"
+#include "mcenatmacros.h"
+#include "mcesdpsession.h"
+#include "mcesrvlogs.h"
+
+// -----------------------------------------------------------------------------
+// CMceStateOffering::CMceStateOffering
+// -----------------------------------------------------------------------------
+//
+CMceStateOffering::CMceStateOffering ()
+    : CMceState( KMceStateOffering )
+	{
+	}
+
+
+// -----------------------------------------------------------------------------
+// CMceStateOffering::~CMceStateOffering
+// -----------------------------------------------------------------------------
+//
+CMceStateOffering::~CMceStateOffering()
+	{
+	}
+
+
+// -----------------------------------------------------------------------------
+// CMceStateOffering::DoAcceptL
+// -----------------------------------------------------------------------------
+//
+TBool CMceStateOffering::DoAcceptL( TMceStateTransitionEvent& aEvent )
+	{
+
+    User::LeaveIfError( 	                 
+       aEvent.Code() == EMceUpdate ||
+       aEvent.Code() == EMceResponse  ||
+       aEvent.Code() == EMceProvisionalResponse ||
+       aEvent.Code() == EMceRedirectionResponse ||
+       aEvent.Code() == EMceErrorResponse ||
+       aEvent.Code() == EMceMediaUpdated ||
+       aEvent.Code() == EMceItcCancel ||    
+       aEvent.Code() == EMceBye ||  
+       aEvent.Code() == EMceItcEnable ||
+       aEvent.Code() == EMceItcDisable || 
+       IsExtensionRequestEvent( aEvent )
+       
+       ? KErrNone : KErrTotalLossOfPrecision );
+           
+	return ETrue;
+	
+	}
+
+// -----------------------------------------------------------------------------
+// CMceStateOffering::EntryL
+// -----------------------------------------------------------------------------
+//
+void CMceStateOffering::EntryL( TMceStateTransitionEvent& aEvent )
+	{
+
+	if ( IsExtensionRequestEvent( aEvent ))
+		{
+		HandleExtensionRequestEventL( aEvent );	
+		}
+	
+    else
+    	{
+	    switch( aEvent.Code() )
+	        {
+            case EMceUpdate:
+                {
+                EntryUpdateL( aEvent );
+                break;
+                }
+	        case EMceProvisionalResponse:
+	            {
+	            EntryProvisionalResponseL( aEvent );
+	            break;
+	            }
+	        //200 OK
+	        case EMceResponse:
+	            {
+	            EntryResponseL( aEvent );
+	            break;                
+	            }
+	        //error
+	        case EMceRedirectionResponse:
+	            {
+	            EntryRedirectionResponseL( aEvent );
+	            break;   
+	            }
+	        case EMceErrorResponse:
+	            {
+	            EntryErrorResponseL( aEvent );
+	            break;                
+	            }
+	        //if client cancels, send CANCEL            
+	        case EMceItcCancel:
+	            {
+	            EntryCancelL( aEvent );
+	            break;
+	            }
+	        case EMceMediaUpdated:
+	            {
+                CMceSipSession& session = aEvent.Session();
+                CSIPServerTransaction* update = &session.Request();
+
+                if ( update && update->Type() == 
+                    SIPStrings::StringF( SipStrConsts::EUpdate ) )
+                    {
+                    EntryMediaUpdatedL( aEvent );
+                    }
+                else
+                    {
+                    if ( aEvent.Session().SubState() == CMceSipSession::EUpdating )
+                        {
+                        EntryAnswerToUpdateDecodedL( aEvent );
+                        }
+                    else
+                        {
+                        EntryAnswerToOfferDecodedL( aEvent );
+                        }
+                    }
+	            break;
+	            }
+	      
+	        case EMceItcEnable:
+	        case EMceItcDisable:
+	            {
+	            aEvent.Session().Actions().ControlMediaL( aEvent.ParamIDs(), 
+	                                             (TMceItcFunctions)aEvent.Code() );
+	            break;
+	            } 
+	        case EMceBye:
+	            {
+	            EntryByeL( aEvent );
+	            break;
+	            }
+	        default:
+	            {
+	            //NOP
+	            break;
+	            }       
+	        }
+    	}
+	}
+
+// -----------------------------------------------------------------------------
+// CMceStateOffering::EntryUpdateL
+// -----------------------------------------------------------------------------
+//
+void CMceStateOffering::EntryUpdateL( TMceStateTransitionEvent& aEvent )
+    {
+    CMceSipSession& session = aEvent.Session();
+    if ( MceSip::HasContent( session.Request() ) )
+        {
+        // UPDATE carries SDP
+        User::LeaveIfError( session.Actions().CreateSDP( session.Request() ) );
+    
+        session.Actions().DecodeL();
+        TMceReturnStatus status = session.Actions().UpdateL();
+        aEvent.ParamStatus() = status;
+        if ( MCE_IS_ERROR( status ) )
+            {
+            // TBD: update failed, reject
+            }
+        else if ( status == KMceAsync )
+            {
+            // NOP
+            }
+        else // ready
+            {
+            aEvent.Code() = EMceMediaUpdated;
+            EntryMediaUpdatedL( aEvent );
+            }
+        }
+    else 
+        {
+        // TBD: handle UPDATE without content
+        }
+        
+    }
+
+// -----------------------------------------------------------------------------
+// CMceStateOffering::EntryProvisionalResponseL
+// -----------------------------------------------------------------------------
+//
+void CMceStateOffering::EntryMediaUpdatedL( TMceStateTransitionEvent& aEvent )
+    {
+    CMceSipSession& session = aEvent.Session();
+
+    TMceReturnStatus status = session.Actions().ReserveL();
+    aEvent.ParamStatus() = status;
+    if ( MCE_IS_ERROR( status ))
+        {
+        // TBD: reservation failed
+        }
+    else
+        if (status == KMceAsync)
+            {
+            // NOP
+            }
+        else // ready, send 2xx to update
+            {
+            CSIPServerTransaction* update= NULL;
+            RStringF trx = session.Request().Type();
+            if (trx == SIPStrings::StringF(SipStrConsts::EUpdate) )
+                {
+                update = &session.Request();
+                }
+
+            if (update)
+                {
+                session.Actions().EncodeL();
+                session.FCActions().UpdateFCAnswerL( *session.Offer() );
+                session.Actions().SendAnswerL( *update);
+                }
+            else
+                {
+                User::Leave(KErrTotalLossOfPrecision);
+                }
+            }
+	}
+
+// -----------------------------------------------------------------------------
+// CMceStateOffering::EntryProvisionalResponseL
+// -----------------------------------------------------------------------------
+//
+void CMceStateOffering::EntryProvisionalResponseL( 
+    TMceStateTransitionEvent& aEvent )
+    {
+    TInt status = KErrNone;
+    CMceSipSession& session = aEvent.Session();
+    CSIPClientTransaction& response = session.Response();
+     
+    session.Extensions().UpdateL( response );
+    session.Actions().CheckContactIsSecureL( response );
+
+    session.ActiveBody().AnswerType() = KMceNegotiationAnswerTypeIntermediate;
+    
+    TBool IsFork = EFalse;
+    if ( MceSip::ResponseCode( session.Response() ) == KMceSipSessionProgress && 
+    	   session.ForkedDialogsCount() ) 
+        {
+        IsFork = ETrue;
+  	    }
+    if ( session.Actions().NeedToProcessL( aEvent ) || IsFork )
+        {
+        if ( MCE_NEED_TO_SEND( session, NULL ) || IsFork )
+            {
+            if ( MceSip::HasContent( response ) )
+                {
+                // create SDP answer
+                //status = session.Actions().CreateSDP( response );
+                NAT_WAIT_NO_EXEC( session, (status = session.Actions().CreateSDP( response )));
+        	    
+                // handle SDP content
+                if ( !MCE_IS_ERROR( status ) )
+                    {
+                    // process session timer
+                    session.Actions().ProcessSessionTimerClientL( response );
+                    // update FC
+                    session.FCActions().PeekFCDocumentL( *session.Offer() );
+                
+                    //decode answer, ignore warning code 
+                    if ( session.ActiveBody().SecureSession())
+                    	{
+                    	session.ActiveBody().SecureSession()->iLSReadyToBind = EFalse;
+                    	}
+                    session.Actions().DecodeL();
+
+                    
+                    // update media
+                    status = session.Actions().UpdateL();
+                    }
+                }
+        
+            //if there was an error
+            if ( MCE_IS_ERROR( status ) )
+                {
+                EntryCancelL( aEvent );
+                //transition exit is performed here
+                session.Actions().StateChanged( KMceStateCanceled );
+                session.Actions().ClientStateChangedL( CMceSession::ECancelling, 
+                                                       aEvent.ParamStatus() );
+                }
+            else if ( status == KMceAsync )
+                {
+                aEvent.Session().SetWaitingMediaCallback( ETrue );
+                }
+            else // KMceReady 
+                {
+                EntryAnswerToOfferDecodedL( aEvent );
+                }
+            }
+        else
+            {
+            EntryAnswerToOfferDecodedL( aEvent );
+            }
+        }
+    aEvent.ParamStatus() = status;
+    }
+
+// -----------------------------------------------------------------------------
+// CMceStateOffering::EntryRedirectionResponseL
+// -----------------------------------------------------------------------------
+//
+void CMceStateOffering::EntryRedirectionResponseL( 
+    TMceStateTransitionEvent& aEvent )
+    {
+    MCESRV_DEBUG("CMceStateOffering::EntryRedirectionResponseL, Entry");
+
+	CMceSipSession& session = aEvent.Session();
+    
+    session.ResetSdpCounts();
+    
+    switch ( MceSip::ResponseCode( session.Response() ) )
+        {   
+        case KMceSipMovedTemporarily:  
+            {
+            // any 3xx response for updating will be handled as
+            // a error situation
+            if ( session.SubState() != CMceSipSession::EUpdating )
+                {
+                // get remoteUri information from response 
+                session.AddRemoteUriFromResponseL( 
+                    *const_cast<CSIPResponseElements*>(session.Response().ResponseElements()) );
+                // create a new inviteAssociationDialog
+                session.CreateDialogFrom3XXResponseL();
+                // send the invite again
+                session.Actions().SendInviteL();    
+                }            
+            break;
+            }
+        // include KMceSipUseProxy, KMceSipAlternativeService,
+        // KMceSipMultipleChoices, KMceSipMovedPermanently
+        default: 
+            {
+            // error situation
+            break;
+            }
+        }
+    
+    MCESRV_DEBUG("CMceStateOffering::EntryRedirectionResponseL, Exit");
+    }
+    
+// -----------------------------------------------------------------------------
+// CMceStateOffering::ExitRedirectionEventL
+// -----------------------------------------------------------------------------
+//
+void CMceStateOffering::ExitRedirectionEventL( 
+    TMceStateTransitionEvent& aEvent )
+    {
+    MCESRV_DEBUG("CMceStateOffering::RedirectionErrorResponseL, Entry");
+
+    CMceSipSession& session = aEvent.Session();
+    CMceSipSession::TSubState subState = session.SubState();
+    TUint responseCode = MceSip::ResponseCode( session.Response() );
+    
+    if ( subState == CMceSipSession::EOffering )
+        {
+        if ( responseCode == KMceSipMovedTemporarily )  
+            {
+            session.Actions().ClientStateChangedL( 
+                CMceSession::EOffering, *session.Body(), session.Response() );           
+            }
+        else
+            {
+            session.Actions().StopMedia();
+            session.FCActions().ReleaseFC();
+            session.Actions().StateChanged( KMceStateTerminated );
+            session.Actions().ClientStateChangedL( 
+                CMceSession::ETerminated, *session.Body(), session.Response() );       
+            }
+        }
+    else if ( session.SubState() == CMceSipSession::EUpdating ) 
+        {
+        session.Actions().StopUpdatingMedia();
+        session.Actions().UpdateFailed();
+        session.Actions().StateChanged( CMceSession::EEstablished );
+        session.Actions().ClientStateChangedL( 
+            CMceSession::EEstablished, *session.Body(),
+            session.Response(), KErrGeneral );                                    
+        }
+    else
+        {
+        // do nothing  
+        }
+    
+    MCESRV_DEBUG("CMceStateOffering::RedirectionErrorResponseL, Exit");
+    }
+
+// -----------------------------------------------------------------------------
+// CMceStateOffering::EntryResponseL
+// -----------------------------------------------------------------------------
+//
+void CMceStateOffering::EntryResponseL( TMceStateTransitionEvent& aEvent )
+    {
+    TInt status = KErrNone;
+	CMceSipSession& session = aEvent.Session();
+    CMceSipSession::TSubState subState = session.SubState();
+	
+    //send ACK
+    session.Actions().SendACKL( session.Response() );
+	session.Actions().CheckContactIsSecureL( session.Response() );
+    session.ActiveBody().AnswerType() = KMceNegotiationAnswerTypeFinal;
+    
+	// Handle the answer only if the media processing is not
+	// already ongoing
+	if ( !session.WaitingMediaCallback() )
+	    {
+	    if ( MceSip::HasContent( session.Response() ) )
+	        {
+	        //process session timer
+            session.Actions().ProcessSessionTimerClientL( session.Response() );
+            
+            if ( subState != CMceSipSession::ERefreshing )
+                {
+                //create SDP answer
+        	    NAT_WAIT_NO_EXEC( session, (status = session.Actions().CreateSDP( session.Response() ) ));
+        	    
+            	if ( !MCE_IS_ERROR( status ) )
+            	    {
+                    //update FC
+                    session.FCActions().PeekFCDocumentL( *session.Offer() );
+                	
+            	    //decode answer, ignore warning code 
+                    if ( session.ActiveBody().SecureSession())
+                    	{
+                    	session.ActiveBody().SecureSession()->iLSReadyToBind = ETrue;
+                    	}
+                    status = session.Actions().Decode();
+
+                    // update media and start waiting EMceMediaUpdated (if needed) 
+				    if ( !MCE_IS_ERROR( status ) )
+						{
+		                status = session.Actions().UpdateL();
+		                //if everything OK, starts floor control
+		        		if ( !MCE_IS_ERROR( status ) )
+		    		        {
+		                    //check should wait EMceMediaUpdated
+		                    aEvent.Code() = status == KMceReady ? 
+		                                    EMceMediaUpdated : EMceResponse;
+		                    if ( subState == CMceSipSession::EOffering )
+		                        {
+		                        // start floor control only for the initial INVITE
+		                        session.FCActions().StartFCL();
+		                        }
+		    		        }
+						}
+            	    }
+                }
+            }
+	    else // no content
+    	    {
+    	    if  ( !MCE_NEED_TO_RECEIVE( session ) )
+    	        {
+                status = session.Actions().UpdateL();
+    	        // SDP answer was received before
+    	        // go to established state
+    	        session.Actions().StateChanged( KMceStateEstablished );
+                //session.Actions().ClientStateChangedL( CMceSession::EEstablished,
+                //                               session.Response() );
+    	        session.Actions().ClientStateChangedL( CMceSession::EEstablished, 
+                                                   *session.Body(),
+                                                   session.Response(),
+                                                   status );
+    	        }
+    	    else
+    	        {
+    	        // SDP answer is not received
+    	        User::Leave( KErrNotReady );
+    	        }
+    	    }
+        
+	    aEvent.ParamStatus() = status;
+        
+        //if there was an error
+        if ( MCE_IS_ERROR( status ) )
+            {
+        	//if first invite
+            if ( subState == CMceSipSession::EOffering )
+                {
+                //send BYE and stop media
+                session.Actions().SendBYEL();
+                session.Actions().StopMedia();
+                }
+            //if updating
+            else if ( subState == CMceSipSession::EUpdating )
+                {
+                //do rollback
+                session.Actions().UpdateFailed();
+                if ( session.Body() && &session.Body()->SdpSession() &&
+                     session.Body()->SdpSession().iOOldSchoolCompleted )
+                    {
+                    session.Actions().ClientStateChangedL( 
+                        CMceSession::EEstablished, *( session.Body() ), status );                         
+                    }       
+                }
+            else
+                {
+                //NOP
+                }
+            }
+        else if ( status == KMceAsync )
+            {
+            // set session waiting for media callback
+            aEvent.Session().SetWaitingMediaCallback( ETrue );
+            }
+        else if ( status == KMceReady && subState == CMceSipSession::EUpdating )
+            {
+            session.Actions().UpdateSucceed();
+            }
+        else
+            {
+            // NOP
+            }
+	    }
+    }
+    
+
+// -----------------------------------------------------------------------------
+// CMceStateOffering::EntryErrorResponseL
+// -----------------------------------------------------------------------------
+//
+void CMceStateOffering::EntryErrorResponseL( TMceStateTransitionEvent& aEvent )
+    {
+	CMceSipSession& session = aEvent.Session();
+    
+    session.ResetSdpCounts();
+    
+    CMceSipSession::TSubState subState = session.SubState();
+    
+    TUint code = MceSip::ResponseCode( session.Response() );
+    TInt errorCode = KErrNone;
+       
+    if ( code == KMceSipSessionIntervalTooSmall )
+    	{
+    	if ( session.Dialog()->Dialog().State() == CSIPDialog::EConfirmed )	
+    		{
+    		//sending re-INVITE after 422 for re-INVITE
+    		session.Actions().ProcessSessionTimerClientL( session.Response() );
+			//send again
+			session.Actions().SendSessionRefreshL();		
+	   		}
+	   		
+		else if ( session.Dialog()->Dialog().State() == CSIPDialog::ETerminated )	   		
+			{
+			//sending re-INVITE after 422 for INVITE
+			errorCode = session.ReUseDialog();	
+            if ( errorCode == KErrNone )
+				{
+			   	session.Actions().ProcessSessionTimerClientL( session.Response() );
+			 	session.Actions().SendInviteL();
+				}
+	  		}
+    	}
+    else if ( code == KMceSipExtensionRequired )    
+        {
+        session.Extensions().UpdateL( session.Response() );
+        session.ReCreateOutgoingDialogL();
+        session.Actions().SendInviteL();
+        }     
+	//if first invite, stop media and FC
+    else if ( subState == CMceSipSession::EOffering )
+        {
+        session.Actions().StopMedia();
+        session.FCActions().ReleaseFC();
+        }
+	//if update, reject update
+    else if ( subState == CMceSipSession::EUpdating ||
+              subState == CMceSipSession::ERefreshing )
+        {
+	 	if ( code == KMceSipCallOrTransactionDoesNotExist ||
+             code == KMceSipRequestTimeout ) 
+            { 
+            session.Actions().UpdateFailed();
+            session.Actions().SendBYEL();
+            session.Actions().StopMedia();
+            session.FCActions().ReleaseFC();
+            session.Actions().StateChanged( KMceStateTerminated );
+            session.Actions().ClientStateChangedL( CMceSession::ETerminated,
+                                                   session.Response() );
+            }
+         else
+            {
+            session.Actions().UpdateFailed(); 
+            session.Actions().StateChanged( KMceStateEstablished );
+            session.Actions().ClientStateChangedL( CMceSession::EEstablished, 
+                                                   *session.Body(),
+                                                   session.Response(),
+                                                   KErrCancel );
+            }
+        }
+    else
+        {
+        //NOP
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CMceStateOffering::EntryCancelL
+// -----------------------------------------------------------------------------
+//
+void CMceStateOffering::EntryCancelL( TMceStateTransitionEvent& aEvent )
+    {
+	CMceSipSession& session = aEvent.Session();
+    CMceSipSession::TSubState subState = session.SubState();
+
+    //(try) send CANCEL
+    session.Actions().SendCancelL();
+
+    if ( subState == CMceSipSession::EOffering )
+        {
+        session.Actions().StopMedia();
+        session.FCActions().ReleaseFC();
+        }
+    else if ( subState == CMceSipSession::EUpdating )
+        {
+        session.Actions().UpdateFailed();
+        }
+        
+    }
+
+// -----------------------------------------------------------------------------
+// CMceStateOffering::EntryAnswerToUpdateDecodedL
+// -----------------------------------------------------------------------------
+//
+void CMceStateOffering::EntryAnswerToUpdateDecodedL( TMceStateTransitionEvent& aEvent )
+    {
+	CMceSipSession& session = aEvent.Session();
+
+    //if media error, media unusable -> send BYE, stop media and FC
+    if ( aEvent.ParamStatus() == KErrNone )
+        {
+        session.Actions().UpdateSucceed();
+        }
+    else
+        {
+        session.Actions().UpdateFailed();
+        }
+    
+    }
+
+// -----------------------------------------------------------------------------
+// CMceStateOffering::EntryAnswerToOfferDecodedL
+// -----------------------------------------------------------------------------
+//
+void CMceStateOffering::EntryAnswerToOfferDecodedL( TMceStateTransitionEvent& aEvent )
+    {
+	CMceSipSession& session = aEvent.Session();
+    CSIPClientTransaction* response = &session.Response();
+    
+    TInt status = KErrNone;
+        
+    if ( MceSip::ResponseType( *response ) == E1XX &&
+         session.Extensions().LevelL( *response, CMceSipExtensions::E100rel )
+         == CMceSipExtensions::ERequired )
+        
+        { 
+        TBool hasContent = MceSip::HasContent( *response );
+		
+        // TBD: Quick Fix: Need to have Support in MediaManager to ask do we need 
+        // to send SDP or not, decision must be based on conf line, and 2ndly 
+        // based on weither negotiation has completed or not.
+        TBool sendSdp = hasContent &&
+                        ( MCE_NEED_TO_SEND( session, NULL ) ||
+                          session.Extensions().RemoteIMSRel5() ||
+                          session.ActiveBody().Modifier( KMceSecPreconditions ) ==
+                           KMcePreconditionsE2ESupported );
+        //if there is required header for precodition but no precondition
+        //Prack should indicate precondition failure
+        if ( MceSip::ResponseType( *response ) == E1XX &&
+         	session.Extensions().LevelL( *response, CMceSipExtensions::ESecPreconds )
+         	== CMceSipExtensions::ERequired )
+        	{
+        	session.ActiveBody().iRemoteSecPreconditionsRequired = ETrue;
+        	}
+        if ( sendSdp )
+            {
+            status = session.Actions().UpdateL();
+            __ASSERT_ALWAYS( status == KMceReady, User::Leave( KErrArgument ) ); 
+            //need not to change secure keys
+            if ( session.ActiveBody().SecureSession() &&
+            	 MceSip:: ResponseCode( *response ) == KMceSipSessionProgress)
+            	{
+            	session.ActiveBody().SecureSession()->iKeyNeedUpdated = EFalse;
+            	}
+            NAT_WAIT_NO_EXEC( session, session.Actions().EncodeL() )	
+            //session, session.Actions().EncodeL(); 
+            }
+
+		
+        session.Actions().SendPrackL( sendSdp );
+        
+        aEvent.Code() = EMceProvisionalResponse;
+        }
+        
+    }
+    
+
+// -----------------------------------------------------------------------------
+// CMceStateOffering::EntryByeL
+// -----------------------------------------------------------------------------
+//
+void CMceStateOffering::EntryByeL( TMceStateTransitionEvent& aEvent )
+    {
+	CMceSipSession& session = aEvent.Session();
+	
+    //send 200OK and stop media and FC
+    session.Actions().Send200OKL( session.Request() );
+    session.Actions().StopMedia();
+    session.FCActions().ReleaseFC();
+	
+    }
+    
+// -----------------------------------------------------------------------------
+// CMceStateOffering::ExitL
+// -----------------------------------------------------------------------------
+//
+void CMceStateOffering::ExitL( TMceStateTransitionEvent& aEvent )
+	{
+	
+	if ( IsExtensionRequestEvent( aEvent ))
+		{
+		//Do Nothing;
+		}
+
+
+	else
+		{
+		CMceSipSession& session = aEvent.Session();
+		CSIPClientTransaction* response = &session.Response(); 
+		TInt status = aEvent.ParamStatus();
+		
+	    switch( aEvent.Code() )
+	        {
+	        //received BYE causes server & client to terminated state
+	        case EMceBye:
+	            {
+	            session.Actions().StateChanged( KMceStateTerminated );
+	            session.Actions().ClientStateChangedL( 
+	                CMceSession::ETerminated, session.Request() );
+	            break;
+	            }      
+	        case EMceMediaUpdated:
+	            {
+	            if ( MceSip::ResponseType( *response ) == E2XX &&
+                        response->ResponseElements()->CSeqHeader()->Method() == 
+                        SIPStrings::StringF( SipStrConsts::EInvite ) )
+		    		{
+			   		//server and client state established,
+		            //if update was successful Body() returns previous BodyCandidate(),
+		            //if update was failed Body() returns original body
+		            session.Actions().ClientStateChangedL( CMceSession::EEstablished,
+		                                                   *session.Body(),
+		                                                   session.Response(),
+		                                                   status );
+		            session.Actions().StateChanged( KMceStateEstablished );
+               	    }	            
+	            break;
+	            }
+	        case EMceResponse:
+	        case EMceErrorResponse:
+	        case EMceProvisionalResponse:
+	        case EMceRedirectionResponse:
+	            {
+	            ExitSIPEventL( aEvent );
+	            break;                
+	            }
+	       
+	        case EMceItcCancel:
+	            {
+	            session.Actions().StateChanged( KMceStateCanceled );
+	            session.Actions().ClientStateChanged( aEvent.ParamIDs(), 
+	                                                  CMceSession::ECancelling );
+	            break;
+	            }
+	            
+	        default:
+	            {
+	            //NOP
+	            }
+	            
+	        }
+		}
+	
+	}
+
+
+// -----------------------------------------------------------------------------
+// CMceStateOffering::ExitSIPEventL
+// -----------------------------------------------------------------------------
+//
+void CMceStateOffering::ExitSIPEventL( TMceStateTransitionEvent& aEvent )
+    {
+    
+	CMceSipSession& session = aEvent.Session();
+	TInt status = aEvent.ParamStatus();
+    CMceSipSession::TSubState subState = session.SubState();
+	
+	if ( aEvent.Code() == EMceResponse )
+	    {
+        //error in response handling
+        if ( status < KErrNone && subState == CMceSipSession::EOffering )//failed
+            {
+            //no need to update body to client
+            session.Actions().StateChanged( KMceStateTerminating );
+            session.Actions().ClientStateChangedL( CMceSession::ETerminating,
+                                                   session.Response(),
+                                                   status );
+            }
+        else if ( status < KErrNone && subState == CMceSipSession::EUpdating )//failed
+            {
+            //original body is updated to client
+            session.Actions().ClientStateChangedL( CMceSession::EEstablished, 
+                                                   *session.Body(),
+                                                   session.Response(),
+                                                   status );
+            session.Actions().StateChanged( KMceStateEstablished );
+            }
+        else if ( subState == CMceSipSession::ERefreshing )
+            {
+            session.Actions().StateChanged( KMceStateEstablished );
+            session.Actions().ClientStateChangedL( CMceSession::EEstablished,
+                                                   session.Response() );
+            }
+        else
+            {
+            // SDP Answer was received previously, ignore the contents if any
+            // Get into established state.
+            if ( !session.WaitingMediaCallback() &&
+                 !MCE_NEED_TO_RECEIVE( session ) )
+                {
+                session.Actions().StateChanged( KMceStateEstablished );
+                session.Actions().ClientStateChangedL( CMceSession::EEstablished,
+                                                       session.Response() );
+                }
+            else
+                {
+                //wait EMceAnswerDecoded or EMceAnswerToUpdateDecoded
+                }
+            }
+	    }
+    else if ( aEvent.Code() == EMceErrorResponse )
+        {
+        if ( subState == CMceSipSession::EOffering )
+            {
+            TUint code = MceSip::ResponseCode( session.Response() );
+            if ( code != KMceSipExtensionRequired && code != KMceSipSessionIntervalTooSmall  )  
+                {
+                session.Actions().StateChanged( KMceStateTerminated );
+                session.Actions().ClientStateChangedL( CMceSession::ETerminated,
+                                                      session.Response() );
+                }
+            }
+        else if ( subState == CMceSipSession::EUpdating )
+            {
+            if ( MceSip::ResponseCode( 
+                 session.Response() ) == KMceSipCallOrTransactionDoesNotExist ||
+                 MceSip::ResponseCode( 
+                 session.Response() ) == KMceSipRequestTimeout ) 
+                {
+                session.Actions().StateChanged( KMceStateTerminating );
+                session.Actions().ClientStateChangedL( CMceSession::ETerminating,
+                                                       session.Response() );
+                }
+            else
+                {
+                session.Actions().ClientStateChangedL( CMceSession::EEstablished,
+                                                       *session.Body(),
+                                                       session.Response(),
+                                                       KErrCancel );
+                session.Actions().StateChanged( KMceStateEstablished );
+                }
+            }
+        else
+            {//MediaUpdated
+            if ( session.PendingTransaction( SIPStrings::StringF( SipStrConsts::EPrack ) ) )
+                {
+                session.Actions().StateChanged( KMceStateConfirming );
+                }
+            else
+                {
+                session.Actions().ClientStateChangedL( CMceSession::EEstablished,
+                                                   session.Response() );
+                session.Actions().StateChanged( KMceStateEstablished );
+                }
+            }
+        }
+    else if ( aEvent.Code() == EMceRedirectionResponse )
+        {
+        ExitRedirectionEventL( aEvent );
+        }
+        
+        
+  	else//EMceProvisionalResponse
+        {
+        if ( MceSip::ResponseCode( session.Response() ) > KMceSipTrying && 
+             session.Actions().NeedToProcessL( aEvent ) )
+            {
+            // update RSeq of a handled response to the session if it contains
+            TInt rseqValueOfLatestResponse = KErrNotFound;
+            
+            rseqValueOfLatestResponse = MceSip::RSeq( *session.Response().ResponseElements() );
+            
+            if ( rseqValueOfLatestResponse != KErrNotFound )
+            	{
+            	session.SetRSeq( rseqValueOfLatestResponse );		
+            	}
+                        
+            session.Actions().ClientStateChangedL( CMceSession::EOffering,
+                *session.Body(), session.Response() );
+            }
+        
+        if ( session.PendingTransaction( SIPStrings::StringF( SipStrConsts::EPrack ) ) )
+            {
+            session.Actions().StateChanged( KMceStateConfirming );
+            }
+        }
+        
+    }
+
+
+
+// End of File
+