IMPSengine/engsrv/src/impssession.cpp
changeset 0 094583676ce7
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/IMPSengine/engsrv/src/impssession.cpp	Thu Dec 17 08:41:52 2009 +0200
@@ -0,0 +1,1349 @@
+/*
+* Copyright (c) 2002-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: Class for Imps session.
+*
+*
+*/
+
+
+// INCLUDE FILES
+#include    "impsserver.h"
+#include    "impsutils.h"
+#include    "impssession.h"
+#include    "impsfields.h"
+#include    "impserrors.h"
+#include    "impstimer.h"
+#include    "impssubsession.h"
+#include    "ImpsVariantAPI.h"
+#include    "impspacked.h"
+
+// MACROS
+#ifndef _DEBUG
+#define _NO_IMPS_LOGGING_
+#endif
+
+
+// ================= MEMBER FUNCTIONS =======================
+
+// C++ default constructor can NOT contain any code, that
+// might leave.
+//
+CImpsSession::CImpsSession( RMessage2& aMsg )
+        :     CSession2(),
+        iCanceled( EFalse ),
+        iMessageCompleted( EFalse ),
+        iMsgR( aMsg )
+    {
+#ifndef _NO_IMPS_LOGGING_
+    CImpsClientLogger::Log( _L( "Session: NEW session sess=%d" ), ( TInt )this );
+#endif
+    }
+
+
+// Destructor
+// RHandleBase::Close() causes this destructor to be called
+CImpsSession::~CImpsSession()
+    {
+#ifndef _NO_IMPS_LOGGING_
+    CImpsClientLogger::Log( _L( "Session: DELETE session sess=%d" ), ( TInt )this );
+#endif
+    // Check if destructor is called by CServer2 class in failed
+    // entity creation or in other case. iContainer is the last
+    // member created is CreateL() so it can be used for this purpose.
+    TBool wasComplete = iContainer ? ETrue : EFalse;
+    // This is here to close CSP session if client is deleted
+    // without calling close method.
+    CloseSession();
+    TImpsSessIdent csp( SID(), SAP(), UserId() );
+    Server()->CloseSession( csp, wasComplete );
+    delete iApplicationId;
+    delete iSID;
+    delete iSAP;
+    delete iUserId;
+    delete iStream;
+    delete iFields;
+    }
+
+// ---------------------------------------------------------
+// CImpsSession::CreateL()
+// ---------------------------------------------------------
+// This overloads the base class implementation
+void CImpsSession::CreateL( )
+    {
+    iFields = CImpsFields::NewL();
+    // create new object index
+    iSubSessions = CObjectIx::NewL();
+    // initialize the object container using the object container index in the server.
+    iContainer = Server()->NewContainerL();
+    }
+
+// ---------------------------------------------------------
+// CImpsSession::DispatchMessageL()
+// ---------------------------------------------------------
+void CImpsSession::DispatchMessageL( const RMessage2& aMessage )
+    {
+    TInt nbrSess = 0;
+    TUint flag = 0;
+
+    iMsgR = aMessage;
+
+    if ( iCanceled )
+        {
+#ifndef _NO_IMPS_LOGGING_
+        CImpsClientLogger::Log( _L( "Session: already CANCELED aMsg=%d" ),
+                                aMessage.Function() );
+#endif
+        CompleteMe( KErrCancel );
+        return;
+        }
+
+    // Set ETrue at the same time as Message().Complete() takes place
+    iMessageCompleted = EFalse;
+    TInt msg = aMessage.Function();
+    // stripp off bit mask in an upper word
+    msg = msg & 0x0FFFF;
+
+#ifndef _NO_IMPS_LOGGING_
+    CImpsClientLogger::Log( _L( "Session: DispatchMessageL msg=%d sess=%d" ), msg, ( TInt )this );
+#endif
+
+    // current CSP indetification
+    TImpsSessIdent csp( SID(), SAP(), UserId() );
+
+    switch ( msg )
+        {
+        case EImpsServAssign:
+            AssignIdL();
+            // Notice that in this case there is subsession specific part too.
+            // So, do not return yet.
+            break;
+
+        case EImpsAccessRegister2:
+            // NewSubSessionL will check SHUTTING_DOWN state of server and
+            // leaves when necessary
+            NewSubSessionL( EImpsEventServerLogin, aMessage );
+            return;
+
+        case EImpsImRegister:
+            NewSubSessionL( EImpsEventMessage, aMessage );
+            return;
+
+        case EImpsFundRegister:
+            NewSubSessionL( EImpsEventCommon, aMessage );
+            return;
+
+        case EImpsGroupRegister:
+            NewSubSessionL( EImpsEventGroup, aMessage );
+            return;
+
+        case EImpsServPureRegister:
+            {
+            NewSubSessionL( EImpsEventPresencePure, aMessage );
+            }
+        return;
+
+        case EImpsServIsLogged:
+            // This has to return positive value is CSP is found
+            // and it has got SID.
+            if ( IsThisLogged() )
+                {
+                CompleteMe( KErrNone );
+                }
+            else
+                {
+                CompleteMe( KImpsErrorNotLogged );
+                }
+            return;
+
+        case EImpsServNbrSessions:
+            nbrSess = NbrOfSessionsL( );
+            CompleteMe( nbrSess );
+            return;
+
+        case EImpsServServices:
+#ifndef _NO_IMPS_LOGGING_
+            CImpsClientLogger::Log( _L( "Session: EImpsServServices" ) );
+#endif
+            CurrentServicesL();
+            return;
+
+        case EImpsServPush:
+            // multi-csp supported, i.e. CIR given for every CSP session
+            // until sessoin cookie matches
+            if ( Server()->IsShuttingDown() )
+                {
+                User::Leave( KImpsErrorShuttingDown );
+                }
+            PushMessageL();
+            iCIRSess = ETrue;
+            return;
+
+        case EImpsServBuffSizeReq:
+            CompleteMe( IsThisLogged() ? Server()->BufferSize() : 0 );
+            return;
+
+        case EImpsServCloseAll:		// close all sessions
+            Server()->LogoutAll();
+            CompleteMe( KErrNone );
+            return;
+        }
+
+    // subsession specific requests
+    TInt myHandle = aMessage.Int3( );
+    CImpsSubSession* sub = ConnectionFromHandle( myHandle );
+    if ( !sub )
+        {
+        PanicClient( EImpsBadRequest );
+        return;
+        }
+
+    TBool reactive( EFalse );
+
+    switch ( msg )
+        {
+
+        case EImpsServAssign:
+            sub->AssignIdL( csp );
+            return;
+
+            // completion of request made in ServiceL
+        case EImpsServReactiveLogin:
+            reactive = ETrue;
+        case EImpsServWVLogin:
+            if ( Server()->IsShuttingDown() )
+                {
+                User::Leave( KImpsErrorShuttingDown );
+                }
+            if ( !Server()->IsConAllowed() )
+                {
+                User::Leave( KImpsErrorTerminalOffLine );
+                }
+            // multi: check if this session is already logged in.
+            if ( IsThisLogged() )
+                {
+                User::Leave( KImpsErrorAlreadyLogged );
+                }
+            iLogoutTID = KNullDesC;
+            sub->LoginL( reactive );
+            return;
+
+            // case EImpsServWVLogoutOne:
+        case EImpsServWVLogout:
+            if ( Server()->IsShuttingDown() )
+                {
+                User::Leave( KImpsErrorShuttingDown );
+                }
+            if ( !IsThisActive() )
+                {
+                User::Leave( KImpsErrorNotLogged );
+                }
+            iLogoutTID = KNullDesC;
+            iLogoutTID = sub->LogoutL( csp, EFalse );
+            // The following is needed if no force logout
+            // and a shared CSP exists.
+            CompleteMe( KErrNone );
+            return;
+
+        case EImpsServWVSendOnly:
+        case EImpsServBlock:
+        case EImpsServGroup:
+        case EImpsServPres:
+        case EImpsServFundSearch:
+        case EImpsServFundInvite:
+            if ( Server()->IsShuttingDown() )
+                {
+                User::Leave( KImpsErrorShuttingDown );
+                }
+            // multi: check if this handle is logged
+            if ( !IsThisLogged() )
+                {
+                User::Leave( KImpsErrorNotLogged );
+                }
+            else if ( !Server()->IsConAllowed() )
+                {
+                User::Leave( KImpsErrorTerminalOffLine );
+                }
+            sub->SendPrimitiveL( aMessage.Function(), csp );
+            return;
+
+        case EImpsServNextEvent:
+            sub->NextEventL( aMessage );
+            // This is completed later
+            iMessageCompleted = ETrue;
+            return;
+
+        case EImpsServEventBody:
+            sub->SendEventBodyL( aMessage );
+            // This is completed later
+            iMessageCompleted = ETrue;
+            return;
+
+        case EImpsServCloseSub:
+#ifndef _NO_IMPS_LOGGING_
+            CImpsClientLogger::Log( _L( "Session: EImpsServCloseSub" ) );
+#endif
+            sub->Unregister();
+            // remove subsession type
+            flag = sub->Type();
+            iTypes = ( iTypes & ~flag );
+            CompleteMe( KErrNone );
+            return;
+
+        case EImpsServDeleteSub:
+            // remove subsession entity
+#ifndef _NO_IMPS_LOGGING_
+            CImpsClientLogger::Log( _L( "Session: EImpsServDeleteSub" ) );
+#endif
+            sub->DeleteSub();
+            CompleteMe( KErrNone );
+            return;
+
+        case EImpsServGetBlocked:
+            if ( Server()->IsShuttingDown() )
+                {
+                User::Leave( KImpsErrorShuttingDown );
+                }
+            // multi: check if this handle is logged in
+            if ( !IsThisLogged() )
+                {
+                User::Leave( KImpsErrorNotLogged );
+                }
+            else if ( !Server()->IsConAllowed() )
+                {
+                User::Leave( KImpsErrorTerminalOffLine );
+                }
+            sub->SendGetBlockedL( csp );
+            return;
+
+        case EImpsServStatusReg:
+            sub->SetStatusObserver( ETrue );
+            CompleteMe( KErrNone );
+            return;
+
+        case EImpsServStatusUnreg:
+            sub->SetStatusObserver( EFalse );
+            CompleteMe( KErrNone );
+            return;
+
+        case EImpsServDetailedReg:
+            sub->SetDetailedError( ETrue );
+            CompleteMe( KErrNone );
+            return;
+
+        case EImpsServDetailedUnreg:
+            sub->SetDetailedError( EFalse );
+            CompleteMe( KErrNone );
+            return;
+
+        case EImpsServCspVersion:
+            CompleteMe( Server()->CspVersion() );
+            return;
+
+        case EImpsServCancelLogin:	// cancel ongoing login
+            if ( Server()->IsShuttingDown() )
+                {
+                User::Leave( KImpsErrorShuttingDown );
+                }
+            // Call logout with cancel parameter.
+            ( void )sub->LogoutL( csp, ETrue );
+            return;
+
+        case EImpsServCancelTrans:	// cancel transaction
+            // If the specified request is not found then just complete the current request.
+            if ( !sub->CancelTrans( aMessage, csp ) )
+                {
+                CompleteMe( KErrNone );
+                }
+            else
+                {
+                // Complete with cancel if operation is cancelled
+                CompleteMe( KErrCancel );
+                }
+            return;
+
+        case EImpsServSetExpiry:
+            sub->SetExpiryTime( aMessage );
+            CompleteMe( KErrNone );
+            return;
+
+        default:
+            PanicClient( EImpsBadRequest );
+            return;
+        }
+    }
+
+
+// ---------------------------------------------------------
+// CImpsSession::NewSubSessionL
+// ---------------------------------------------------------
+// Create a new connection; pass back its handle via the message
+// Ensures the object is cleaned up on failure
+void CImpsSession::NewSubSessionL(
+    TImpsEventType aType,
+    const RMessage2& aMessage )
+    {
+#ifndef _NO_IMPS_LOGGING_
+    CImpsClientLogger::Log( _L( "Session: NewSubSessionL sess=%d" ), TInt( this ) );
+#endif
+    // Reject request if server is SHUTTING_DOWN
+    if ( Server()->IsShuttingDown() )
+        {
+        User::Leave( KImpsErrorShuttingDown );
+        }
+    CImpsSubSession* sub = CImpsSubSession::NewL( this, aType, aMessage );
+    CleanupClosePushL( *sub );
+    iContainer->AddL( sub );
+    // Add subsession to object index, this returns unique handle
+    TInt handle = iSubSessions->AddL( sub );
+    // write the handle to client
+    TPckg<TInt> handlePckg( handle );
+    TRAPD( res, aMessage.WriteL( 3, handlePckg ) );
+    if ( res != KErrNone )
+        {
+        // Removing sub from object index will
+        // cause Close() to be called on sub, and that calls destructor
+        CleanupStack::Pop();
+        iSubSessions->Remove( handle );
+        PanicClient( EImpsCorrupted );
+        User::Leave( res );
+        }
+    sub->SetHandle( handle );
+    // notch up another resource
+    iResourceCount++;
+    // update iTypes bit Mask
+    iTypes = iTypes | aType;
+    CleanupStack::Pop( );
+    }
+
+// ---------------------------------------------------------
+// CImpsSession::ConnectionFromHandle()
+// ---------------------------------------------------------
+CImpsSubSession* CImpsSession::ConnectionFromHandle( TUint aHandle )
+    {
+    CImpsSubSession* sub = ( CImpsSubSession* )iSubSessions->At( aHandle );
+    return sub;
+    }
+
+// ---------------------------------------------------------
+// CImpsSession::DeleteSubSession
+// ---------------------------------------------------------
+void CImpsSession::DeleteSubSession( TUint aHandle )
+    {
+#ifndef _NO_IMPS_LOGGING_
+    CImpsClientLogger::Log( _L( "Session: DeleteSubSession sess=%d" ), ( TInt )this );
+#endif
+    // panic if bad handle
+    CImpsSubSession* sub = ConnectionFromHandle( aHandle );
+    if ( sub == NULL )
+        {
+#ifndef _NO_IMPS_LOGGING_
+        CImpsClientLogger::Log( _L( "Session: PANIC" ) );
+#endif
+        PanicClient( EImpsCorrupted );
+        }
+
+    // remove subsession
+    iSubSessions->Remove( aHandle );
+    // decrement resource count
+    iResourceCount--;
+
+#ifndef _NO_IMPS_LOGGING_
+    TInt count = iSubSessions->ActiveCount();
+    CImpsClientLogger::Log( _L( "Session: DeleteSubSession nbrsub=%d %d subses=%d" ),
+                            count, iResourceCount,  ( TInt )sub );
+#endif
+    }
+
+// ---------------------------------------------------------
+// CImpsSession::MatchSession
+// ---------------------------------------------------------
+TBool CImpsSession::MatchSession( TImpsSessIdent aCSP )
+    {
+    // -----------------------------------
+    // Notice: comment
+    // extra stuff for debugging
+    /*
+    TPtrC pp1 = aCSP.SAP();
+    TPtrC pp2 = aCSP.UserId();
+    TPtrC pp3 = aCSP.SID();
+    TPtrC ppa = SAP();
+    TPtrC ppb = UserId();
+    TPtrC ppc = SID();
+    CImpsClientLogger::Log(_L("Session: MatchSession aCSP sap=%S user=%S sid=%S"), &pp1, &pp2, &pp3);
+    CImpsClientLogger::Log(_L("Session: MatchSession this sap=%S user=%S sid=%S"), &ppa, &ppb, &ppc);
+    */
+    // -----------------------------------
+
+    // The current session-id must match if it is non-zero
+    if ( aCSP.SID().Length() > 0 &&
+         SID().Length() > 0 &&
+         aCSP.SID().CompareF( SID() ) )
+        {
+        return EFalse;
+        }
+    // Also user-id and SAP address must match
+    else if ( !( SAP().CompareF( aCSP.SAP() ) ) &&
+              !( UserId().CompareF( aCSP.UserId() ) ) )
+        {
+#ifndef _NO_IMPS_LOGGING_
+        TPtrC p1 = SAP();
+        TPtrC p2 = UserId();
+        TPtrC p3 = aCSP.SID();
+        CImpsClientLogger::Log( _L( "Session: MatchSession MATCH sess=%d sap=%S user=%S sid=%S" ),
+                                ( TInt )this,  &p1, &p2, &p3 );
+#endif
+        return ETrue;
+        }
+    else
+        {
+        return EFalse;
+        }
+    }
+
+
+// ---------------------------------------------------------
+// CImpsSession::SendEvent()
+// ---------------------------------------------------------
+void CImpsSession::SendEvent(
+    CImpsFields *aFields,
+    TInt aOpId,
+    TImpsServRequest aRequestType,
+    TImpsMessageType aReqMsgType,
+    TUint aHandle )
+    {
+    // It is possible that the cancel request from client is not
+    // complete and this session entity is still waiting deletion.
+    if ( iCanceled )
+        {
+        return;
+        }
+
+    TInt errx = KErrNone;
+
+#ifndef _NO_IMPS_LOGGING_
+    CImpsClientLogger::Log( _L( "Session: SendEvent begins" ) );
+#endif
+
+    // specified subsession
+    if ( aHandle )
+        {
+        CImpsSubSession* sub = ConnectionFromHandle( aHandle );
+        if ( sub )
+            {
+            sub->SendEvent(
+                aFields,
+                aOpId,
+                aRequestType,
+                aReqMsgType );
+            }
+        }
+    // scan subsessions
+    else
+        {
+        // This is safe even if client would close session or subsession
+        // Scheduler does not allocate time for it until this loop ends.
+        TInt count = iSubSessions->Count();
+        for ( TInt i = 0; i < count; i++ )
+            {
+            CImpsSubSession* sub = ( CImpsSubSession* )( ( *iSubSessions )[i] );
+            if ( sub )
+                {
+                TRAP( errx, sub->SendEvent(
+                          aFields,
+                          aOpId,
+                          aRequestType,
+                          aReqMsgType ) );
+                }
+            }
+        }
+
+#ifndef _NO_IMPS_LOGGING_
+    CImpsClientLogger::Log( _L( "Session: SendEvent ends" ) );
+#endif
+    }
+
+// ---------------------------------------------------------
+// CImpsSession::SendEvent()
+// Lighter version for engine status event
+// ---------------------------------------------------------
+void CImpsSession::SendEvent(
+    EImpsInternalStatus aStatus )
+    {
+
+    // It is possible that the cancel request from client is not
+    // complete and this session entity is still waiting deletion.
+    if ( iCanceled )
+        {
+        return;
+        }
+
+#ifndef _NO_IMPS_LOGGING_
+    CImpsClientLogger::Log( _L( "Session: SendEvent begins aStatus=%d" ), aStatus );
+#endif
+
+    if ( aStatus == EInternal_NOT_LOGGED || aStatus == EInternal_SHUTTING_DOWN )
+        {
+        // NOT_LOGGED event is sent after LogoutResponse and it cleans
+        // the WV CSP TID, so that it will not receive any further
+        // messages from transport.
+        CleanSID();
+        SetThisInactive();
+        }
+
+    // Scan subsessions
+    TInt count = iSubSessions->Count();
+    for ( TInt i = 0; i < count; i++ )
+        {
+        CImpsSubSession* sub = ( CImpsSubSession* )( ( *iSubSessions )[i] );
+        if ( sub )
+            {
+            sub->SendEvent( aStatus );
+            }
+        }
+
+#ifndef _NO_IMPS_LOGGING_
+    CImpsClientLogger::Log( _L( "Session: SendEvent ends" ) );
+#endif
+    }
+
+// ---------------------------------------------------------
+// CImpsSession::SendLogoutEvent
+// ---------------------------------------------------------
+void CImpsSession::SendLogoutEvent(
+    TInt aRespStatus, TInt aOpId, CImpsSubSession* aSub,
+    TUint aHandle )
+    {
+    // It is possible that the cancel request from client is not
+    // complete and this session entity is still waiting deletion.
+    if ( iCanceled )
+        {
+        return;
+        }
+
+#ifndef _NO_IMPS_LOGGING_
+    CImpsClientLogger::Log( _L( "Session: SendLogoutEventL" ) );
+#endif
+
+    // specified subsession only
+    if ( aHandle )
+        {
+        CImpsSubSession* sub = ConnectionFromHandle( aHandle );
+        if ( sub )
+            {
+            sub->SendLogoutEvent( aRespStatus, aOpId );
+            return;
+            }
+        }
+
+    // Scan subsessions
+    TInt count = iSubSessions->Count();
+    for ( TInt i = 0; i < count; i++ )
+        {
+        CImpsSubSession* sub = ( CImpsSubSession* )( ( *iSubSessions )[i] );
+        // Igone a specific subsession
+        if ( sub && sub != aSub )
+            {
+            sub->SendLogoutEvent( aRespStatus, aOpId );
+            }
+        }
+    }
+
+// ---------------------------------------------------------
+// CImpsSession::CheckNotification()
+// ---------------------------------------------------------
+TBool CImpsSession::CheckNotifications(
+    CImpsFields* aFields, TImpsSessIdent aCSP )
+    {
+    TBool retVal( EFalse );
+    // It is possible that the cancel request from client is not
+    // complete and this session entity is still waiting deletion.
+    // Multi: Validate the CSP connection id and check that
+    // client has not completed logout request.
+    if ( iCanceled || !MatchSession( aCSP ) || !IsThisActive() )
+        {
+        return retVal;
+        }
+
+    TInt myType = 0;
+    TInt myOpId = 0;
+    // Notice: client thread use this information
+    if ( aFields->MessageType() == EImpsDisconnect )
+        {
+        myType = EImpsServWVLogout;
+        }
+
+
+    // Scan subsessions
+    TInt count = iSubSessions->Count();
+    for ( TInt i = 0; i < count; i++ )
+        {
+        CImpsSubSession* sub = ( CImpsSubSession* )( ( *iSubSessions )[i] );
+        if ( sub && sub->CheckNotification( aFields ) )
+            {
+            retVal = ETrue;
+            sub->SendEvent(
+                aFields, myOpId, ( TImpsServRequest )myType, EImpsMessageNone );
+            }
+        }
+    return retVal;
+    }
+
+// ---------------------------------------------------------
+// CImpsSession::HandleAllOrphans()
+// ---------------------------------------------------------
+void CImpsSession::HandleAllOrphans()
+    {
+    // current CSP indetification
+    TImpsSessIdent csp( SID(), SAP(), UserId() );
+    // Scan subsessions
+    TInt count = iSubSessions->Count();
+    for ( TInt i = 0; i < count; i++ )
+        {
+        CImpsSubSession* sub = ( CImpsSubSession* )( ( *iSubSessions )[i] );
+        if ( sub )
+            {
+            sub->HandleAllOrphans( csp );
+            }
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CImpsSession::CloseSession()
+// -----------------------------------------------------------------------------
+void CImpsSession::CloseSession()
+    {
+#ifndef _NO_IMPS_LOGGING_
+    CImpsClientLogger::Log( _L( "Session: CloseSession" ) );
+#endif
+
+    iCanceled = ETrue;
+    DeleteAllRequests();
+    void DeleteAllEvents();
+    // Delete the object index (this stores the objects for this session)
+    delete iSubSessions;
+    iSubSessions = NULL;
+    Server()->RemoveContainer( iContainer );
+    iContainer = NULL;
+    }
+
+// ---------------------------------------------------------
+// CImpsSession::CheckRequests()
+// ---------------------------------------------------------
+TUint CImpsSession::CheckRequests(
+    const TDesC& aTid,
+    TInt& aOpId,
+    TImpsServRequest& aRequestType,
+    TImpsMessageType& aReqMsgType,
+    TImpsSessIdent aCSP )
+    {
+
+    // It is possible that the cancel request from client is not
+    // complete and this session entity is still waiting deletion.
+    if ( iCanceled )
+        {
+        return 0;
+        }
+
+    // Check also that the CSP session matches
+    if ( !MatchSession( aCSP ) )
+        {
+        return 0;
+        }
+
+    // Scan subsessions
+    TInt count = iSubSessions->Count();
+    for ( TInt i = 0; i < count; i++ )
+        {
+        CImpsSubSession* sub = ( CImpsSubSession* )( ( *iSubSessions )[i] );
+        if ( sub && sub->CheckRequests(
+                 aTid,
+                 aOpId,
+                 aRequestType,
+                 aReqMsgType ) )
+            {
+            // Check if a successful response for login
+            if ( SID().Length() == 0 &&
+                 aCSP.SID().Length() > 0 &&
+                 aRequestType == EImpsServWVLogin )
+                {
+                // If OOM here then this returns 0 and expiry routines
+                // handles the request later on. This is extremely
+                // rare situation anyway.
+                TRAPD( errx, ModifySIDL( aCSP.SID() ) );
+                if ( errx )
+                    {
+                    return 0;
+                    }
+                }
+            return sub->Handle();
+            }
+        }
+
+    return 0;
+    }
+
+// ---------------------------------------------------------
+// CImpsSession::DiscardRequests()
+// ---------------------------------------------------------
+void CImpsSession::DiscardRequests(
+    TTime aExpiryTime,
+    TImpsEventType aServiceType,
+    TImpsSessIdent aCSP,
+    MImpsCSPSession* aSess )
+    {
+
+    // It is possible that the cancel request from client is not
+    // complete and this session entity is still waiting deletion.
+    // Multi: Validate the CSP connection too.
+    if ( iCanceled || !MatchSession( aCSP ) )
+        {
+        return;
+        }
+
+    // Scan subsessions
+    TInt count = iSubSessions->Count();
+    for ( TInt i = 0; i < count; i++ )
+        {
+        CImpsSubSession* sub = ( CImpsSubSession* )( ( *iSubSessions )[i] );
+        if ( sub )
+            {
+            sub->DiscardRequests( aExpiryTime, aServiceType, aSess );
+            }
+        }
+    }
+
+// ---------------------------------------------------------
+// CImpsSession::DiscardRequests()
+// ---------------------------------------------------------
+void CImpsSession::DiscardRequests(
+    TInt aError,
+    TImpsEventType aServiceType,
+    TImpsSessIdent aCSP,
+    MImpsCSPSession* aSess )
+    {
+
+    // It is possible that the cancel request from client is not
+    // complete and this session entity is still waiting deletion.
+    // It is possible that the cancel request from client is not
+    // complete and this session entity is still waiting deletion.
+    // Multi: Validate the CSP connection too.
+    if ( iCanceled || !MatchSession( aCSP ) )
+        {
+        return;
+        }
+
+    // Scan subsessions
+    TInt count = iSubSessions->Count();
+    for ( TInt i = 0; i < count; i++ )
+        {
+        CImpsSubSession* sub = ( CImpsSubSession* )( ( *iSubSessions )[i] );
+        if ( sub )
+            {
+            sub->DiscardRequests( aError, aServiceType, aSess );
+            }
+        }
+    }
+
+// ---------------------------------------------------------
+// CImpsSession::DiscardRequest()
+// ---------------------------------------------------------
+TBool CImpsSession::DiscardRequest(
+    const TDesC& aTid,
+    TImpsEventType aServiceType,
+    TInt aCode,
+    TImpsSessIdent aCSP )
+    {
+
+    TBool ret( EFalse );
+
+    // It is possible that the cancel request from client is not
+    // complete and this session entity is still waiting deletion.
+    // Multi: Validate the CSP connection too.
+    if ( iCanceled || !MatchSession( aCSP ) )
+        {
+        return EFalse;
+        }
+
+    // Scan subsessions
+    TInt count = iSubSessions->Count();
+    for ( TInt i = 0; i < count; i++ )
+        {
+        CImpsSubSession* sub = ( CImpsSubSession* )( ( *iSubSessions )[i] );
+        if ( sub )
+            {
+            ret = sub->DiscardRequest( aTid, aServiceType, aCode );
+            if ( ret )
+                {
+                return ETrue;
+                }
+            }
+        }
+
+    return EFalse;
+    }
+
+// -----------------------------------------------------------------------------
+// CImpsSession::DeleteAllRequests()
+// -----------------------------------------------------------------------------
+void CImpsSession::DeleteAllRequests( )
+    {
+#ifndef _NO_IMPS_LOGGING_
+    CImpsClientLogger::Log( _L( "Session: DeleteAllRequests" ) );
+#endif
+    if ( iCanceled )
+        {
+        return;
+        }
+
+    // Delete all buffered requests from this client.
+    // Delete from subsessions
+    TInt count = iSubSessions->Count();
+    for ( TInt i = 0; i < count; i++ )
+        {
+        CImpsSubSession* sub = ( CImpsSubSession* )( ( *iSubSessions )[i] );
+        if ( sub )
+            {
+            sub->DeleteAllRequests();
+            }
+        }
+
+    }
+
+// -----------------------------------------------------------------------------
+// CImpsSession::DeleteAllRequests()
+// -----------------------------------------------------------------------------
+void CImpsSession::DeleteAllRequests( TImpsSessIdent* aCSP )
+    {
+#ifndef _NO_IMPS_LOGGING_
+    CImpsClientLogger::Log( _L( "Session: DeleteAllRequests aCSP" ) );
+#endif
+    if ( iCanceled )
+        {
+        return;
+        }
+
+    if ( !MatchSession( *aCSP ) )
+        {
+        return;
+        }
+
+    // Delete all buffered requests from this client.
+    // Delete from subsessions
+    TInt count = iSubSessions->Count();
+    for ( TInt i = 0; i < count; i++ )
+        {
+        CImpsSubSession* sub = ( CImpsSubSession* )( ( *iSubSessions )[i] );
+        if ( sub )
+            {
+            sub->DeleteAllRequests();
+            }
+        }
+
+    }
+
+// -----------------------------------------------------------------------------
+// CImpsSession::DeleteRequest
+// -----------------------------------------------------------------------------
+void CImpsSession::DeleteRequest( TInt aOpId, TUint aSubHandle )
+    {
+
+    if ( aSubHandle )
+        {
+        CImpsSubSession* sub = ConnectionFromHandle( aSubHandle );
+        if ( sub )
+            {
+            sub->DeleteRequest( aOpId );
+            }
+        return;
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CImpsSession::ExpiryTime
+// -----------------------------------------------------------------------------
+TInt CImpsSession::ExpiryTime( )
+    {
+    if ( iCanceled )
+        {
+        return 0;
+        }
+
+    // Search the minimum subsession expiry time.
+    TInt sesexp = 0;
+    TInt exp = 0;
+    TInt count = iSubSessions->Count();
+    for ( TInt i = 0; i < count; i++ )
+        {
+        CImpsSubSession* sub = ( CImpsSubSession* )( ( *iSubSessions )[i] );
+        if ( sub )
+            {
+            exp = sub->ExpiryTime();
+            if ( ( exp && exp < sesexp ) || !sesexp )
+                {
+                sesexp = exp;
+                }
+            }
+        }
+    return sesexp;
+    }
+
+// ---------------------------------------------------------
+// CImpsSession::CompleteMe()
+// ---------------------------------------------------------
+void CImpsSession::CompleteMe( TInt aStatus )
+    {
+    iMsgR.Complete( aStatus );
+    iMessageCompleted = ETrue;
+    }
+
+// ---------------------------------------------------------
+// CImpsSession::PushMessageL()
+// ---------------------------------------------------------
+void CImpsSession::PushMessageL()
+    {
+    // read cookie
+#ifndef _NO_IMPS_LOGGING_
+    CImpsClientLogger::Log( _L( "Session: PushMessageL" ) );
+#endif
+    if ( !iStream )
+        {
+        iStream = HBufC8::NewL( KImpsMaxCookie );
+        }
+
+    // server instance saves these after successful login
+    ( void ) ReadBuffer8L(  1, iStream );
+    Server()->CirMessageL( iStream->Des() );
+    }
+
+
+// ---------------------------------------------------------
+// CImpsSession::ServiceL()
+// ---------------------------------------------------------
+
+void CImpsSession::ServiceL( const RMessage2& aMessage )
+    {
+    TRAPD( err, DispatchMessageL( aMessage ) );
+    if ( !iMessageCompleted )
+        {
+        CompleteMe( err );
+        }
+    }
+
+// ---------------------------------------------------------
+// CImpsSession::PanicClient()
+// ---------------------------------------------------------
+void CImpsSession::PanicClient( TImpsPanic aPanic ) const
+    {
+    iMsgR.Panic( KImpsPanicCategory, aPanic );
+    }
+
+// ---------------------------------------------------------
+// CImpsSession::CurrentServicesL()
+// ---------------------------------------------------------
+void CImpsSession::CurrentServicesL()
+    {
+
+    TImpsSessIdent csp( SID(), SAP(), UserId() );
+    if ( !Server()->IsNegotiated( csp ) )
+        {
+        User::Leave( KImpsErrorServices );
+        }
+
+    // Buffer for response
+    TBuf < sizeof( TImpsServices ) + 4 >
+    myBuf( sizeof( TImpsServices ) + 4 );
+    TImpsServices myServices;
+    myServices.Reset();
+
+    TImpsServices* activeServices = Server()->Services( csp );
+    if ( !activeServices )
+        {
+        User::Leave( KImpsErrorServices );
+        }
+    myServices.Copy( *activeServices );
+
+    // Copy service tree to the local descriptor buffer
+    const TUint8* aPtrStart = ( const TUint8* )myBuf.Ptr();
+    TInt32 tempSize = 0;
+    tempSize = sizeof( TImpsServices );
+    Mem::Copy( ( void* )aPtrStart, &tempSize, sizeof( tempSize ) );
+    aPtrStart = aPtrStart + sizeof( tempSize );
+    if ( tempSize )
+        {
+        Mem::Copy( ( void* )aPtrStart, ( void* )&myServices, tempSize );
+        }
+    TInt ret = iMsgR.Write( 0, myBuf );
+    // complete the request
+    CompleteMe( ret );
+
+    }
+
+// ---------------------------------------------------------
+// CImpsSession::ReadBuffer8L()
+// aBuffer must be a member if there is a risk that
+// more memory must be allocated, because of cleanupstack is
+// inconsistent otherwise.
+// ---------------------------------------------------------
+TBool CImpsSession::ReadBuffer8L(
+    TInt aIndex,
+    HBufC8*& aBuffer )
+//
+// Copies a buffer from the client
+// Only fails if there is not enough memory to increase the buffer size
+//
+    {
+    TBool alloced = EFalse;
+    TInt desLen = iMsgR.GetDesLength( aIndex );
+
+    if ( desLen < 0 )
+        {
+        User::Leave( desLen );
+        }
+
+    HBufC8* newBuffer = NULL;
+
+    if ( aBuffer == NULL )
+        {
+        newBuffer = HBufC8::NewLC( desLen );
+        alloced = ETrue;
+        }
+    else if ( desLen > aBuffer->Des().MaxLength() )
+        {
+        alloced = ETrue;
+        // we have to increase the size of buffer
+        aBuffer->Des().SetLength( 0 ); // to avoid copying the contents
+        newBuffer = aBuffer->ReAllocL( desLen  );
+        CleanupStack::PushL( newBuffer );
+        }
+
+    TPtr8 desPtr = alloced ? newBuffer->Des() : aBuffer->Des();  //lint !e613 !e661
+    // newBuffer is allocated, aBuffer must not be zero
+    iMsgR.ReadL( aIndex, desPtr );
+
+    if ( alloced )
+        {
+        aBuffer = newBuffer;
+        CleanupStack::Pop();
+        }
+
+    return alloced;
+
+    }
+
+// ---------------------------------------------------------
+// CImpsSession::ApplicationId()
+// ---------------------------------------------------------
+TPtrC CImpsSession::ApplicationId()
+    {
+    return iApplicationId ? TPtrC( *iApplicationId ) : TPtrC();
+    }
+
+// ---------------------------------------------------------
+// CImpsSession::SetUserIdL()
+// ---------------------------------------------------------
+void CImpsSession::SetUserIdL( const TDesC& aId )
+    {
+    delete iUserId;
+    iUserId = NULL;
+    iUserId = aId.AllocL();
+    }
+
+// ---------------------------------------------------------
+// CImpsSession::SetSAPL()
+// ---------------------------------------------------------
+void CImpsSession::SetSAPL( const TDesC& aId )
+    {
+    delete iSAP;
+    iSAP = NULL;
+    iSAP = aId.AllocL();
+    }
+
+// ---------------------------------------------------------
+// CImpsSession::SetThisInactive()
+// Use iUserId to check whether client session is logged in
+// ---------------------------------------------------------
+void CImpsSession::SetThisInactive()
+    {
+#ifndef _NO_IMPS_LOGGING_
+    CImpsClientLogger::Log( _L( "Session: SetThisInactive sess=%d" ), ( TInt )this );
+#endif
+    delete iUserId;
+    iUserId = NULL;
+    }
+
+// ---------------------------------------------------------
+// CImpsSession::NewFieldsL()
+// Old iFields must not be deleted because of CImpsServer
+// still uses that.
+// ---------------------------------------------------------
+void CImpsSession::NewFieldsL()
+    {
+    CImpsFields* newF = CImpsFields::NewL();
+    iFields = newF;
+    }
+
+// ---------------------------------------------------------
+// CImpsSession::AssignIdL()
+// ---------------------------------------------------------
+void CImpsSession::AssignIdL()
+    {
+
+#ifndef _NO_IMPS_LOGGING_
+    CImpsClientLogger::Log( _L( "Session: AssignIdL begins" ) );
+#endif
+    // Generate session's application id and client id
+    RMessage2 myMsg( iMsgR );
+    // verify that length is valid
+    TInt desLen = myMsg.GetDesLength( 0 );
+    if ( desLen > KImpsMaxClientId )
+        {
+#ifndef _NO_IMPS_LOGGING_
+        CImpsClientLogger::Log( _L( "Session: Error: too long client-id" ) );
+#endif
+        User::Leave( KImpsErrorValidate );
+        }
+    // allocate memory dynamically
+    delete iApplicationId;
+    iApplicationId = NULL;
+    iApplicationId = HBufC::NewL( desLen );
+    TPtr desPtr = iApplicationId->Des();
+    myMsg.ReadL( 0, desPtr );
+    }
+
+// ---------------------------------------------------------
+// CImpsSession::CleanSID()
+// ---------------------------------------------------------
+void CImpsSession::CleanSID()
+    {
+    if ( !iSID )
+        {
+        return;
+        }
+#ifndef _NO_IMPS_LOGGING_
+    TPtr p = iSID->Des();
+    CImpsClientLogger::Log( _L( "Session: CleanSID sess=%d sid=%S" ), ( TInt )this, &p );
+#endif
+    delete iSID;
+    iSID = NULL;
+    }
+
+// ---------------------------------------------------------
+// CImpsSession::ModifySIDL()
+// ---------------------------------------------------------
+void CImpsSession::ModifySIDL( const TDesC& aSID )
+    {
+#ifndef _NO_IMPS_LOGGING_
+    TPtrC p = aSID;
+    CImpsClientLogger::Log( _L( "Session: ModifySIDL sess=%d sid=%S" ), ( TInt )this, &p );
+#endif
+    delete iSID;
+    iSID = NULL;
+    iSID = aSID.AllocL();
+    }
+
+// ---------------------------------------------------------
+// CImpsSession::NbrSessionsL( )
+// ---------------------------------------------------------
+TInt CImpsSession::NbrOfSessionsL()
+    {
+    RMessage2 myMsg( Message() );
+
+    // Read PACKED ARRAY
+    CDesCArrayFlat* tempArr = new ( ELeave )CDesCArrayFlat( 2 );
+    CleanupStack::PushL( tempArr );   // << tempArr
+
+    HBufC8* stream = *StreamBufAddr();
+    if ( ReadBuffer8L( 0, stream ) )
+        {
+        HBufC8** stream2 = StreamBufAddr();
+        *stream2 = stream;
+        }
+    TImpsPackedEntity packedMessage( stream );
+    const TUint8* pS = stream->Ptr();
+    packedMessage.DoUnpackArrayL( pS, tempArr );
+
+    __ASSERT_DEBUG(
+        tempArr->MdcaCount() == 2,
+        User::Panic( KImpsPanicCategory,
+                     EImpsCorrupted ) );
+
+    TPtrC tempUser = tempArr->MdcaPoint( 1 );
+    TPtrC tempSAP = tempArr->MdcaPoint( 0 );
+    TImpsSessIdent csp( KNullDesC, tempSAP, tempUser );
+
+    // ask number of clint sessions
+    TInt ret =  Server()->NbrSessions( EFalse, csp );
+
+    tempArr->Reset();
+    CleanupStack::PopAndDestroy( 1 );   // >> tempArr
+
+    return ret;
+    }
+
+
+// -----------------------------------------------------------------------------
+// CWvEvent::CWvEvent
+// -----------------------------------------------------------------------------
+
+CWvEvent::CWvEvent( TImpsEventType aType ) :
+        iType( aType ),
+        iMessageType( EImpsStatus ), // just default
+        iSent( EFalse ),
+        iPackedMessage ( NULL )
+    {}
+
+CWvEvent::~CWvEvent()
+    {
+    if ( iPackedMessage )
+        {
+        delete iPackedMessage;
+        }
+    iPackedMessage = NULL;
+    }
+
+void CWvEvent::Destroy()
+    {
+    iLink.Deque();
+    delete this;
+    }
+
+// -----------------------------------------------------------------------------
+// CRequest::CRequest
+// -----------------------------------------------------------------------------
+CRequest::CRequest(
+    const TDesC& aTID,
+    TInt aOpId,
+    TImpsServRequest aRequestType,
+    TTime aExpiry,
+    TImpsMessageType aMessageType )
+        : iOpId( aOpId ),
+        iRequestType ( aRequestType ),
+        iMessageType ( aMessageType ),
+        iExpiry( aExpiry )
+    {
+    iTID = aTID;
+    }
+
+CRequest::~CRequest()
+    {
+
+    }
+
+void CRequest::Destroy()
+    {
+    iLink.Deque();
+    delete this;
+    }
+
+//  End of File