IMPSengine/engsrv/src/impscspsession.cpp
author Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Thu, 17 Dec 2009 08:41:52 +0200
changeset 0 094583676ce7
permissions -rw-r--r--
Revision: 200949 Kit: 200951

/*
* Copyright (c) 2004 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: Session for IMPS.
*
*
*/


// INCLUDE FILES
#include    <e32base.h>
#include    <e32math.h>
#include    "impsserver.h"
#include    "impssession.h"
#include    "impssubsession.h"
#include    "impscspsession.h"
#include    "impsfields.h"
#include    "impsutils.h"
#include    "impserrors.h"
#include    "impstimer.h"
#include    "impssendreceive.h"
#include    "impsservices.h"
#include    "impscommonenums.h"
#include    "impssdatautils.h"
#include    "impsmessageinterpreterapi.h"
#include    "impsdataaccessor.h"
#include    "impsdigestbytes.h"
#include    "impsvariant.h"
#include    "impsalivemanager.h"
#include    "impsactivecirmonitor.h"
#include    "ImpsVariantAPI.h"
#include    "impstidqueue.h"
#include    "impsactivecirmonitor.h"

#ifdef LOCAL_IMPS
#ifndef _FAKE_RESPONSE
#define _FAKE_RESPONSE
#endif
#endif

#ifdef _FAKE_RESPONSE
#include    "impssrvtestutils.h"
#endif

// MACROS
#ifndef _DEBUG
#define _NO_IMPS_LOGGING_
#endif

// CONSTANTS
// Adative polling policy time increment
const TInt KImpsPollIncrement = 10;

// ================= MEMBER FUNCTIONS =======================

CImpsCSPSession::CImpsCSPSession( CImpsServer& aServer,
                                  TImpsSrvSettings& aSettings,
                                  RFs& aFs,
                                  CImpsVariant& aVariant,
                                  TImpsCspVersion aVer ):
        iServer( aServer ),
        iCSPVersion( aVer ),
        iFs( aFs ),
        iVariant( aVariant ),
        iTransactionList( _FOFF( CTransaction, iLink ) ), //lint !e413
        iRequestList( _FOFF( CReq, iLink ) ), //lint !e413
        iCSPState( EImpsCSPIdle ),
        iPendingLogout( EFalse ),
        iAliveMgr( NULL ),
        iPollTime( KImpsPollTime ),
        iPollWasRequested( EFalse ),
        iUserId( NULL ),
        iIntStatus ( EInternal_NOT_LOGGED ),
        iMultiTrans( KImpsMultiTrans ),
        iNegoExpiry( ),
        iCirManager( NULL ),
        iLogoutTID( KNullDesC ),
        iConAllowed( ETrue ),
        iPendingAlive( EFalse ),
        iSAP( NULL ),
        iIAP( 0 ),
        iPollState( EImpsPollNone ),
        iPollInResume( 0 ),
        iPendingPDP( EImpsPDPPendNone ),    // PDP:
        iPendPDPLogout ( EFalse ), // PDP:
        iTidSapHistory( NULL ),
        iTidCliHistory( NULL ),
        iTcpCIRError( EFalse ),
        iCancelLogin ( EFalse )
    {
    iCSPSessionId = KNullDesC;
    iLogCID = KNullDesC;
    iTempTid = KNullDesC;
    iTempTid2 = KNullDesC;
    iMsg = EImpsMessageNone;
    iLoginPhase = 1;
    iKey1 = NULL;
    iKey2 = NULL;
    iSettings = aSettings;
    }

// Create and start a new server.

CImpsCSPSession* CImpsCSPSession::NewL( CImpsServer& aServer,
                                        TImpsSrvSettings& aSettings,
                                        RFs& aFs,
                                        CImpsVariant& aVariant,
                                        TImpsCspVersion aVer )
    {
#ifndef _NO_IMPS_LOGGING_
    if ( aVer == EImpsCspVersion11 )
        {
        CImpsClientLogger::Log( _L( "CSPSession: NewL rel200542.2+ WV 1.1" ) );
        }
    else
        {
        CImpsClientLogger::Log( _L( "CSPSession: NewL rel200542.2+ WV 1.2" ) );
        }
#endif

    CImpsCSPSession* self = new ( ELeave ) CImpsCSPSession( aServer,
                                                            aSettings, aFs, aVariant, aVer );
    CleanupStack::PushL( self );
    self->ConstructL();
    CleanupStack::Pop();
    return self;
    }

CImpsCSPSession::~CImpsCSPSession()
    {
#ifndef _NO_IMPS_LOGGING_
    CImpsClientLogger::Log( _L( "CSPSession: DESTRUCTOR csp=%d **" ), ( TInt )this );
#endif
    // deallocate all memory
    DeleteTransactions();
    DeleteRequests();

    delete iTransportOut;

    delete iCirManager;
    delete iReceiver2;
    delete iAllMessages;
    delete iRcv;
    delete iSnd;

    delete iIdleTimer;
    delete iAliveMgr;

    delete iSendQ;

    delete iTCPAddr;
    delete iLogPwd;
    delete iLogTid;
    delete iKey1;
    delete iKey2;
    delete iUserId;

    delete iSAP;

    if ( iDecoder )
        {
        iDecoder->Destroy();
        }
    if ( iEncoder )
        {
        iEncoder->Destroy();
        }

    delete iPDPIdleTimer;
    delete iPDPOpenTimer;
    delete iTidSapHistory;
    delete iTidCliHistory;
    }

// -----------------------------------------------------------------------------
// CImpsCSPSession::Destroy()
// -----------------------------------------------------------------------------
void CImpsCSPSession::Destroy()
    {
#ifndef _NO_IMPS_LOGGING_
    CImpsClientLogger::Log( _L( "CSPSession: Destroy csp=%d" ), ( TInt )this );
#endif
    // You MUST delete ip-cir entity before conn-manager entity.
    // refer to ImpsIpCirWatcherApi.h.
    delete iCirManager;
    iCirManager = NULL;
    iReceiver2->Destroy();
    delete iReceiver2;
    iReceiver2 = NULL;
    }

// -----------------------------------------------------------------------------
// CImpsCSPSession::ConstructL()
// -----------------------------------------------------------------------------
void CImpsCSPSession::ConstructL()
    {
#ifndef _NO_IMPS_LOGGING_
    CImpsClientLogger::Log( _L( "CSPSession: ConstructL begins csp=%d **" ), ( TInt )this );
#endif

    iTransportOut = CBufFlat::NewL( KImpsStreamSize / 2 );
    iTransportOut->ResizeL( KImpsStreamSize );

    iDecoder = NewDecoderL( this );
    iEncoder = NewEncoderL();

    iTidSapHistory = CImpsTidQueue::NewL();
    iTidCliHistory = CImpsTidQueue::NewL();

    iSnd = CImpsFields::NewL();
    iRcv = CImpsFields::NewL();
    iIdleTimer = new ( ELeave ) CImpsIdleTimer( *this, CActive::EPriorityStandard );
    iPDPIdleTimer = new ( ELeave ) CImpsPDPIdleTimer( *this, CActive::EPriorityStandard );
    iPDPOpenTimer = new ( ELeave ) CImpsPDPOpenTimer( *this, CActive::EPriorityStandard );
    iAliveMgr = CImpsAliveManager::NewL( *this );

    iSendQ = new ( ELeave ) CImpsSendQueued( * this, CActive::EPriorityStandard );

    // Just initialize undefined address
    iTCPAddr = HBufC::NewL( 1 );
    *iTCPAddr = KNullDesC;

    TPtrC8 myMime = iEncoder->MimeType();
    iReceiver2 = CImpsSendReceive2::NewL(
                     iFs, *this, *iTransportOut, myMime );

#ifndef _NO_IMPS_LOGGING_
    CImpsClientLogger::Log( _L( "CSPSession:ConstructL ends" ) );
#endif
    }

// -----------------------------------------------------------------------------
// CImpsCSPSession::CloseAll()
// CImpsServer::CloseEngine calls this. TransportStatus handles the callback.
// -----------------------------------------------------------------------------
void CImpsCSPSession::CloseAll( )
    {
#ifndef _NO_IMPS_LOGGING_
    CImpsClientLogger::Log( _L( "CSPSession: CloseAll %d csp=%d" ), ( TInt )this );
#endif

    NewState( EImpsCSPShuttingDown );

    if ( iIdleTimer )
        {
        iIdleTimer->Stop( );
        }
    iPollState = EImpsPollNone;
#ifndef _NO_IMPS_LOGGING_
    CImpsClientLogger::Log( _L( "CSPSession: iPollState %d" ), iPollState );
#endif

    if ( iAliveMgr )
        {
        iAliveMgr->StopTimer( );
        }

    if ( iSendQ )
        {
        iSendQ->Cancel( );
        }

    if ( iCirManager )
        {
        iCirManager->CloseCh( 0xF );
        delete iCirManager;
        iCirManager = NULL;
        }

    // Close the transport
    if ( iReceiver2 )
        {
        iReceiver2->CloseTr( );
        }
    // TransportStatus handles rest of shut down activities
    }


// -----------------------------------------------------------------------------
// CImpsCSPSession::ClosePDP
// called by - CImpsPDPIdleTimer
// ClosePDP method needed to close PDP-context.
// -----------------------------------------------------------------------------
void CImpsCSPSession::ClosePDP()
    {
#ifndef _NO_IMPS_LOGGING_
    CImpsClientLogger::Log( _L( "CSPSession: ClosePDP" ) );
#endif

    if ( iPollState != EImpsPollCIR )
        {
#ifndef _NO_IMPS_LOGGING_
        CImpsClientLogger::Log( _L( "CSPSession: ClosePDP IGNORED iPollState = %d****" ),
                                iPollState );
#endif
        return;
        }
    if ( IsPDPIdle() )
        {
#ifndef _NO_IMPS_LOGGING_
        CImpsClientLogger::Log( _L( "CSPSession: ClosePDP PDP already IDLE ****" ) );
#endif
        if ( iCSPState == EImpsCSPOnLineIdleEnd )
            {
#ifndef _NO_IMPS_LOGGING_
            CImpsClientLogger::Log( _L( "CSPSession: ClosePDP -> EImpsPDPPendClose" ) );
#endif
            // set pending close request if PDP is opening
            iPendingPDP = EImpsPDPPendClose;
            }
        return;
        }

    NewState( EImpsCSPOnLineIdleStart );

    // This does not close WAP-SMS-CIR
    if ( iCirManager )
        {
        iCirManager->CloseCh( 0xF );
        delete iCirManager;
        iCirManager = NULL;
        }

    // Close the transport
    if ( iReceiver2 )
        {
        iReceiver2->ClosePDP( );
        }
    // TransportStatus handles rest of shut down activities
    }


// -----------------------------------------------------------------------------
// CImpsCSPSession::OpenPDP
// Called by LogoutL, SendAliveL, SendDataL, TransportStatus, SendAllQueued
// Called by CIRMessageL directly and by the CImpsPDPTimer class too.
// OpenPDP method needed to re-open PDP-context
// -----------------------------------------------------------------------------
TInt CImpsCSPSession::OpenPDP()
    {
#ifndef _NO_IMPS_LOGGING_
    CImpsClientLogger::Log( _L( "CSPSession: OpenPDP" ) );
#endif
    if ( !IsPDPIdle() )
        {
        // Nothing to do
#ifndef _NO_IMPS_LOGGING_
        CImpsClientLogger::Log( _L( "CSPSession: OpenPDP IGNORED - not idle" ) );
#endif
        return KErrAlreadyExists;
        }
    else if ( iCSPState == EImpsCSPOnLineIdleEnd )
        {
        // already opening
#ifndef _NO_IMPS_LOGGING_
        CImpsClientLogger::Log( _L( "CSPSession: OpenPDP IGNORED - EImpsCSPOnLineIdleEnd" ) );
#endif
        return KErrNotReady;
        }
    else if ( iCSPState == EImpsCSPOnLineIdleStart )
        {
#ifndef _NO_IMPS_LOGGING_
        CImpsClientLogger::Log( _L( "CSPSession: OpenPDP -> EImpsPDPPendOpen" ) );
#endif
        iPendingPDP = EImpsPDPPendOpen;
        return KErrNone;
        }

    NewState( EImpsCSPOnLineIdleEnd );
    TRAPD( errx, iReceiver2->OpenPDPL( SAP(), iIAP ) );
    if ( errx )
        {
        NewState( EImpsCSPOnLineIdle );
        // Does not matter which error code is returned. Used in Logout only
        // to start internal logout routines.
#ifndef _NO_IMPS_LOGGING_
        CImpsClientLogger::Log( _L( "CSPSession: err: openpdp E1 ****" ) );
#endif
        return KErrGeneral;
        }
    return KErrNone;
    // TransportStatus/transportError handles rest of open activities
    }

// -----------------------------------------------------------------------------
// CImpsCSPSession::LoginL
// -----------------------------------------------------------------------------
TPtrC CImpsCSPSession::LoginL(
    const TDesC& aUser,
    const TDesC& aPassword,
    const TDesC& aClientId,
    const TDesC& aSAP,
    TUint32 aAP,
    const TDesC& aKey1,
    const TDesC& aKey2,
    TTime aLoginExpiry,
    TBool aReactive )
    {
#ifndef _NO_IMPS_LOGGING_
    CImpsClientLogger::Log( _L( "CSPSession: LoginL state=%d csp=%d" ), iCSPState, ( TInt )this );
#endif

    // AOL Login
    if ( aKey1.Length() && aKey2.Length() )
        {
        // this should be the case anyway
        iSettings.iFourWayLogin = ETrue;
        delete iKey1;
        iKey1 = NULL;
        iKey1 = aKey1.AllocL();
        delete iKey2;
        iKey2 = NULL;
        iKey2 = aKey2.AllocL();
        }
    TPtrC tid ( KNullDesC );

    delete iSAP;
    iSAP = NULL;
    iSAP = aSAP.AllocL();
    iIAP = aAP;

    iPendingAlive = EFalse;
#ifndef _NO_IMPS_LOGGING_
    CImpsClientLogger::Log( _L( "CSPSession: iPendingAlive->F" ) );
#endif

    if ( iCSPState >= EImpsCSPLogged )
        {
#ifndef _NO_IMPS_LOGGING_
        CImpsClientLogger::Log( _L( "CSPSession: err: Login when logged ***" ) );
#endif
        User::Leave( KImpsErrorAlreadyLogged );
        }
    else if ( iCSPState == EImpsCSPDisconnecting )
        {
#ifndef _NO_IMPS_LOGGING_
        CImpsClientLogger::Log( _L( "CSPSession: err: Login when CSP logging out ***" ) );
#endif
        User::Leave(  KErrNotReady );
        }
    // Check that no active CSP session exists
    // This should not happen before login
    else if ( iReceiver2->NbrOfPending() >= KImpsMaxPending ||
              iCSPState == EImpsCSPLogging )
        {
#ifndef _NO_IMPS_LOGGING_
        CImpsClientLogger::Log( _L( "CSPSession: err: Login when busy ***" ) );
#endif
        User::Leave( KErrNotReady );
        }
    // Close old connections if any in re-login case (wrong psw first time e.g.)
    // The pending logout response is handled above, not here.
    else if ( iReceiver2->isConnected() )
        {
        // These are for re-login without logout after an error response
        NewState( EImpsCSPIdle );
        iPollState = EImpsPollNone;
#ifndef _NO_IMPS_LOGGING_
        CImpsClientLogger::Log( _L( "CSPSession: iPollState %d" ), iPollState );
        CImpsClientLogger::Log( _L( "CSPSession: err: transport was connected ***" ) );
#endif
        iAliveMgr->StopTimer();
        iSendQ->Cancel();
        iIntStatus = EInternal_NOT_LOGGED;
        iReceiver2->CloseTr();
        User::Leave( KErrNotReady );
        }

    // aPassword cannot be NULL
    delete iLogPwd;
    iLogPwd = NULL;
    delete iUserId;
    iUserId = NULL;
    iLogPwd = aPassword.AllocL();
    iUserId = aUser.AllocL();
    iLogCID = aClientId;
    iLogoutTID = KNullDesC;
    iNegoExpiry = aLoginExpiry;
    iReactive = aReactive;
    TImpsSrvUtils::InitializeServices( iServices, iReactive );

    // Make a login request
    iSnd->Reset();
    tid.Set( GenerateTid() );
    iSnd->SetTidL( tid );
    iSnd->SetMessageType( EImpsLoginReq );
    // Session type is OUTBAND
    iSnd->SetSessionTypeL( EImpsOutband );

    TImpsDataAccessor myAccess( iSnd );
    CImpsKey* myKey = CImpsKey::NewLC();    // <<< myKey

    iAliveTime = iSettings.iAliveTime;

    if ( iSettings.iFourWayLogin == EFalse )
        {
        TImpsSDataUtils::CreateLoginReqL(
            myKey,
            &myAccess,
            aUser,
            iLogCID,
            LogPwd(),
            GenerateCookie(),
            iAliveTime );
        // set this, that response goes to the right place
        iLoginPhase = 2;
        }
    else
        {
        TImpsDigestSchema aSchema = EImpsMD5;
        TImpsSDataUtils::CreateLoginReqPhaseOneL(
            myKey,
            &myAccess,
            aUser,
            iLogCID,
            aSchema,
            GenerateCookie(),
            iAliveTime );
        // just to be sure
        iLoginPhase = 1;
        }

    // Add TImpsTransactionMode now
    myKey->Reset();
    TImpsSDataUtils::AddValuesFromArrayL(
        myKey,
        KTransModeElements,
        sizeof( KTransModeElements ) /
        sizeof( KTransModeElements[0] ) );
    myAccess.StoreIntegerL( myKey, EImpsRequest );
    CleanupStack::PopAndDestroy( 1 );   // >>> myKey

    // Save login id for error handling purposes
    iTempTid2 = tid;

    // Set WV version
    iSnd->SetCspVersion( iCSPVersion );

    // Encode login request
    iEncoder->EncodeMessageL( myAccess, *iTransportOut );
    iLastSent = EImpsLoginReq;

    delete iLogTid;
    iLogTid = NULL;
    iLogTid = tid.AllocL();

    // This does not leave immediately if network is not available
    NewState( EImpsCSPLogging );
    TRAPD( errx, iReceiver2->OpenL( tid, iSettings.iXmlLog, aSAP, aAP ) );
    if ( errx )
        {
        // In rare situations the previous call may leave
        NewState( EImpsCSPIdle );
        User::Leave( errx );
        }

    // iReceiver callback handles the rest of the login method.
    // This handles interrupted logout request as well as shut down interrupt

    iMsg = EImpsMessageNone;

    return tid;
    }

// -----------------------------------------------------------------------------
// CImpsCSPSession::LogoutL
// Notice that subsession class prevents calling this in certain
// situations, if not iLogged or not pending login operation.
// Therefore shut down situation is not handled here.
// -----------------------------------------------------------------------------
TPtrC CImpsCSPSession::LogoutL( TBool aCancel )
    {
#ifndef _NO_IMPS_LOGGING_
    CImpsClientLogger::Log( _L( "CSPSession: LogoutL state=%d cancel=%d csp=%d" ), iCSPState,
                            aCancel, ( TInt )this );
#endif

    if ( iCSPState == EImpsCSPIdle )
        {
#ifndef _NO_IMPS_LOGGING_
        CImpsClientLogger::Log( _L( "CSPSession: LogoutL LEAVES KImpsErrorNotLogged" ) );
#endif
        iPendingPDP = EImpsPDPPendNone;
        iPendPDPLogout = EFalse;
        User::Leave( KImpsErrorNotLogged );
        }

    if ( iCancelLogin && aCancel )
        {
        // cancel login already requested!
        return TPtrC();
        }

    // Make a logout request (encode)
    TPtrC tid;
    tid.Set( GenerateTid() );
    iLogoutTID = tid;
    // Use iLogoutTID when loggin out later after PDP-open
    // Check if PDP is closed and start to re-open it here (Logout)
    if ( IsPDPIdle() )
        {
        // check this flag when PDP has been re-opened
        iPendPDPLogout = ETrue;
        if ( iCSPState == EImpsCSPOnLineIdle )
            {
            // E1: error handling; return boolean to speed up error handling
            // E2: fix:
            if ( OpenPDP() )
                {
#ifndef _NO_IMPS_LOGGING_
                CImpsClientLogger::Log( _L( "CSPSession: err: Ex2 OpenPDP FAILS ****" ) );
#endif
                DoLogout();
                }
            return tid;
            }
        }

    if ( iCSPState != EImpsCSPLogging )
        {
        // Clear buffers from old stuff
        DeleteRequests();
        DeleteTransactions();
        // Send Logout primitive and set state to EImpsCSPDisconnecting.
        TRAPD( errx, DoSendLogoutL( tid ) );
        if ( errx )
            {
#ifndef _NO_IMPS_LOGGING_
            CImpsClientLogger::Log( _L( "CSPSession: DoSendLogoutL error %d ***" ), errx );
#endif
            // Do logout routines immediately if transport gives an error
            DoLogout();
            // The following error code is handled in a special way in
            // client session classes.
            User::Leave( KImpsErrorTerminalOffLine );
            }
        }
    else // LoggingIn
        {
        if ( !aCancel )
            {
            iPendingLogout = ETrue;
#ifndef _NO_IMPS_LOGGING_
            CImpsClientLogger::Log( _L( "CSPSession: iPendingLogout->TRUE ***" ) );
#endif
            }
        else
            {
            iCancelLogin = ETrue;
#ifndef _NO_IMPS_LOGGING_
            CImpsClientLogger::Log( _L( "CSPSession: iCancelLogin->TRUE ***" ) );
#endif
            }
        // Logout must not ever fail so this must not leave.
        StartLoginCancel( );
        }

    return tid;
    }

// -----------------------------------------------------------------------------
// CImpsCSPSession::CirMessageL
// -----------------------------------------------------------------------------
void CImpsCSPSession::CirMessageL(
    const TDesC8& aCookie )
    {
#ifndef _NO_IMPS_LOGGING_
    CImpsClientLogger::Log( _L( "CSPSession: CirMessageL csp=%d" ), ( TInt )this );
#endif

    // if CIR is not negotiated then ignore
    if ( ( iSettings.iUDPWAPCIR != 2 && iSettings.iSMSWAPCIR != 2 &&
           iSettings.iTCPSCIR != 2 && iSettings.iUDPSCIR != 2 ) ||
         !IsNegotiated() )
        {
#ifndef _NO_IMPS_LOGGING_
        CImpsClientLogger::Log( _L( "CSPSession: CirMessage IGNORED" ) );
#endif
        return;
        }

    // check session cookie but not CSP-version.
    // CIR syntax: WVCI <CSP-version> <Session-cookie>

    TPtrC8 cookie = aCookie.Left( 4 );
    if ( cookie.CompareF( _L8( "WVCI" ) ) )
        {
#ifndef _NO_IMPS_LOGGING_
        CImpsClientLogger::Log( _L( "CSPSession: CirMessage SYNTAX ERROR" ) );
#endif
        User::Leave( KErrArgument );
        }

    cookie.Set( aCookie );
    // Find if the cookie exists in this push body
    if ( cookie.Find( iCookie8 ) == KErrNotFound )
        {
#ifndef _NO_IMPS_LOGGING_
        CImpsClientLogger::Log( _L( "CSPSession: CirMessage COOKIE ERROR" ) );
#endif
        User::Leave( KImpsErrorUnauthorized );
        }

    // reset PDP idle timer when CIR received
    iPDPIdleTimer->Reset();

    // If PDP-context is idle or shutting down then set pending open request.
    if ( IsPDPIdle() )
        {
        if ( iCSPState == EImpsCSPOnLineIdle ||
             iCSPState == EImpsCSPOnLineIdleStart )
            {
            iPendingPDP = EImpsPDPPendOpen;
            }
        if ( !iPollInResume )
            {
            iPollInResume = 1;
#ifndef _NO_IMPS_LOGGING_
            CImpsClientLogger::Log( _L( "CSPSession: iPollInResume %d" ),
                                    iPollInResume );
#endif
            }
        // This is a fix for cases when GPRS bearer event has not been received
#ifndef _NO_IMPS_LOGGING_
        CImpsClientLogger::Log( _L( "CSPSession: CIR -> openPDP ****" ) );
#endif
        OpenPDP();
        iPDPOpenTimer->Start( KImpsPDPRetryOpenTime );
        }

    // Send the actual Poll message
    else if ( iIntStatus == EInternal_ON_LINE )  // && !PDPIdle
        {
        TRAPD( errPoll, SendPollL() );
        if ( errPoll && !iPollInResume )
            {
            iPollInResume = 1;
#ifndef _NO_IMPS_LOGGING_
            CImpsClientLogger::Log( _L( "CSPSession: iPollInResume %d" ), iPollInResume );
#endif
            }
        }
    else  // NOT ON_LINE && !PDPIdle
        {
        // WAP SMS CIR causes OFF-LINE and therefore has to wait ON-LINE
        iPollState = EImpsPollPending;
#ifndef _NO_IMPS_LOGGING_
        CImpsClientLogger::Log( _L( "CSPSession: iPollState %d" ), iPollState );
#endif
        }
    }

// -----------------------------------------------------------------------------
// CImpsCSPSession::SendDataL
// -----------------------------------------------------------------------------
TPtrC CImpsCSPSession::SendDataL(
    CImpsFields* aFields, TInt aExpiry, TBool& aOwnerCh )
    {

#ifndef _NO_IMPS_LOGGING_
    CImpsClientLogger::Log( _L( "CSPSession: SendDataL begins csp=%d" ), ( TInt )this );
#endif

    // reset PDP idle timer
    iPDPIdleTimer->Reset();

    aOwnerCh = EFalse;

    // generate TID
    CImpsFields* fields = aFields;
    TPtrC tid;
    tid.Set( GenerateTid() );
    fields->SetTidL( tid );
    // Insert CSP Session-id
    fields->SetSessionIdL( iCSPSessionId );
    // Session-type
    fields->SetSessionTypeL( EImpsInband );

    TImpsDataAccessor myAccess( fields );
    CImpsKey* myKey = CImpsKey::NewLC();    // <<< myKey

    // Add TImpsTransactionMode now
    myKey->Reset();
    TImpsSDataUtils::AddValuesFromArrayL(
        myKey,
        KTransModeElements,
        sizeof( KTransModeElements ) /
        sizeof( KTransModeElements[0] ) );
    myAccess.StoreIntegerL( myKey, EImpsRequest );

    // API supports deliver method and thus do not overwrite it here anymore

    CleanupStack::PopAndDestroy( 1 );   // >>> myKey

    // We have to check if queued messages exist
    TBool queuedMsg = EFalse;
    queuedMsg = RequestExist();

    // if PDP-idle then queue request + start to open PDP
    TInt nbrPend = iReceiver2->NbrOfPending();
    if ( nbrPend >= KImpsMaxPending ||
         iIntStatus != EInternal_ON_LINE ||
         iTr >= iMultiTrans ||
         queuedMsg ||
         IsPDPIdle() )
        {
        // Transport adapter is busy so queue the request
        QueueClientRequestL( fields, aExpiry );
        aOwnerCh = ETrue;
        if ( iCSPState == EImpsCSPOnLineIdle )
            {
            // Try to open PDP only once, don't start open PDP timer.
            // The request will expiry if this fails anyway and it's
            // a task of application to retry sending of this message.
            OpenPDP( );
            }
        else if ( iCSPState == EImpsCSPOnLineIdleStart ||
                  iCSPState == EImpsCSPOnLineIdle )
            {
            iPendingPDP = EImpsPDPPendOpen;

            /* Notice:
             Thus CImpsConnManager DLL
             does not give bearer event for GPRS resume in all situations
             it is better to try to open the connection always.
            */
            OpenPDP();
            }

        else if ( queuedMsg )
            {
            // This must not leave because of the error is not message specific
            SendAllQueued();
            }
        }
    else
        {
        // Message sending should be possible without PDP open
        DoSendSingleL(
            &myAccess, tid, ( TImpsMessageType ) fields->MessageType() );
        }

#ifndef _NO_IMPS_LOGGING_
    CImpsClientLogger::Log( _L( "CSPSession: SendData ends" ) );
#endif

    return tid;
    }

// -----------------------------------------------------------------------------
// CImpsCSPSession::TransportResponseL
// -----------------------------------------------------------------------------
void CImpsCSPSession::TransportResponseL( HBufC8** aDataPtr )
    {
#ifndef _NO_IMPS_LOGGING_
    CImpsClientLogger::Log( _L( "CSPSession: TransportResponseL csp=%d" ), ( TInt )this );
#endif

    HBufC8* rawData = *aDataPtr;

    // reset PDP idle timer
    iPDPIdleTimer->Reset();

    SendAllQueued();

    TInt myError = KErrNone;
    // Handle pending logout here
    if ( iPendingLogout || iCancelLogin )
        {
        DoPendingLogout();
        return;
        }

    if ( rawData == NULL || rawData->Des().Length() == 0 )
        {
        // SAP did not send anything in the response
        iLastReceived = 0;
        // Increase adaptive polling time if necessary
        if ( iLastSent == EImpsPolling )
            {
            IncreasePollTime();
            }
        return;
        }

    if ( iLastSent != EImpsKeepAliveReq )
        {
        // Reset poll timer
        ResetPollTime();
        }

    if ( iRcv )
        {
        iRcv->Reset();
        }
    else
        {
        // QueueTidL may have leaved and this is NULL
        iRcv = CImpsFields::NewL();
        }

    CImpsDataAccessor* myAccess = CImpsDataAccessor::NewLC( iRcv ); // <<<

    TInt retCode = KErrNone;

// ----------- NORMAL CASE -------------------------
#ifndef _FAKE_RESPONSE

#ifndef _NO_IMPS_LOGGING_
    CImpsClientLogger::Log( _L( "CSPSession: Gonna to call Decode" ) );
#endif
    // Decode to iRcv
    iDecoder->DecodeMessageL( *myAccess, aDataPtr );
    retCode = iRcv->ResponseStatusL();
    // Decode errors cancel this method and error are
    // reported to client by expiry timers.

#ifndef _NO_IMPS_LOGGING_
    CImpsClientLogger::Log( _L( "CSPSession: Decoded status = %d" ), iRcv->Status() );
    CImpsClientLogger::Log( _L( "CSPSession: Decoded ResponseStatus = %d" ),
                            retCode );
#endif

// ----------- NORMAL CASE ENDS -------------------------

// ----------- TEST CASE -------------------------
#endif  // ifndef _FAKE_RESPONSE

#ifdef _FAKE_RESPONSE
    TImpsSrvTestUtils tests( *this, iFs );
    tests.MakeFakeResponseL( myAccess, aDataPtr );
#endif
// ----------- TEST CASE ENDS -------------------------

    // Message successfully received from SAP
    // Session-id check
    if ( iRcv->SessionTypeL() == EImpsInband )
        {
        TPtrC sesId = iRcv->SessionIdL();
        // This is case sensitive
        if ( sesId.Length( ) > 0 && sesId.Compare( iCSPSessionId ) )
            {
            // Invalid session id
            User::Leave( KImpsErrorSID );
            }
        }

    // KeepAlive handling
    iAliveMgr->CheckResp( retCode );

    // ---------------------------------
    // check if multiTrans messages
    // ---------------------------------
    TInt trs = myAccess->NbrOfTransactionsL( );
    if ( trs < 1 )
        {
        // If no transaction content then it is handled as encode error
        myError = KImpsErrorDecode;
        }
    else if ( trs == 1 )
        {
        // regular case, one transaction content in a transport messages
        // Update internal data structure (CImpsFields)
#ifndef _FAKE_RESPONSE
        if ( !( myAccess->GetTransactionL( 0, NULL ) ) )
            {
            // internal error
            myError = KErrCorrupt;
            }
#endif
        }

    // ----------------------------------
    // checking multiTrans messages ends
    // ----------------------------------

    // If error then stop further progress of transport response
    if ( myError )
        {
        User::Leave( myError );
        }

    // Check if PollRequest was requested in incoming transport message
    if ( iRcv->PollL() )
        {
        iPollWasRequested = ETrue;
#ifndef _NO_IMPS_LOGGING_
        CImpsClientLogger::Log( _L( "CSPSession: iPollWasRequested->T in msg" ) );
#endif
        }
    else
        {
        iPollWasRequested = EFalse;
#ifndef _NO_IMPS_LOGGING_
        CImpsClientLogger::Log( _L( "CSPSession: iPollWasRequested->F in msg" ) );
#endif
        }

    if ( trs > 1 )
        {
        delete iAllMessages;
        iAllMessages = iRcv;
        iRcv = CImpsFields::NewL();
        }
    else
        {
        // paranoid about memory leaks
        delete iAllMessages;
        iAllMessages = NULL;
        }

    // ---------------------------------
    // Send each new message to sessions
    // ---------------------------------
    for ( TInt i = 0; i < trs; i ++ )
        {

        if ( trs == 1 )
            {
            // No need for split
            }
        else
            {
            // Data accessor points to the original iRcv (allMessages)
            iRcv->Reset();
#ifndef _NO_IMPS_LOGGING_
            CImpsClientLogger::Log( _L( "CSPSession: MULTI-TRANS nbr=%d" ), i );
#endif
            if ( !( myAccess->GetTransactionL( i, iRcv ) ) )
                {
#ifndef _NO_IMPS_LOGGING_
                CImpsClientLogger::Log( _L( "CSPSession: Error with MultiTrans" ) );
#endif
                // error, continue
                continue;
                }
            }

        iLastReceived = iRcv->MessageType();

#ifndef _NO_IMPS_LOGGING_
        CImpsClientLogger::Log( _L( "CSPSession: TransportResponse msg = 0x%x" ),
                                iLastReceived );
#endif

        // Check if csp Session startup routines needed
        // TID is case sensitive
        if ( ( iCSPState == EImpsCSPLogging || iCSPState == EImpsCSPNegotiation ) &&
             ( iRcv->MessageType() == EImpsLoginRes ||
               iRcv->MessageType() == EImpsClientCapabilityRes ||
               iRcv->MessageType() == EImpsServiceRes ||
               ( iRcv->MessageType() == EImpsStatus &&
                 !iRcv->TidL().Compare( iTempTid2 ) ) ) )
            {
            SessionStartupL( iRcv );
            }
        // Sent events to all sub-sessions interested in this type of event
        // This also handles login-resposes and removes the login-req from
        // queues.
        if ( iRcv->MessageType() != 0 &&
             iRcv->MessageType() != EImpsClientCapabilityRes &&
             iRcv->MessageType() != EImpsServiceRes &&
             iLoginPhase != 2 )
            {
            RouteMessageL();
            }
        }  // for

    // CIR-error-flag check in WV 1.2.
    // WV 1.1 messages returns always EFalse.
    // Check this flag only if TCP/IP CIR channel is negotiated.
    if ( !iTcpCIRError && iSettings.TCPSCIR() == 2 && IsLogged() )
        {
        // Close and re-open TCP/IP CIR if CIR flag is on.
        TInt erx = KErrNone;
        TRAP( erx, iTcpCIRError = TImpsSDataUtils::GetCIRL( myAccess ) );
        // iTcpCIRError is reset in CirChOpened()
        if ( iTcpCIRError )
            {
            if ( iCirManager )
                {
                iCirManager->CloseCh( KImpsCirTcp );
                }
            TRAP( erx, DoStartIpCIRL() );
            }
        }

    CleanupStack::PopAndDestroy( 1 );   // >>> myAccess

    delete iAllMessages;
    iAllMessages = NULL;

    SendAllQueued();

#ifndef _NO_IMPS_LOGGING_
    CImpsClientLogger::Log( _L( "CSPSession: TransportResponse ends" ) );
#endif

    }

// -----------------------------------------------------------------------------
// CImpsCSPSession::TransportErrorL
// -----------------------------------------------------------------------------
void CImpsCSPSession::TransportErrorL(
    const TDesC& aTID,
    TInt aError )
    {
#ifndef _NO_IMPS_LOGGING_
    CImpsClientLogger::Log( _L( "CSPSession: TransportError err=%d tid=%S csp=%d" ), aError, &aTID, ( TInt )this );
#endif

    TImpsCSPState origCSP = iCSPState;
    // reset PDP idle timer
    iPDPIdleTimer->Reset();

    TImpsSessIdent csp( iCSPSessionId, DoSAP(), DoUserId() );


    // Handle pending logout here
    // CSP destroyer is started finally
    if ( iPendingLogout || iCancelLogin )
        {
        NewState( EImpsCSPDisconnecting );
        DoPendingLogout();
        return;
        }

    // Do not let the PDP start up again if it has just shut down.
    if ( origCSP == EImpsCSPOnLineIdleEnd && aTID.Length() == 0 &&
         aError == KImpsErrorNoIAP )
        {
#ifndef _NO_IMPS_LOGGING_
        CImpsClientLogger::Log( _L( "CSPSession: DON'T START UP PDP AGAIN ****" ) );
#endif
        if ( iPollState > EImpsPollAdaptive )
            {
            iPollState = EImpsPollCIR;
#ifndef _NO_IMPS_LOGGING_
            CImpsClientLogger::Log( _L( "CSPSession: iPollState %d" ), iPollState );
#endif
            }
        ResetPollTime();
        iPendingAlive = EFalse;
#ifndef _NO_IMPS_LOGGING_
        CImpsClientLogger::Log( _L( "CSPSession: iPendingAlive->F" ) );
#endif
        NewState( EImpsCSPOnLineIdle );

        // KeepAlive handling
        iAliveMgr->CheckError( aTID );

        // Discard all the current requests
        // We change the error code for UI.
        // First we have to check if there is Logout request so that
        // it is completed with OK status!
        if ( LogoutTID().Length() )
            {
#ifndef _NO_IMPS_LOGGING_
            CImpsClientLogger::Log( _L( "CSPSession: Err: Discard logout ****" ) );
#endif
            // This is for normal logout response error, i.e. no pending logout nor login-cancel.
            iServer.DiscardLogout( LogoutTID(), csp );
            DoLogout();
            }
        iServer.DiscardRequests( EImpsEventAll, KImpsErrorBearerSuspended, csp, this );
        return;
        }

    // Let's call this to be sure that new messages are sent
    SendAllQueued();

    // Reset poll timer to resume from error case
    ResetPollTime();

    TInt myErr = KErrNone;

    if ( iRcv )
        {
        iRcv->Reset();
        }
    else
        {
        // QueueTidL may have leaved and this is NULL
        iRcv = CImpsFields::NewL();
        }

    // This ensures that login gets a response in 4-way login later phase
    if ( origCSP == EImpsCSPLogging && !LogTid().CompareF( aTID ) )
        {
#ifndef _NO_IMPS_LOGGING_
        CImpsClientLogger::Log( _L( "CSPSession: Special LogTid ****" ) );
#endif
        // Route response to a requestion client and later below do logout.
        iRcv->SetTidL( LogTid() );
        }
    else
        {
        iRcv->SetTidL( aTID );
        }
    iRcv->SetMessageType( EImpsStatus );
    iRcv->SetStatus( aError );
    TRAP( myErr, RouteMessageL( ) );

    // KeepAlive handling
    iAliveMgr->CheckError( aTID );

    if ( origCSP == EImpsCSPLogging )
        {
#ifndef _NO_IMPS_LOGGING_
        CImpsClientLogger::Log( _L( "CSPSession: err: Ex ****" ) );
#endif
        DoLogout();
        }
    // If RouteMessage has not done internal logout then let's do it here
    else if ( origCSP == EImpsCSPDisconnecting )
        {
#ifndef _NO_IMPS_LOGGING_
        CImpsClientLogger::Log( _L( "CSPSession: err: E6 ****" ) );
#endif
        // Message type is used in subsession to prevent sending logout event twice
        iServer.DiscardLogout( iLogoutTID, csp );
        DoLogout();
        }

    return;
    }

// -----------------------------------------------------------------------------
// CImpsCSPSession::RouteMessageL
// -----------------------------------------------------------------------------
void CImpsCSPSession::RouteMessageL(  )
    {
#ifndef _NO_IMPS_LOGGING_
    CImpsClientLogger::Log( _L( "CSPSession: RouteMessageL begins csp=%d" ), ( TInt )this );
#endif

    TImpsSessIdent csp( iCSPSessionId, DoSAP(), DoUserId() );

    // *****************************************************
    // First check keep alive reponses
    // *****************************************************

    TInt32 resstatus = iRcv->ResponseStatusL();

    // KeepAlive time may be reset on fly
    if ( iRcv->MessageType() == EImpsKeepAliveRes )
        {
        if ( resstatus != KImpsStatusOk )
            {
#ifndef _NO_IMPS_LOGGING_
            CImpsClientLogger::Log( _L( "CSPSession: RouteMessageL ends 1" ) );
#endif
            return;
            }
        // get new KeepAlive time if any
        TInt newTime = 0;
        TImpsDataAccessor myAc( iRcv );
        if ( TImpsSDataUtils::GetKeepAliveL( &myAc, newTime ) )
            {
            iAliveTime = newTime;
            iAliveMgr->StartTimer( iAliveTime );
#ifndef _NO_IMPS_LOGGING_
            CImpsClientLogger::Log( _L( "Server: new AliveTime %d" ), iAliveTime );
#endif
            }
        // Keep alive response does not cause events to clients
#ifndef _NO_IMPS_LOGGING_
        CImpsClientLogger::Log( _L( "CSPSession: RouteMessageL ends 2" ) );
#endif
        return;
        }

    // *************************************************************
    // Ignore informational messages from server status code 100-199
    // *************************************************************
    if ( resstatus >= 100 && resstatus < 200 )
        {
        iTr--;
#ifndef _NO_IMPS_LOGGING_
        CImpsClientLogger::Log( _L( "CSPSession: 100-200 iTr = %d" ), iTr );
        CImpsClientLogger::Log( _L( "CSPSession: RouteMessageL ends 3" ) );
#endif
        return;
        }

    // *************************************************************
    // Harmonize WV 1.1 and WV 1.2 logout responses
    // *************************************************************
    TImpsLogoutTrans logoutRsp = IsLogoutResp( iRcv );

    // *****************************************************
    // Handle regular request
    // *****************************************************

    // Check requests
    TBool someFound = EFalse;
    TBool notOrphan = EFalse;
    TInt error = 0;
    // The following sends logout reponse to a requesting client
    TRAP( error, iServer.CheckRequestsL ( iRcv, someFound, csp ) );

    if ( someFound )
        {
        // Message was response to our request, login phase has not
        // increased this counter, that's why if statement here
        TrMinus();
        }
    else if ( iRcv->MessageType() != EImpsDisconnect )
        {
        // Check that SAP initiated TID is not sent to clients already.
        if ( ValidateTid( ETrue ) )
            {
            // Notifications check.
            notOrphan = iServer.CheckNotifications( iRcv, csp );
            }
        }

    // Check error that means cancelled CSP session
    // notice: fullfill the list of serious erros
    if ( logoutRsp != EImpsLogoutNone  ||
         resstatus == 600 || resstatus == 601 || resstatus == 604 )
        {
        TInt myOpId = 0;
        if ( logoutRsp == EImpsLogoutSAP )
            {
            // Detect SAP initiated logout. disconnect primitive and
            // TID not matching to our own logout TID.
            myOpId = KImpsNullId;
            }
        // Both logout callback events and Status change events
        // are sent here in logout.
        DoLogoutNow( myOpId );
#ifndef _NO_IMPS_LOGGING_
        CImpsClientLogger::Log( _L( "CSPSession: RouteMessageL ends 4" ) );
#endif
        return;
        }

    // No reason to do this:
    // if ( someFound ) notOrphan = ETrue;

    // If the message was not a response to our TID then it was SAP originated
    // Update pending transaction queue
    if ( ( iRcv->MessageType() != EImpsDisconnect ) &&
         ( iRcv->MessageType() != EImpsMessageNone ) &&
         ( iRcv->MessageType() != EImpsStatus ) &&
         ( !someFound )
       )
        {
        // Make SAP response to wait actions
        QueueTidL( !notOrphan );
        }

#ifndef _NO_IMPS_LOGGING_
    CImpsClientLogger::Log( _L( "CSPSession: RouteMessageL ends 5" ) );
#endif
    }

// -----------------------------------------------------------------------------
// CImpsCSPSession::GetNextMessageL
// Called by SendReceive2
// -----------------------------------------------------------------------------
void CImpsCSPSession::GetNextMessageL( )
    {

#ifndef _NO_IMPS_LOGGING_
    CImpsClientLogger::Log( _L( "CSPSession: GetNextMessageL begins" ) );
#endif

    // Use this to generate response for SAP intiated transactions
    iSnd->Reset();

    // Rejected, nothing to send
    if ( !IsLogged() )
        {
        return;
        }

    // Send next buffered user request if any
    // search. Not immediately, but via active object scheduler
    SendAllQueued();

    iLastSent = 0;
    return;
    }

// -----------------------------------------------------------------------------
// CImpsCSPSession::CheckExpiry
// -----------------------------------------------------------------------------
void CImpsCSPSession::CheckExpiry(
    TImpsEventType aType, const TTime aExpiry  )
    {
#ifndef _NO_IMPS_LOGGING_
    CImpsClientLogger::Log( _L( "CSPSession: CheckExpiry begins" ) );
#endif

    TImpsSessIdent csp( iCSPSessionId, DoSAP(), DoUserId() );

    // Login negotiation phase is a special case.
    // Access timer handles that.
    // Because of there may be messages not initiated by
    // API methods, server must check special time-out variable iNegoExpiry.
    // Internal iRequestList cannot be used for that purpose
    // because of requests are deleted after transport has
    // got them succesfully, but we are not satisfied until get response.

    if ( IsLogged() && !IsNegotiated() && iNegoExpiry < aExpiry )
        {
        // Expired negotiation in session startup negotiation
        TInt errorCode = KErrTimedOut;
        switch ( iMsg )
            {
            case EImpsClientCapabilityReq:
                errorCode = KImpsErrorCapabilities;
                break;
            case EImpsServiceReq:
                errorCode = KImpsErrorServices;
                break;
            default:
                break;
            }
        iServer.SendErrorEvent( EImpsEventServerLogin, errorCode, 0, csp );
        // goto to NOT_LOGGED
        DoLogout();
        }
    else if ( iCSPState == EImpsCSPDisconnecting && iNegoExpiry < aExpiry )
        {
        if ( iCancelLogin || iPendingLogout )
            {
            DoPendingLogout();
            }
        else
            {
            iServer.DiscardLogout( LogoutTID(), csp );
            // goto to NOT_LOGGED
            DoLogout();
            }
        }
    else if ( iCSPState == EImpsCSPLogging && iNegoExpiry < aExpiry )
        {
#ifndef _NO_IMPS_LOGGING_
        CImpsClientLogger::Log( _L( "CSPSession: CheckExpiry in EImpsCSPLogging ***" ) );
#endif
        iServer.DiscardRequests( aType, aExpiry, csp, this );
        DoLogout();
        }
    else
        {
        // Regular mode.
        // Go through all sessions (each having an own request list)
        // The following ends up calling CancelTrans and there
        // we can check if login or logout is expired and change the
        // iCSPState.
        iServer.DiscardRequests( aType, aExpiry, csp, this );
        }
    }

// -----------------------------------------------------------------------------
// CImpsCSPSession::SessionStartupL
// -----------------------------------------------------------------------------
void CImpsCSPSession::SessionStartupL( CImpsFields* aFields )
    {
#ifndef _NO_IMPS_LOGGING_
    CImpsClientLogger::Log( _L( "CSPSession: SessionStartupL begins csp=%d" ), ( TInt )this );
#endif

    TImpsSessIdent csp( iCSPSessionId, DoSAP(), DoUserId() );
    TInt errx = KErrNone;
    TrMinus();

    // check if error for 2-way login
    if ( ( !IsLogged() ) &&
         (
             aFields->MessageType() == EImpsLoginRes ||
             aFields->MessageType() == EImpsStatus ) &&
         aFields->ResponseStatusL() != KImpsStatusOk &&
         !iSettings.iFourWayLogin
       )
        {
        // RouteMessageL handles errors if iLoginPhase != 2
        // iLoginPhase starts from 2 in 2-way login
        // See LoginL method
        NewState( EImpsCSPIdle );
        iReceiver2->CloseTr();
        return;
        }

    // Login response, 4-way login phase one
    // *************************************
    if ( aFields->MessageType() == EImpsLoginRes &&
         aFields->Status() == KErrNone &&
         ( aFields->ResponseStatusL() == KImpsStatusOk ||
           aFields->ResponseStatusL() == 401 ) &&
         iLoginPhase == 1 )
        {
#ifndef _NO_IMPS_LOGGING_
        CImpsClientLogger::Log( _L( "CSPSession: SessionStartupL 4-login phase one" ) );
#endif
        iLoginPhase++;
        TRAP( errx, HandleLoginResponseL( aFields ) );
        if ( errx )
            {
            iServer.DiscardRequest( LogTid(), EImpsEventServerLogin, errx, csp );
            NewState( EImpsCSPIdle );
            }
        return;
        }   // LOGIN RESPONSE1

    // Login response, 4-way login phase two or 2-way login
    // ****************************************************
    // save session id if received
    if ( aFields->MessageType() == EImpsLoginRes &&
         aFields->Status() == KErrNone &&
         aFields->ResponseStatusL() == KImpsStatusOk &&
         iLoginPhase == 2 )
        {
        iLoginPhase++;
#ifndef _NO_IMPS_LOGGING_
        CImpsClientLogger::Log( _L( "CSPSession: SessionStartupL 4-login phase two" ) );
#endif
        TImpsDataAccessor myAc( aFields );

        TPtrC newId;
        TImpsSDataUtils::GetLoginSessionIDL( &myAc, newId );
        // protect us against illegal data from SAP
        if ( newId.Length() > KImpsMaxSID )
            {
            User::Leave( KErrCorrupt );
            }
        iCSPSessionId = newId;

        // get TimeToLive
        TInt newTime( 0 );
        if ( TImpsSDataUtils::GetKeepAliveL( &myAc, newTime ) )
            {
            iAliveTime = newTime;
            }

        NewState( EImpsCSPLogged );
        // This is next message to be sent
        iMsg = EImpsClientCapabilityReq;

        // KeepAlive timer started when logged in
        iAliveMgr->StartTimer( iAliveTime );
        // Start polling timer with a static value to be sure that
        // something is received if SAP happened to send an empty response.
        // After capability negotiation a proper value is set for polling timer.
        iPollState = EImpsPollAdaptive;
        iIdleTimer->Start( iSettings.iMaxPollTime );
#ifndef _NO_IMPS_LOGGING_
        CImpsClientLogger::Log( _L( "CSPSession: iPollState %d" ), iPollState );
        CImpsClientLogger::Log( _L( "CSPSession: PollTime %d" ), iSettings.iMaxPollTime );
        CImpsClientLogger::Log( _L( "CSPSession: AliveTime %d" ), iAliveTime );
#endif

        // Let's send Client Capability request
        TRAP( errx, DoSendClientCapabilityReqL() );
        if ( errx )
            {
            TImpsSessIdent csp( iCSPSessionId, DoSAP(), DoUserId() );
            iServer.SendErrorEvent( EImpsEventServerLogin,
                                    KImpsErrorCapabilities, 0, csp );
            }
        return;
        }   // LOGIN RESPONSE


    // Client capability response
    // ***************************
    if ( aFields->MessageType() == EImpsClientCapabilityRes &&
         aFields->Status() == KErrNone &&
         IsLogged() )
        {
#ifndef _NO_IMPS_LOGGING_
        CImpsClientLogger::Log( _L( "CSPSession: SessionStartupL ClientCapabality" ) );
#endif
        TRAP( errx, HandleClientCapabilityResL ( aFields ) );
        if ( errx )
            {
            TImpsSessIdent csp( iCSPSessionId, DoSAP(), DoUserId() );
            iServer.SendErrorEvent( EImpsEventServerLogin, KImpsErrorCapabilities, 0, csp );
            NewState( EImpsCSPLogged );
            }
        // Let's send Service Negotiation request
        TRAP( errx, DoSendServiceNegotiationReqL () );
        if ( errx )
            {
            TImpsSessIdent csp( iCSPSessionId, DoSAP(), DoUserId() );
            iServer.SendErrorEvent( EImpsEventServerLogin, KImpsErrorServices, 0, csp );
            NewState( EImpsCSPLogged );
            }
        return;
        }

    // Service Negotiation response
    // ****************************
    if ( aFields->MessageType() == EImpsServiceRes &&
         aFields->Status() == KErrNone &&
         IsLogged() )
        {

#ifndef _NO_IMPS_LOGGING_
        CImpsClientLogger::Log( _L( "CSPSession: SessionStartupL ServiceRes" ) );
#endif
        iTempTid2 = KNullDesC;

        if ( aFields->MessageType() == EImpsServiceRes )
            {
            TImpsDataAccessor myAccess( aFields );
            // Calculate agreed features and functions
            TImpsSrvUtils::DiscardServicesL(
                &myAccess,
                &iServices );
            }

        // WV engine state in ON_LINE now
        iIntStatus = EInternal_ON_LINE;
        NewState( EImpsCSPOnLine );
        iMsg = EImpsMessageNone;

#ifndef _NO_IMPS_LOGGING_
        CImpsClientLogger::Log( _L( "CSPSession: status ON_LINE" ) );
#endif
        // Send events to clients
        iServer.TransportStatus( EInternal_ON_LINE, this );

        // Start PDP idle time if WAP-SMS-CIR is negotiated as only CIR channel.
        if ( iSettings.iSMSWAPCIR == 2 ||
             iSettings.iUDPWAPCIR == 2 ||
             iSettings.iTCPSCIR == 2 ||
             iSettings.iUDPSCIR == 2 )
            {
            // goto CIR-polling-mode
            iPollState = EImpsPollCIR;
            iPollTime = iSettings.CIRModePollTime();
            iIdleTimer->Start( iPollTime );
#ifndef _NO_IMPS_LOGGING_
            CImpsClientLogger::Log( _L( "CSPSession: iPollState %d" ), iPollState );
            CImpsClientLogger::Log( _L( "CSPSession: iPollTime %d" ), iPollTime );
#endif
            }
        if ( iSettings.iSMSWAPCIR == 2 )
            {
            // PDP Idle timer closes PDP-context
            iPDPIdleTimer->Start( iSettings.PDPExpiryTime() );
            }

        TInt errxy = KErrNone;
        TRAP( errxy, DoStartIpCIRL() );
        }

    // Error handling in negotiation phase AND FOR 4-WAY-LOGIN
    // ********************************************************
    if ( ( aFields->Status() != KErrNone ) ||
         ( aFields->ResponseStatusL() != KImpsStatusOk &&
           aFields->ResponseStatusL() != 0 ) )
        {
        TInt errorCode = KErrNone;
#ifndef _NO_IMPS_LOGGING_
        CImpsClientLogger::Log( _L( "CSPSession: SessionStartupL Error handling %d" ), iMsg );
#endif
        switch ( iMsg )
            {
            case EImpsClientCapabilityReq:
                errorCode = KImpsErrorCapabilities;
                break;
            case EImpsServiceReq:
                errorCode = KImpsErrorServices;
                break;
            default:
                break;
            }
        if ( errorCode )
            {
            TImpsSessIdent csp( iCSPSessionId, DoSAP(), DoUserId() );
            iServer.SendErrorEvent( EImpsEventServerLogin, errorCode, 0, csp );
            // We assume that an application will call logout in this case
            // and thus we do not close PDP here.
            }
        else
            {
            // RouteMessageL handles errors if iLoginPhase != 2
            NewState( EImpsCSPIdle );
            // routeMessaegL does not close PDP context so let't do it now
            iReceiver2->CloseTr();
            }
        }
#ifndef _NO_IMPS_LOGGING_
    CImpsClientLogger::Log( _L( "CSPSession: SessionStartupL ends" ) );
#endif
    }

// -----------------------------------------------------------------------------
// CImpsCSPSession::DoSendClientCapabilityReqL
// -----------------------------------------------------------------------------
void CImpsCSPSession::DoSendClientCapabilityReqL ()
    {
    CImpsFields* tempFields = CImpsFields::NewL();
    CleanupStack::PushL( tempFields );  // <<< tempFields
    tempFields->SetMessageType( EImpsClientCapabilityReq );
    tempFields->SetSessionTypeL( EImpsInband );
    iTempTid2 = GenerateTid();
    TImpsDataAccessor myAccess( tempFields );

    iMultiTrans = iSettings.iMultiTrans;
    iPollTime = iSettings.iPollTime;

#ifndef _NO_IMPS_LOGGING_
    CImpsClientLogger::Log( _L( "CSPSession: MaxParserSize=%d" ), iSettings.MaximumParserSize() );
    CImpsClientLogger::Log( _L( "CSPSession: MaxMessageSize=%d" ), iSettings.MaximumMessageSize() );
#endif

    TImpsSDataUtils::CreateClientCapabilityReqL(
        &myAccess,
        iCSPSessionId,
        iTempTid2,
        iLogCID,
        iMultiTrans,
        iPollTime,
        iSettings );
    // Put Client Capability request into queue to wait sending
    // Do not copy but add this instance.
    // Negotiation phase expiry time is saved in iNegoExpiry so does not
    // matter what we set here.
    iMsg = EImpsClientCapabilityReq;
    QueueClientRequestL( tempFields, 0, EFalse );
    SendAllQueued();
    CleanupStack::Pop( 1 ); // tempFields  >>>
    iNegoExpiry = iServer.ExpiryTime( EImpsEventServerLogin );
    NewState( EImpsCSPNegotiation );
    }

// -----------------------------------------------------------------------------
// CImpsCSPSession::DoSendServiceNegotiationReqL
// -----------------------------------------------------------------------------
void CImpsCSPSession::DoSendServiceNegotiationReqL()
    {
    iMsg = EImpsServiceReq;
    CImpsFields* tempFields = CImpsFields::NewL();
    CleanupStack::PushL( tempFields );      // <<< tempfields
    tempFields->SetMessageType( EImpsServiceReq );
    tempFields->SetSessionTypeL( EImpsInband );
    iTempTid2 = GenerateTid();
    TImpsDataAccessor myAcc( tempFields );

    // Initialize the iServices again (in case of re-login)
    TImpsSrvUtils::InitializeServices( iServices, iReactive );
    TImpsSDataUtils::CreateServiceRequestL(
        &myAcc,
        iServices,
        iCSPSessionId,
        iTempTid2,
        iLogCID,
        iReactive );

    // Put Service Negotiation request into queue to wait sending.
    // Negotiation phase expiry time is saved in iNegoExpiry so does not
    // matter what we set here.
    QueueClientRequestL( tempFields, 0, EFalse );
    SendAllQueued();
    CleanupStack::Pop( 1 );         // >>> tempFields
    iNegoExpiry = iServer.ExpiryTime( EImpsEventServerLogin );
    NewState( EImpsCSPNegotiation );
    }

// -----------------------------------------------------------------------------
// CImpsCSPSession::HandleLoginResponseL
// -----------------------------------------------------------------------------
void CImpsCSPSession::HandleLoginResponseL ( CImpsFields* aFields )
    {
    // protect us against illegal data from SAP
    TImpsDataAccessor myAc( aFields );

    TPtrC newId;
    TImpsSDataUtils::GetLoginSessionIDL( &myAc, newId );
    if ( newId.Length() > KImpsMaxSID )
        {
        User::Leave( KErrCorrupt );
        }
    iCSPSessionId = newId;

    TDesC8* nonce = NULL;
    CImpsKey* myKey = CImpsKey::NewLC();
    myKey->AddL( EImpsKeySession );
    myKey->AddL( EImpsKeyTransaction );
    myKey->AddL( EImpsKeyTransactionContent );
    myKey->AddL( EImpsKeyLogin_Response );
    myKey->AddL( EImpsKeyDigestSchema );
    TInt schema;
    TBool sendPwd = myAc.RestoreIntegerL( myKey, schema );
    if ( sendPwd )
        {
        if ( schema == EImpsPWD )
            {
            // Now we have to send the PWD
            sendPwd = ETrue;
            }
        else
            sendPwd = EFalse;
        }
    myKey->PopL();
    myKey->AddL( EImpsKeyNonce );
    ( void )myAc.RestoreDesc8L( myKey, nonce );
    TInt newTime( 0 );
    if ( TImpsSDataUtils::GetKeepAliveL( &myAc, newTime ) )
        {
        iAliveTime = newTime;
        }

    TImpsSDataUtils::SetResultStatusL( myKey, &myAc, KImpsStatusOk );

    CleanupStack::PopAndDestroy( 1 );
    CImpsFields* tempFields = CImpsFields::NewL();
    CleanupStack::PushL( tempFields );
    tempFields->SetMessageType( EImpsLoginReq );
    iTempTid2 = LogTid();

    TImpsDataAccessor myAcc( tempFields );

    TImpsSDataUtils::CreateLoginReqPhaseTwoL(
        sendPwd,
        &myAcc,
        iCSPSessionId,
        LogTid(),
        UserId(),
        iLogCID,
        LogPwd(),
        nonce,
        iCookie,
        iAliveTime,
        iKey1,
        iKey2 );

    iMsg = EImpsMessageNone;

    // Send 2nd login phase request
    // Login expiry time is saved in iNegoExpiry so no need to calculate it here.
    QueueClientRequestL( tempFields, 0, EFalse );
    SendAllQueued();

    CleanupStack::Pop( 1 );
    delete iKey1; // not needed anymore
    iKey1 = NULL;
    delete iKey2; // not needed anymore
    iKey2 = NULL;
    }

// -----------------------------------------------------------------------------
// CImpsCSPSession::HandleClientCapabilityResL
// -----------------------------------------------------------------------------
void CImpsCSPSession::HandleClientCapabilityResL ( CImpsFields* aFields )
    {
    iTempTid2 = KNullDesC;

    TImpsDataAccessor myAccess( aFields );
    CImpsKey* myKey = CImpsKey::NewLC();   // <<< myKey

    const TImpsContent* myContent = KClientCapabilityResElements;
    TImpsSDataUtils::AddValuesFromArrayL(
        myKey,
        myContent,
        sizeof( KClientCapabilityResElements ) /
        sizeof( KClientCapabilityResElements[0] ) );


    // WV CSP versions are not fully compatible
    if ( iCSPVersion == EImpsCspVersion11 )
        {
        // WV 1.1 code
        // CapabilityList element
        myKey->AddL( CREATEKEY( EImpsKeyCapabilityList, 0 ) );

        // We are interested in supported CIR methods, TCP/IP CIR addresses
        // and polltime.
        // SupportedBearer is ignored because of we support HTTP only.´
        // WV 1.1 specific ClientID is ignored too.
        // AcceptedContentType not in a response based on
        // Corrigenda Catalog for WV ver 1.1
        }
    else
        {
        // WV 1.2 code
        // AgreedCapabilityList element
        myKey->AddL( CREATEKEY( EImpsKeyAgreedCapabilityList, 0 ) );

        // We are interested in supported CIR methods, TCP/IP CIR addresses
        // and polltime.
        // SupportedBearer is ignored because of we support HTTP only.
        // CIRURL is ignored too because of it is for HTTP CIR binding only
        // that is not supported by this sw.
        // <!ELEMENT AgreedCapabilityList
        //   (SupportedBearer*, SupportedCIRMethod*, TCPAddress?, TCPPort?,
        //   ServerPollMin?, CIRURL?)>
        }

    // ServerPollMin
    myKey->AddL( CREATEKEY( EImpsKeyServerPollMin, 0 ) );
    TInt myInt;
    if ( myAccess.RestoreIntegerL( myKey, myInt ) )
        {
        if ( myInt > iPollTime )
            {
            iPollTime = myInt;
            }
        }
    // Save new minimum polling time value in settings
    iSettings.iPollTime = iPollTime;

    // Reset polling timer, ServerPollMin is optional, but if we do not get
    // new value then we start to us our own suggestion
    iPollState = EImpsPollAdaptive;
#ifndef _NO_IMPS_LOGGING_
    CImpsClientLogger::Log( _L( "CSPSession: PollTime %d" ), iPollTime );
    CImpsClientLogger::Log( _L( "CSPSession: iPollState %d" ), iPollState );
#endif
    iIdleTimer->Start( iPollTime );

    // MultiTrans response
    myKey->ReplaceLastL( CREATEKEY( EImpsKeyMultiTrans, 0 ) );
    if ( myAccess.RestoreIntegerL( myKey, myInt ) )
        {
        iMultiTrans = myInt;
#ifndef _NO_IMPS_LOGGING_
        CImpsClientLogger::Log( _L( "CSPSession: new iMultiTrans %d" ), iMultiTrans );
#endif
        }

    myKey->PopL();

    // SupportedCIRMethod update
    iSettings.SetCirBindingsL( &myAccess, myKey );

    // TCPAddress
    TDesC* myPtr;
    myKey->AddL( CREATEKEY( EImpsKeyTCPAddress, 0 ) );
    if ( myAccess.RestoreDescL( myKey, myPtr ) )
        {
        HBufC* newAttrib = myPtr->AllocL();
        delete iTCPAddr;
        iTCPAddr = newAttrib;
        }

    // TCPPort
    myKey->ReplaceLastL( CREATEKEY( EImpsKeyTCPPort, 0 ) );
    if ( myAccess.RestoreIntegerL( myKey, myInt ) )
        {
        iTCPPort = ( TUint )myInt;
        }

    CleanupStack::PopAndDestroy( 1 );   // >>> mKey
    }

// -----------------------------------------------------------------------------
// CImpsCSPSession::SendPollL
// -----------------------------------------------------------------------------
void CImpsCSPSession::SendPollL()
    {
#ifndef _NO_IMPS_LOGGING_
    CImpsClientLogger::Log( _L( "CSPSession: SendPollL csp=%d" ), ( TInt )this );
#endif

    TInt orig = iPollInResume;
    iPollInResume = 0;

    if ( iIntStatus != EInternal_ON_LINE || IsPDPIdle() )
        {
#ifndef _NO_IMPS_LOGGING_
        CImpsClientLogger::Log( _L( "CSPSession: SendPollL IGNORED" ) );
#endif
        iPollInResume = 2;
        User::Leave( KErrNotReady );
        }

    // Create Poll request
    iSnd->Reset();
    iSnd->SetSessionTypeL( EImpsInband );
    iSnd->SetMessageType( EImpsPolling );
    iSnd->SetSessionIdL( iCSPSessionId );
    CImpsDataAccessor* myAccess = CImpsDataAccessor::NewLC( iSnd ); // <<<
    CImpsKey* myKey = CImpsKey::NewLC(); // <<<
    // Add TImpsTransactionMode now
    myKey->Reset();
    TImpsSDataUtils::AddValuesFromArrayL(
        myKey,
        KTransModeElements,
        sizeof( KTransModeElements ) /
        sizeof( KTransModeElements[0] ) );
    myAccess->StoreIntegerL( myKey, EImpsRequest );
    myKey->Reset();
    TImpsSDataUtils::AddValuesFromArrayL(
        myKey,
        KTransContentElements,
        sizeof( KTransContentElements ) /
        sizeof( KTransContentElements[0] ) );
    myKey->AddL( CREATEKEY( EImpsKeyPolling_Request, 0 ) );
    myAccess->StoreEmptyL( myKey );

    // Send
    iTempTid = KNullDesC;
    iSnd->SetTidL( iTempTid );

    iPollWasRequested = EFalse;
#ifndef _NO_IMPS_LOGGING_
    CImpsClientLogger::Log( _L( "CSPSession: iPollWasRequested->F in SendPollL" ) );
#endif

    if ( orig >= 1 )
        {
        iPollInResume = 2;
        }
    DoSendSingleL( myAccess, iTempTid, EImpsPolling, KImpsPollTO );
    iPollInResume = 0;

    CleanupStack::PopAndDestroy( 2 );   // >> myKey, myAccess
    }


// -----------------------------------------------------------------------------
// CImpsCSPSession::SendAliveL
// -----------------------------------------------------------------------------
TPtrC CImpsCSPSession::SendAliveL( )
    {
    return DoSendAliveL();
    }

// -----------------------------------------------------------------------------
// CImpsCSPSession::SendAliveInResume
// -----------------------------------------------------------------------------
void CImpsCSPSession::SendAliveInResume( )
    {
#ifndef _NO_IMPS_LOGGING_
    CImpsClientLogger::Log( _L( "CSPSession: SendAliveInResume iPendingAlive->T" ) );
#endif
    iPendingAlive = ETrue;
    }

// -----------------------------------------------------------------------------
// CImpsCSPSession::DoSendAliveL
// -----------------------------------------------------------------------------
TPtrC CImpsCSPSession::DoSendAliveL( )
    {
#ifndef _NO_IMPS_LOGGING_
    CImpsClientLogger::Log( _L( "CSPSession: DoSendAliveL csp=%d" ), ( TInt )this );
#endif

    // send poll request. Do not update Transaction queue
    iSnd->Reset();
    iSnd->SetSessionTypeL( EImpsInband );
    iSnd->SetMessageType( EImpsKeepAliveReq );
    iSnd->SetSessionIdL( iCSPSessionId );

    // Set TID
    TPtrC tid;
    tid.Set( GenerateTid() );
    iSnd->SetTidL( tid );

    // Add KeepAlive
    CImpsDataAccessor* myAc = CImpsDataAccessor::NewLC( iSnd ); // <<< myAc
    CImpsKey* myk = CImpsKey::NewLC();    // <<< myk
    TImpsSDataUtils::AddValuesFromArrayL(
        myk,
        KKeepAliveReq,
        sizeof( KKeepAliveReq ) /
        sizeof( KKeepAliveReq[0] ) );
    myAc->StoreEmptyL( myk );
    // Add Transaction mode
    myk->Reset();
    TImpsSDataUtils::AddValuesFromArrayL(
        myk,
        KTransModeElements,
        sizeof( KTransModeElements ) /
        sizeof( KTransModeElements[0] ) );
    myAc->StoreIntegerL( myk, EImpsRequest );

    if ( IsPDPIdle() )  // PDP idle-> start to open
        {
        iPendingAlive = ETrue;
#ifndef _NO_IMPS_LOGGING_
        CImpsClientLogger::Log( _L( "CSPSession: iPendingAlive->T" ) );
#endif
        if ( iCSPState == EImpsCSPOnLineIdle )
            {
            OpenPDP();
            }
        else if ( iCSPState == EImpsCSPOnLineIdleStart )
            {
            iPendingPDP = EImpsPDPPendOpen;
            }
#ifndef _NO_IMPS_LOGGING_
        CImpsClientLogger::Log( _L( "CSPSession: DoSendAliveL POSTPONED ***" ) );
#endif
        }
    else if ( iIntStatus != EInternal_ON_LINE )
        {
#ifndef _NO_IMPS_LOGGING_
        CImpsClientLogger::Log( _L( "CSPSession: DoSendAliveL IGNORED" ) );
#endif
        iSnd->Reset();
        User::Leave( KImpsGeneralError );
        }
    else
        {
        DoSendSingleL( myAc, iTempTid, EImpsKeepAliveReq, KImpsKeepATO );
        iPendingAlive = EFalse;
#ifndef _NO_IMPS_LOGGING_
        CImpsClientLogger::Log( _L( "CSPSession: iPendingAlive->F" ) );
#endif
        }

    CleanupStack::PopAndDestroy( 2 );   // >>> myk myAc

    return iTempTid;
    }


// -----------------------------------------------------------------------------
// CImpsCSPSession::SendAllQueued
// -----------------------------------------------------------------------------
void CImpsCSPSession::SendAllQueued()
    {
    // Actually this does not send all messages at once but one by one.
    // iSendQ calls DoSendAllQueued that calls (in most cases)
    // this again and so on until no more valid messages found!
    // DoSendAllQueued handles SAP initiated requests in same way.
    if ( RequestExist() || SapReqExist() || iPendingAlive ||
         iPollState == EImpsPollExtWait || iPollInResume == 1 ||
         iPollWasRequested )
        {
        if ( !IsPDPIdle() )
            {
            iSendQ->Send();
            }
        else if ( iCSPState == EImpsCSPOnLineIdle )
            {
            iPollState = EImpsPollCIR;
#ifndef _NO_IMPS_LOGGING_
            CImpsClientLogger::Log( _L( "CSPSession: iPollState %d" ), iPollState );
#endif
            }
        }
    }

// -----------------------------------------------------------------------------
// CImpsCSPSession::CreateSapResponse
// -----------------------------------------------------------------------------
TImpsSAPResStatus CImpsCSPSession::CreateSapResponse()
    {
#ifndef _NO_IMPS_LOGGING_
    CImpsClientLogger::Log( _L( "CSPSession: CreateSapResponse begins csp=%d" ), ( TInt )this );
#endif

    TImpsSAPResStatus ret( EImpsSAPNone );
    TInt err = KErrNone;
    // Check if pending SAP initiated CSP transactions exists
    TDblQueIter<CTransaction> iter2 ( iTransactionList );
    iter2.SetToFirst();
    if ( iter2 )
        {
        ret = EImpsSAPMore;
        CTransaction* trans = iter2;
        // Get first
        iter2++;
        CImpsFields* fields = trans->iFields;
        TInt messageType = fields->MessageType();

        // Try to get actual message type
        if ( messageType == EImpsPureData )
            {
            TRAP( err, TImpsDataAccessor temp ( fields );
                  messageType = TImpsSDataUtils::GetPureMessageTypeL( &temp ) );
            }

#ifndef _NO_IMPS_LOGGING_
        CImpsClientLogger::Log( _L( "CSPSession: CreateSapResponse messageType=%x" ), messageType );
#endif
        // Here we have a list of supported push messages, i.e.
        // SAP initiated transactions.
        // Other pushed messages are not supported!
        // Notice: add new methods as needed
        // Disconnect is a special case handled before this method call
        if ( messageType == EImpsNewMessage ||
             messageType == EImpsLeaveGroupRes ||
             messageType == EImpsInviteUserReq ||
             messageType == EImpsInviteRes ||
             messageType == EImpsCancelInviteUserReq ||
             messageType == EImpsPresenceNotification ||
             messageType == EImpsGroupChangeNotice ||
             messageType == EImpsPresenceAuthReq ||
             messageType == EImpsDeliveryReportReq
           )
            {
            // This also tries to send a SAP initiated transaction response once immediately
            TRAP( err, DoMakeSapResponseL( trans ) );
            if ( !err )
                {
                iPollInResume = 0;
                }
            // Last request handled.
            if ( !iter2 )
                {
                ret = EImpsSAPLast;
                iPollInResume = 0;

                // All the WV servers do not work according to WV specs and they seems to need
                // to get a Poll request instead for SAP initiated transactions, therefore the
                // extra polling is needed.
                err = KErrNone;
                TBool polli ( EFalse );
                TRAP( err, polli = fields->PollL() )
                if ( polli )
                    {
                    iPollWasRequested = ETrue;
#ifndef _NO_IMPS_LOGGING_
                    CImpsClientLogger::Log( _L( "CSPSession: iPollWasRequested->T in CreateSapResponse" ) );
#endif
                    }
                }

#ifndef _NO_IMPS_LOGGING_
            if ( err )
                {
                CImpsClientLogger::Log( _L( "CSPSession: DoMakeSapResponseL ERROR %d" ), err );
                }

#endif
            }

        // Transaction is deleted. If the response has failed the WV server should send
        // the transaction again. Timer limit is not implemented in terminal side here.
        trans->Destroy();

        } // if (iter2)
#ifndef _NO_IMPS_LOGGING_
    CImpsClientLogger::Log( _L( "CSPSession: CreateSapResponse returns %d" ), ret );
#endif
    return ret;
    }

// -----------------------------------------------------------------------------
// CImpsCSPSession::DoSendAllQueuedL
// -----------------------------------------------------------------------------
void CImpsCSPSession::DoSendAllQueuedL()
    {

    TInt errx = KErrNone;

    // Handle login phase specials first
    // ---------------------------------
    if ( iLoginPhase != 2 )
        {
        if ( !IsLogged() || !iReceiver2->isConnected() ||
             ( iReceiver2->NbrOfPending() >= KImpsMaxPending ) ||
             IsPDPIdle() ) // no reason to try if PDP is not open
            {
#ifndef _NO_IMPS_LOGGING_
            CImpsClientLogger::Log( _L( "CSPSession: DoSendAllQueuedL IGNORED" ) );
#endif
            return;
            }
        }

    // Pending Alive messages and pending Poll messages
    // -------------------------------------------------
    if ( iPendingAlive )
        {
        // Pending Alive overrides pending Poll
        iPendingAlive = EFalse;
#ifndef _NO_IMPS_LOGGING_
        CImpsClientLogger::Log( _L( "CSPSession: iPendingAlive->F" ) );
#endif
        iPollInResume = 0;
        iAliveMgr->SendKeepAlive( EFalse );
        SendAllQueued();
        return;
        }
    else if ( iPollState == EImpsPollExtWait )
        {
        iPollState = EImpsPollCIR;
        iPollTime = iSettings.CIRModePollTime();
        iIdleTimer->Start( iPollTime );
#ifndef _NO_IMPS_LOGGING_
        CImpsClientLogger::Log( _L( "CSPSession: iPollState %d" ), iPollState );
        CImpsClientLogger::Log( _L( "CSPSession: iPollTime %d" ), iPollTime );
#endif
        errx = KErrNone;
        TRAP( errx, SendPollL() );
        // If Polling fails then try again
        if ( errx && !iPollInResume )
            {
            iPollInResume = 1;
#ifndef _NO_IMPS_LOGGING_
            CImpsClientLogger::Log( _L( "CSPSession: iPollInResume %d" ), iPollInResume );
#endif
            }

        SendAllQueued();
        return;
        }

    // Reqular cases
    // --------------------------
    CReq* request = NULL;

    if ( iTr < iMultiTrans )
        {
        // Try to send terminal initiated request
        request = GiveNextRequestL();

        // Block messages in negotiation phase
        if ( request && request->iFields )
            {
            TInt msgType = request->iFields->MessageType();
            if ( iIntStatus != EInternal_ON_LINE &&
                 ( msgType != EImpsKeepAliveReq &&
                   msgType != EImpsClientCapabilityReq &&
                   msgType != EImpsServiceReq &&
                   msgType != EImpsLoginReq &&
                   msgType != EImpsLogoutReq ) )

                {
                request = NULL;
                }
            }

        if ( request )
            {
            iPollInResume = 0;
            // Send next buffered user request if any
            // search. Not immediately, but via active object scheduler
            SendAllQueued();

            CImpsFields* fields = request->iFields;
            errx = KErrNone;
            TRAP( errx, DoSendNextBufferedL( fields ) );
            // Delete the client request
            request->Destroy();
            } // if request
        }

    if ( !request )
        {
        // Check if SAP initiated message instead of terminal initiated one.
        // This sends data and calls SendAllQueued if needed.
        // comment: SAP responses should not exists in PDP-idle state

        // CreateSapResponse not only create the response but also tries to send it..
        TImpsSAPResStatus sapr = CreateSapResponse();
        if ( ( sapr != EImpsSAPMore ) &&
             ( iPollWasRequested || iPollInResume == 1 ) &&
             ( IsLogged() ) )
            {
            errx = KErrNone;
            // If Poll fails then re-try polling when GPRS resumes
            TRAP( errx, SendPollL() );
            if ( errx && !iPollInResume )
                {
                iPollInResume = 1;
#ifndef _NO_IMPS_LOGGING_
                CImpsClientLogger::Log( _L( "CSPSession: err: iPollInResume %d" ), iPollInResume );
#endif
                }
            }
        else if ( sapr == EImpsSAPMore )
            {
            SendAllQueued();
            }
        }
    }

// -----------------------------------------------------------------------------
// CImpsCSPSession::CancelTrans
// client subsession calls this when request expires
// -----------------------------------------------------------------------------
void CImpsCSPSession::CancelTrans( const TDesC& aTID )
    {
    DeleteRequest( aTID );
    // CancelTrans does not cause callback.
    iReceiver2->CancelTrans( aTID );
    TrMinus();
    // Check if login-req expires and change CSP state
    if ( iCSPState == EImpsCSPLogging && !aTID.Compare( LogTid() ) )
        {
        NewState( EImpsCSPIdle );
        CancelData();
        }

    SendAllQueued();
    }

// -----------------------------------------------------------------------------
// CImpsCSPSession::GenerateTid
// -----------------------------------------------------------------------------
TPtrC CImpsCSPSession::GenerateTid( )
    {
    // iCounter++;
    // TInt tidNbr = iCounter;
    TInt tidNbr = iServer.TidSeed();
    iTempTid = KNullDesC;
    iTempTid = _L( "nok" );
    iTempTid.AppendFormat( _L( "%d" ), tidNbr  );
    return iTempTid;
    }

// -----------------------------------------------------------------------------
// CImpsCSPSession::GenerateCookie
// -----------------------------------------------------------------------------
TPtrC CImpsCSPSession::GenerateCookie( )
    {
    TTime myTime;
    myTime.HomeTime();
    const TInt64& seed = myTime.Int64();
    TUint low = I64LOW( seed );
    TUint high = I64HIGH( seed );
    TInt64 seed2 MAKE_TINT64( high, low );
    iCookie = KNullDesC;
    iCookie = _L( "wv:nokia." );
#ifndef _FAKE_RESPONSE
    TInt tidNbr = Math::Rand( seed2 );
    iCookie.AppendFormat( _L( "%d" ), tidNbr  );
#else
    iCookie.AppendFormat( _L( "%d" ), 12345  );
#endif
    // copy to 8-bit buffer for CIR
    iCookie8.Copy( iCookie );
    return iCookie;
    }

// -----------------------------------------------------------------------------
// CImpsCSPSession::DoLogout
// -----------------------------------------------------------------------------
void CImpsCSPSession::DoLogout( )
    {

#ifndef _NO_IMPS_LOGGING_
    CImpsClientLogger::Log( _L( "CSPSession: DoLogout" ) );
#endif
    DoLogoutNow( 0 );
    }

// -----------------------------------------------------------------------------
// CImpsCSPSession::DoLogoutNow
// -----------------------------------------------------------------------------
void CImpsCSPSession::DoLogoutNow( TInt aOpId )
    {
#ifndef _NO_IMPS_LOGGING_
    CImpsClientLogger::Log( _L( "CSPSession: DoLogoutNow opid=%d, log=%d csp=%d" ),
                            aOpId, IsLogged(), ( TInt )this );
#endif

    // save old status for this method
    TBool oldLogged = IsLogged();
    TImpsCSPState oldState = iCSPState;
    NewState( EImpsCSPIdle );

    iAliveMgr->StopTimer();
    iIdleTimer->Stop();
    // stop PDP idle timer in logout routines
    iPDPIdleTimer->Stop( );
    iPDPOpenTimer->Stop( );
    iPollState = EImpsPollNone;
    iPendingPDP = EImpsPDPPendNone;
    iPendPDPLogout = EFalse;
    iPollWasRequested = EFalse;
#ifndef _NO_IMPS_LOGGING_
    CImpsClientLogger::Log( _L( "CSPSession: iPollState %d  iPollWasRequested->F in logout" ), iPollState );
#endif

    // Reset settings for further logins
    ResetSession();

    iSendQ->Cancel();

    // Reset local variables
    iIntStatus = EInternal_NOT_LOGGED;

#ifndef _NO_IMPS_LOGGING_
    CImpsClientLogger::Log( _L( "CSPSession: status NOT_LOGGED" ) );
#endif

    // Clean own queues
    DeleteRequests();
    DeleteTransactions();
    iTidSapHistory->DeleteAll();
    iTidCliHistory->DeleteAll();

    // Close ip cir
#ifndef _NO_IMPS_LOGGING_
    CImpsClientLogger::Log( _L( "CSPSession: CLOSE IP-CIR CHANNEL" ) );
#endif
    if ( iCirManager )
        {
        // Close all cir bindings
        iCirManager->CloseCh( 0xF );
        }

    // Cancel the HTTP transport in logout
#ifndef _NO_IMPS_LOGGING_
    CImpsClientLogger::Log( _L( "CSPSession: CANCEL TRANSPORT IN DOLOGOUT" ) );
#endif
    CancelData();

    // Clean server core and send logout and status events there.
    // We first detect if this is really CSP disconnect situation.
    TBool cspDisconnect = ( oldLogged || oldState == EImpsCSPDisconnecting ) ?
                          ETrue : EFalse ;
    iServer.DoLogoutSrv( aOpId, cspDisconnect, this );

    delete iSAP;
    iSAP = NULL;
    iIAP = 0;

#ifndef _NO_IMPS_LOGGING_
    CImpsClientLogger::Log( _L( "CSPSession: CLOSE TRANSPORT SOON..." ) );
#endif
    if ( iReceiver2->Close2() == KErrCancel )
        {
        // Start to delete this session asynchronously
        // if there is nothing to close.
        iServer.TransportStatus(  EInternal_NO_IAP, this );
        }
    }

// -----------------------------------------------------------------------------
// CImpsCSPSession::CancelData
// server CloseSession calls this
// -----------------------------------------------------------------------------
void CImpsCSPSession::CancelData( )
    {

#ifndef _NO_IMPS_LOGGING_
    CImpsClientLogger::Log( _L( "CSPSession: CancelData csp=%d" ), ( TInt )this );
#endif
    // Cancel the HTTP transport now, no callback
    iReceiver2->Cancel();
    // Must reset variables because if new Login request mey be
    // received before WV Engine is shut down and CloseEngine() called.
    }

// -----------------------------------------------------------------------------
// CImpsCSPSession::QueueClientRequestL
// -----------------------------------------------------------------------------
void CImpsCSPSession::QueueClientRequestL(
    CImpsFields* aFields,
    TInt aExpiry,
    TBool aLast )
    {
    // Check if subsession specific expiry time needed
    CReq* req = new ( ELeave ) CReq( aFields );
    if ( !aExpiry )
        {
        req->iExpiry = iServer.ExpiryTime( ( TImpsMessageType ) aFields->MessageType() );
        }
    else
        {
        req->iExpiry = iServer.ExpiryTime( aExpiry );
        }

    // Put request into queue in a right place,
    if ( aLast )
        {
        iRequestList.AddLast( *req );
        }
    else
        {
        iRequestList.AddFirst( *req );
        }
    }

// -----------------------------------------------------------------------------
// CImpsCSPSession::QueueTidL
// This resets iRcv!
// -----------------------------------------------------------------------------
void CImpsCSPSession::QueueTidL( TBool aOrphan )
    {

    if ( !ValidateTid( EFalse ) )
        {
        // TID is already responded to SAP
        return;
        }

    TPtrC tid;
    TImpsDataAccessor myAccess( iRcv );
    TImpsDataUtils::GetTransactionIDL( &myAccess, tid );

    if ( tid.Length() > 0 )
        {

        // Add new Sap initiated transaction to queue
        CTransaction* trans = new ( ELeave ) CTransaction(
            aOrphan,
            tid,                    // tid
            iRcv->SessionIdL(),     // session-id
            ( TImpsMessageType ) iRcv->MessageType(),
            iRcv );

#ifndef _NO_IMPS_LOGGING_
        CImpsClientLogger::Log( _L( "CSPSession: QUEUE SAP TID=%S csp=%d" ),
                                &( trans->iTID ), ( TInt )this ); //lint !e525
#endif

        iTransactionList.AddLast( *trans );
        iRcv = NULL;
        iRcv = CImpsFields::NewL();
        iRcv->Reset();
        }
    }

// -----------------------------------------------------------------------------
// CImpsCSPSession::ValidateTid
// Validate SAP initiated TID
// -----------------------------------------------------------------------------
TBool CImpsCSPSession::ValidateTid( TBool aClientHistory )
    {

    // The requesting entity may resend the request message using the same
    // transaction identifier. The responding entity should
    // guarantee that the requested operation or data is carried out only once,
    // even if multiple request messages with the same transaction identifier
    // are received.

    // Check that TID has not already sent to clients or has not responded to SAP.

    TPtrC tid;
    TImpsDataAccessor myAccess( iRcv );
    TInt errx = KErrNone;
    TRAP( errx, TImpsDataUtils::GetTransactionIDL( &myAccess, tid ) );

    if ( tid.Length() > 0 )
        {
        if ( aClientHistory && iTidCliHistory->TidFound( tid ) )
            {
            // TID has sent to clients
#ifndef _NO_IMPS_LOGGING_
            CImpsClientLogger::Log( _L( "CSPSession: already received TID=%S ***" ), &tid );
#endif
            return EFalse;
            }
        else if ( aClientHistory /* && !iTidCliHistory->TidFound( tid )*/ )
            {
            // Save TId into client history
            iTidCliHistory->Add( tid );
            }
        else if ( !aClientHistory && iTidSapHistory->TidFound( tid ) )
            {
            // TID has already responded to SAP
            // TID-SAP-history has been updated when the transport response is sent
            // successfully to SAP (i.e. no transport error)
#ifndef _NO_IMPS_LOGGING_
            CImpsClientLogger::Log( _L( "CSPSession: already responded TID=%S ***" ), &tid );
#endif
            return EFalse;
            }
        }
    return ETrue;
    }

// -----------------------------------------------------------------------------
// CImpsCSPSession::DiscardTid
// -----------------------------------------------------------------------------
void CImpsCSPSession::DiscardTid( const TDesC& aTid )
    {
    // Delete buffered transaction
    TDblQueIter<CTransaction> rIter( iTransactionList );
    rIter.SetToFirst();
    while ( rIter )
        {
        CTransaction* trans = rIter;
        rIter++;
        if ( !trans->iTID.Compare( aTid ) )
            {
#ifndef _NO_IMPS_LOGGING_
            CImpsClientLogger::Log( _L( "CSPSession: DiscardTid deletes a request " ) );
#endif
            trans->Destroy();
            return;
            }
        }
    }

// -----------------------------------------------------------------------------
// CImpsCSPSession::DeleteTransactions
// -----------------------------------------------------------------------------
void CImpsCSPSession::DeleteTransactions()
    {
    // Delete all buffered transactions
    TDblQueIter<CTransaction> rIter( iTransactionList );

    rIter.SetToFirst();

    while ( rIter )
        {
        CTransaction* trans = rIter;
        rIter++;
        trans->Destroy();
        }
    }

// -----------------------------------------------------------------------------
// CImpsCSPSession::DeleteRequests
// -----------------------------------------------------------------------------
void CImpsCSPSession::DeleteRequests()
    {
#ifndef _NO_IMPS_LOGGING_
    CImpsClientLogger::Log( _L( "CSPSession: DeleteRequests csp=%d" ), ( TInt )this );
#endif
    // Delete all buffered transaction requests
    TDblQueIter<CReq> rIter( iRequestList );
    rIter.SetToFirst();

    while ( rIter )
        {
        CReq* req = rIter;
        rIter++;
        req->Destroy();
        }
    }

// -----------------------------------------------------------------------------
// CImpsCSPSession::DeleteRequest
// -----------------------------------------------------------------------------
void CImpsCSPSession::DeleteRequest( const TDesC& aTID )
    {
#ifndef _NO_IMPS_LOGGING_
    CImpsClientLogger::Log( _L( "CSPSession: DeleteRequest tid=%S csp=%d" ), &aTID, ( TInt )this );
#endif
    // Delete buffered transaction request
    TInt errx = KErrNone;
    TPtrC p( KNullDesC );

    TDblQueIter<CReq> rIter( iRequestList );
    rIter.SetToFirst();

    while ( rIter )
        {
        CReq* req = rIter;
        rIter++;
        TRAP( errx, p.Set( req->iFields->TidL() ) );
        if ( !p.Compare( aTID ) )
            {
#ifndef _NO_IMPS_LOGGING_
            CImpsClientLogger::Log( _L( "CSPSession: DeleteRequest MATCH tid=%S csp=%d" ), &aTID, ( TInt )this );
#endif
            req->Destroy();

            }
        }
    }

// -----------------------------------------------------------------------------
// CImpsCSPSession::RequestExist
// -----------------------------------------------------------------------------
TBool CImpsCSPSession::RequestExist()
    {
    // Check buffered transactions
    TDblQueIter<CReq> rIter( iRequestList );

    rIter.SetToFirst();

    if ( rIter )
        {
        return ETrue;
        }
    return EFalse;
    }

// -----------------------------------------------------------------------------
// CImpsCSPSession::SapReqExist
// -----------------------------------------------------------------------------
TBool CImpsCSPSession::SapReqExist()
    {
    TDblQueIter<CTransaction> iter2 ( iTransactionList );
    iter2.SetToFirst();
    if ( iter2 )
        {
        return ETrue;
        }
    return EFalse;
    }

// -----------------------------------------------------------------------------
// CImpsCSPSession::DoSendNextBufferedL
// -----------------------------------------------------------------------------
void CImpsCSPSession::DoSendNextBufferedL( CImpsFields* aFields )
    {
    TImpsDataAccessor myAccess( aFields );
    TRAPD( err, DoSendSingleL( &myAccess, aFields->TidL(),
                               ( TImpsMessageType )aFields->MessageType() ) );
    if ( err )
        {
        //  send an error event
#ifndef _NO_IMPS_LOGGING_
        CImpsClientLogger::Log( _L( "CSPSession: DoSendSingleL ERROR=%d csp=%d" ), err, ( TInt )this );
#endif
        iSnd->Reset();
        iSnd->SetStatus( err );
        iSnd->SetTidL( aFields->TidL() );
        TBool someFound;
        // This sends error event to the right client session
        TImpsSessIdent csp( iCSPSessionId, DoSAP(), DoUserId() );
        iServer.CheckRequestsL( iSnd, someFound, csp );
        }
    }

// ---------------------------------------------------------
// CImpsCSPSession::TransportStatus
// ---------------------------------------------------------
//
void CImpsCSPSession::TransportStatus(
    EImpsInternalStatus aConnectionState )
    {

#ifndef _NO_IMPS_LOGGING_
    CImpsClientLogger::Log( _L( "CSPSession: TransportStatus=%d old=%d state=%d csp=%d" ),
                            ( TInt ) aConnectionState, iIntStatus, iCSPState, ( TInt )this );
#endif

    TInt errx = KErrNone;
    TRAP( errx, DoTransportStatusL ( aConnectionState ) );

#ifndef _NO_IMPS_LOGGING_
    CImpsClientLogger::Log( _L( "CSPSession: TransportStatus ends" ) );
#endif

    }

// ---------------------------------------------------------
// CImpsCSPSession::DoTransportStatusL
// ---------------------------------------------------------
//
void CImpsCSPSession::DoTransportStatusL(
    EImpsInternalStatus aConnectionState )
    {
    TImpsSessIdent csp( iCSPSessionId, DoSAP(), DoUserId() );
    EImpsInternalStatus oldStatus = iIntStatus;

    // If there is pending logout request then the login is cancelled and
    // logout performed immediately.
    if ( iPendingLogout || iCancelLogin )
        {
#ifndef _NO_IMPS_LOGGING_
        CImpsClientLogger::Log( _L( "CSPSession: err: ex3 iPendingLogout->F *****" ) );
#endif
        iPendingLogout = EFalse;
        if ( iCSPState == EImpsCSPLogging )
            {
            // This sends first a login response
            iServer.DiscardRequest( LogTid(), EImpsEventServerLogin, KErrCancel, csp );
            // Special case where login is cancelled
            if ( aConnectionState == EInternal_NO_IAP )
                {
                iServer.DiscardLogout( LogoutTID(), csp );
                // below rest of activities are done
                }
            }
        }

    // *********************************************
    // PDP idle situations handled first
    if ( IsPDPIdle() )
        {
        if ( aConnectionState == EInternal_NO_IAP )
            {
            NewState( EImpsCSPOnLineIdle );
            // In a rare situation there is pending PDP open request
            // received when PDP is closing down.
            if ( iPendingPDP == EImpsPDPPendOpen )
                {
#ifndef _NO_IMPS_LOGGING_
                CImpsClientLogger::Log( _L( "CSPSession: iPendingLogout->F in NO_IAP ***" ) );
#endif
                iPendingPDP = EImpsPDPPendNone;
                OpenPDP();
                }
            return;
            }
        else if ( aConnectionState == EInternal_IAP_OPEN )
            {
            // PDP re-open completes here.
            NewState( EImpsCSPOnLine );
            if ( iPendingPDP == EImpsPDPPendOpen )
                {
                iPendingPDP = EImpsPDPPendNone;
                }
            // pending logout if PDP-context has been opened for Logout msg
            if ( iPendPDPLogout )
                {
                iPendPDPLogout = EFalse;
                iPendingPDP = EImpsPDPPendNone;
                TRAPD( errx, DoSendLogoutL( LogoutTID() ) );
                if ( errx )
                    {
                    // E5: Typically Bearer Suspended error with bad luck
#ifndef _NO_IMPS_LOGGING_
                    CImpsClientLogger::Log( _L( "CSPSession: err: E5 ****" ) );
#endif
                    DoLogout();
                    }
                }
            else
                {
                // Send all queued reqular requests to transport
#ifndef _NO_IMPS_LOGGING_
                CImpsClientLogger::Log( _L( "CSPSession: Normal PDP open ***" ) );
#endif
                iPollInResume = 1;
                // *********************************************************
                // Notice: we assume that GPRS is resumed in this case even
                // if ConnManager DLL cannot provide us such an information
                // in all cases.
                iIntStatus = EInternal_ON_LINE;
#ifndef _NO_IMPS_LOGGING_
                CImpsClientLogger::Log( _L( "CSPSession: status ON_LINE" ) );
#endif
                // start ip-cir-channels if not running
                TInt errxy = KErrNone;
                TRAP( errxy, DoStartIpCIRL() );
                }
            // Send all queued requests to transport
            SendAllQueued();
            }
        }

    // *********************************************
    // NO PDP IDLE STARTS HERE
    else if ( aConnectionState == EInternal_ON_LINE && IsNegotiated() )
        {
        iIntStatus = EInternal_ON_LINE;
        // we assume that old messages are in a bit heaven
        iTr = 0;
#ifndef _NO_IMPS_LOGGING_
        CImpsClientLogger::Log( _L( "CSPSession: status ON_LINE" ) );
#endif
        if ( iPollState == EImpsPollPending )
            {
            iPollState = EImpsPollExtWait;
#ifndef _NO_IMPS_LOGGING_
            CImpsClientLogger::Log( _L( "CSPSession: iPollState %d" ), iPollState );
#endif
            }

        // This makes poll to be sent if no other requests
        iPollInResume = 1;

        // pending logout if PDP-context has been opened for Logout msg
        if ( iPendPDPLogout )
            {
            iPendPDPLogout = EFalse;
            DoSendLogoutL( LogoutTID() );
            }
        else
            {
            SendAllQueued();
            // start ip-cir-channels if not running
            TInt errxy = KErrNone;
            TRAP( errxy, DoStartIpCIRL() );
            }
        }
    else if ( aConnectionState == EInternal_ON_LINE && !IsNegotiated() )
        {
        iIntStatus = EInternal_NOT_LOGGED;
#ifndef _NO_IMPS_LOGGING_
        CImpsClientLogger::Log( _L( "CSPSession: status NOT_LOGGED" ) );
#endif
        if ( IsLogged() )
            {
            // Rare situation where GPRS resume is taken place in negotiation phase.
            // iAliveMgr->SendKeepAlive( EFalse );
            SendAllQueued();
            }
        }
    else if ( aConnectionState == EInternal_OFF_LINE &&
              oldStatus == EInternal_ON_LINE )
        {
        iIntStatus = EInternal_OFF_LINE;
#ifndef _NO_IMPS_LOGGING_
        CImpsClientLogger::Log( _L( "CSPSession: status OFF_LINE" ) );
#endif
        }
    else if ( iCSPState == EImpsCSPLogging &&
              ( aConnectionState == EInternal_NO_IAP ||
                aConnectionState == EInternal_NO_IAP_AUTH ) )
        {
        // Discard request immediately in this case
        // This sends first a login response
#ifndef _NO_IMPS_LOGGING_
        CImpsClientLogger::Log( _L( "CSPSession: err: Login cancelled" ) );
#endif
        TImpsSessIdent csp( iCSPSessionId, DoSAP(), DoUserId() );
        iServer.DiscardRequest( LogTid(), EImpsEventServerLogin, KImpsErrorBearerSuspended, csp );
        DoLogout();
        }
    else if ( aConnectionState == EInternal_NO_IAP )
        {
        if ( IsNegotiated() )
            {
            // Check if no WAP SMS CIR negotiated then do logout.
            // Otherwise close PDP connection only
            if ( iSettings.iSMSWAPCIR == 2 )   // WAP CIR
                {
#ifndef _NO_IMPS_LOGGING_
                CImpsClientLogger::Log( _L( "CSPSession: err: PDP LOST SMS-CIR ***" ) );
#endif
                NewState( EImpsCSPOnLineIdle );
                if ( iPendingPDP == EImpsPDPPendClose )
                    {
                    iPendingPDP = EImpsPDPPendNone;
                    ClosePDP();
                    }
                return;
                }
            else  // no WAP CIR
                {
#ifndef _NO_IMPS_LOGGING_
                CImpsClientLogger::Log( _L( "CSPSession: err: PDP LOST NO-SMS-CIR ***" ) );
#endif
                DoLogout();
                }
            }
        else
            {
#ifndef _NO_IMPS_LOGGING_
            CImpsClientLogger::Log( _L( "CSPSession: err: PDP LOST NOT-NEGOTIATED ***" ) );
#endif
            if ( !IsLogged() )
                {
                iIntStatus = EInternal_NOT_LOGGED;
                // This causes DoLogout call from CImpsServer.
                iServer.TransportStatus( EInternal_NO_IAP, this );
                NewState( EImpsCSPIdle );
                return;
                }
            else
                // PDP can be lost in negotiation phase. Then we do internal
                // logout.
                {
#ifndef _NO_IMPS_LOGGING_
                CImpsClientLogger::Log( _L( "CSPSession: LOGGED BUT NOT-NEGOTIATED -> Logout ***" ) );
#endif
                DoLogout();
                }
            }
        }
    else if ( aConnectionState == EInternal_NO_IAP_AUTH )
        {
        // Handle authorative bearer-lost situation here and
        // make CSP logout
#ifndef _NO_IMPS_LOGGING_
        CImpsClientLogger::Log( _L( "CSPSession: NO_IAP_AUTH ***" ) );
#endif
        iIntStatus = EInternal_NOT_LOGGED;
        DoLogout();
        }

    // Call server's TransportStatus only if this is a state change from
    // LOGGED->NOT_LOGGED.
    // NOT_LOGGED event clears the client session CSP identification data and
    // thus it must not be called in vain..
    if ( iIntStatus == EInternal_NOT_LOGGED && oldStatus != EInternal_NOT_LOGGED )
        {
        iServer.TransportStatus( iIntStatus, this );
        }
    }

// ---------------------------------------------------------
// CImpsCSPSession::CirChOpened
// ---------------------------------------------------------
//
void CImpsCSPSession::CirChOpened( )
    {
#ifndef _NO_IMPS_LOGGING_
    CImpsClientLogger::Log( _L( "CSPSession: CirChOpened" ) );
#endif
    iTcpCIRError = EFalse;
    }

// ---------------------------------------------------------
// CImpsCSPSession::CirChError
// ---------------------------------------------------------
//
void CImpsCSPSession::CirChError( )
    {
#ifndef _NO_IMPS_LOGGING_
    CImpsClientLogger::Log( _L( "CSPSession: CirChError csp=%d" ), ( TInt )this );
#endif
    delete iCirManager;
    iCirManager = NULL;
    // start poll mode again
    if ( IsLogged() )
        {
        iPollTime = iSettings.iPollTime;
        iPollState = EImpsPollAdaptive;
        iIdleTimer->Start( iPollTime );
        iPDPIdleTimer->Stop();
#ifndef _NO_IMPS_LOGGING_
        CImpsClientLogger::Log( _L( "CSPSession: iPollState %d" ), iPollState );
        CImpsClientLogger::Log( _L( "CSPSession: iPollTime %d" ), iPollTime );
#endif
        }
    }

// ---------------------------------------------------------
// CImpsCSPSession::SetConnAllowed
// ---------------------------------------------------------
//
void CImpsCSPSession::SetConnAllowed( TBool aParam )
    {
#ifndef _NO_IMPS_LOGGING_
    CImpsClientLogger::Log( _L( "CSPSession: SetConnAllowed %d" ), aParam );
#endif
    iConAllowed = aParam;
    // Logout CSP session on behalf of user if terminal connection is not allowed.
    if ( !aParam )
        {
        // It's important that data channel is started to close first and after
        // that internal CSP disconnect is done.
        iReceiver2->CloseTr( );
        DoLogout( );
        }
    }

// ---------------------------------------------------------
// CImpsCSPSession::DoSendSingleL
// aAc connot be null
// ---------------------------------------------------------
//
void CImpsCSPSession::DoSendSingleL(
    MImpsDataAccessor* aAc,
    const TDesC& aTID,
    TImpsMessageType aMsgType,
    TInt aExpiryTime )
    {
#ifndef _NO_IMPS_LOGGING_
    CImpsClientLogger::Log( _L( "CSPSession: DoSendSingle messagetype = 0x%x csp=%d" ),
                            aMsgType, ( TInt )this );
#endif

    // Set the WV 1.2 version if needed, WV 1.1 is the default
    if ( iCSPVersion == EImpsCspVersion12 )
        {
        CImpsFields* f = aAc->GetImpsFields();
        f->SetCspVersion( EImpsCspVersion12 );
        }

    // Encode the message
    iEncoder->EncodeMessageL( *aAc, *iTransportOut );

    // Send to the transport module
#ifndef _NO_IMPS_LOGGING_
    CImpsClientLogger::Log( _L( "CSPSession: DoSendSingle message encoded = 0x%x" ), aMsgType );
#endif

    // reset PDP idle timer
    iPDPIdleTimer->Reset();

    iReceiver2->SendAndWaitL( aTID, aExpiryTime );
    iLastSent = aMsgType;

    // Notice: Maintain this list of non terminal originated
    // transactions, send by terminal to SAP.
    if ( !( aMsgType == EImpsPolling || aMsgType == EImpsKeepAliveReq ||
            aMsgType == EImpsStatus  || aMsgType == EImpsMessageDelivered ) )
        {
        iTr++;
#ifndef _NO_IMPS_LOGGING_
        CImpsClientLogger::Log( _L( "CSPSession: DoSendSingle iTr = %d" ), iTr );
#endif
        }
    // Anything except Poll and KeepAlive request resets Poll Timer.
    if ( !( aMsgType == EImpsPolling || aMsgType == EImpsKeepAliveReq ) )
        {
        ResetPollTime( );
        }

#ifdef _FAKE_RESPONSE
    iTestMsgTid = aTID;
#endif
    }
// -----------------------------------------------------------------------------
// CImpsCSPSession::DoSendLogoutL
// -----------------------------------------------------------------------------
void CImpsCSPSession::DoSendLogoutL( const TDesC& aTID )
    {
#ifndef _NO_IMPS_LOGGING_
    CImpsClientLogger::Log( _L( "CSPSession: DoSendLogoutL csp=%d" ), ( TInt )this );
#endif

    // Check if the transport is halted
    if ( iReceiver2->NbrOfPending() >= KImpsMaxPending )
        {
        User::Leave( KErrInUse );
        }

    NewState( EImpsCSPDisconnecting );
    // Set expiry time for logout.
    // In case of Login-csncel expiry time is not overwritten, but it
    // is the original login expiry time.
    // Otherwise clint session would expire first and the user client would get
    // normal time-out error, but we want that the user gets OK response.
    if ( !iCancelLogin )
        {
        iNegoExpiry = iServer.ExpiryTime( EImpsEventServerLogin );
        }

    // Make a logout request (encode)
    iSnd->Reset();

    // Insert CSP Session-id
    iSnd->SetSessionIdL( iCSPSessionId );
    iSnd->SetTidL( aTID );
    iSnd->SetMessageType( EImpsLogoutReq );

    // Session type is inband
    iSnd->SetSessionTypeL( EImpsInband );

    TImpsDataAccessor myAc( iSnd );
    CImpsKey* myKey = CImpsKey::NewLC();    // <<< myKey

    // Add TImpsTransactionMode
    TImpsSDataUtils::AddValuesFromArrayL(
        myKey,
        KTransModeElements,
        sizeof( KTransModeElements ) /
        sizeof( KTransModeElements[0] ) );
    myAc.StoreIntegerL( myKey, EImpsRequest );
    myKey->Reset();
    TImpsSDataUtils::AddValuesFromArrayL(
        myKey,
        KTransContentElements,
        sizeof( KTransContentElements ) /
        sizeof( KTransContentElements[0] ) );
    myKey->AddL( CREATEKEY( EImpsKeyLogout_Request, 0 ) );
    myAc.StoreEmptyL( myKey );

    CleanupStack::PopAndDestroy( 1 );   // >>> myKey

    DoSendSingleL( &myAc, aTID, EImpsLogoutReq );
    }

// -----------------------------------------------------------------------------
// CImpsCSPSession::DoMakeSapResponseL
// -----------------------------------------------------------------------------
//
void CImpsCSPSession::DoMakeSapResponseL( CTransaction* aTrans )
    {
    TPtrC tid;
    CImpsFields* fields = aTrans->iFields;
    tid.Set( aTrans->iTID );
    TInt messageType = fields->MessageType();

    TInt responseType = EImpsStatus;
    // Copy values from the new message to a response
    iSnd->Reset();
    iSnd->SetSessionIdL( fields->SessionIdL() );
    iSnd->SetTidL( fields->TidL() );
    iSnd->SetSessionTypeL( EImpsInband );

#ifndef _NO_IMPS_LOGGING_
    TPtrC tid2;
    tid2.Set( fields->TidL() );
    CImpsClientLogger::Log( _L( "CSPSession: MakeSAPresp SAP TID=%S" ), &( tid2 ) );//lint !e525
#endif

    CImpsDataAccessor* myAccess = CImpsDataAccessor::NewL( iSnd );
    CleanupStack::PushL( myAccess );    // << myAccess
    CImpsKey* myKey = CImpsKey::NewLC();  // <<< myKey

    CImpsDataAccessor* myAcRcv = CImpsDataAccessor::NewL( fields );
    CleanupStack::PushL( myAcRcv );    // << myAcRcv

    TPtrC myId;

    switch ( messageType )
        {
        case EImpsNewMessage:
            responseType = EImpsMessageDelivered;
            iSnd->SetMessageType( responseType );
            // Get messageId from received message
            TImpsSDataUtils::GetNewMessageIdL( myKey, myAcRcv, myId );
            // ... and copy data to outgoing response
            TImpsSDataUtils::SetMessageDeliveredIdL(
                myKey, myAccess, myId );
            break;
        default:
            iSnd->SetMessageType( responseType );
            TImpsSDataUtils::SetResultStatusL( myKey, myAccess, KImpsStatusOk );
            break;
        }

    CleanupStack::PopAndDestroy( 1 );   // >> myAcRcv

    // Add TImpsTransactionMode now
    myKey->Reset();
    TImpsSDataUtils::AddValuesFromArrayL(
        myKey,
        KTransModeElements,
        sizeof( KTransModeElements ) /
        sizeof( KTransModeElements[0] ) );
    myAccess->StoreIntegerL( myKey, EImpsResponse );
    CleanupStack::PopAndDestroy( 1 );   // >>> myKey

    // -------------------------------------------
    // Handle orphan message
    if ( aTrans->iOrphan )
        {
        TImpsSessIdent csp( iCSPSessionId, DoSAP(), DoUserId() );
        TRAPD( errx, iServer.HandleOrphanL( aTrans->iFields, csp ) );
        if ( !errx )
            {
            // ownership of the msg is in CImpsServer now
            aTrans->iFields = NULL;
            }
        }
    // -------------------------------------------

    // DoSendSingleL leaves if GPRS suspended,
    // so don't delete entry too early
    DoSendSingleL( myAccess, tid, ( TImpsMessageType )responseType );


    // Save TID into tid-sap-history so that we so not send the response twicw
    // even if SAP would send the transaction multiple times.
    iTidSapHistory->Add( tid );

    CleanupStack::PopAndDestroy( 1 );   // >> myAccess
    }

// -----------------------------------------------------------------------------
// CImpsCSPSession::DoStartIpCIRL
// -----------------------------------------------------------------------------
//
void CImpsCSPSession::DoStartIpCIRL()
    {
    // Start ip-cir-watcher
    if ( iVariant.IsFeatureSupportedL( EIpCirStandalone ) &&
         iSettings.iTCPSCIR == 2 || iSettings.iUDPSCIR == 2 )
        {
        // Check which CIR bindings are negotiated for CSP session
        TUint ipChannels = 0;
        if ( iSettings.iTCPSCIR == 2 )
            {
            ipChannels = KImpsCirTcp;
            }
        if ( iSettings.iUDPSCIR == 2 )
            {
            ipChannels = ipChannels | KImpsCirUdp;
            }
#ifndef _NO_IMPS_LOGGING_
        CImpsClientLogger::Log( _L( "CSPSession: Starting ip-cir-watcher %d" ),
                                ipChannels );
#endif
        iCSPSessionId8.Copy( iCSPSessionId );
        if ( !iCirManager )
            {
            iCirManager = CImpsCirManager::NewL( *this,
                                                 CActive::EPriorityStandard );
            }
        iCirManager->OpenChL( ipChannels, iReceiver2->ConnManagerHandleL(),
                              iTCPPort, *iTCPAddr, iCSPSessionId8 );
        }
    }

// -----------------------------------------------------------------------------
// CImpsCSPSession::IncreasePollTime
// -----------------------------------------------------------------------------
//
void CImpsCSPSession::IncreasePollTime()
    {
    // Increase poll timer. Two modes; CIR Mode and other modes.
    if ( iPollState == EImpsPollCIR )
        {
        ResetPollTime();
        }
    else if ( iPollTime < iSettings.iMaxPollTime && iIdleTimer->IsActive() )
        {
        iPollTime += KImpsPollIncrement;
        iIdleTimer->Start( iPollTime );
#ifndef _NO_IMPS_LOGGING_
        CImpsClientLogger::Log( _L( "CSPSession: PollTime increased to %d" ), iPollTime );
#endif
        }
    }

// -----------------------------------------------------------------------------
// CImpsCSPSession::ResetPollTime
// -----------------------------------------------------------------------------
//
void CImpsCSPSession::ResetPollTime()
    {
    // Reset poll timer. Two modes; CIR Mode and other modes.
    if ( iPollState == EImpsPollCIR )
        {
        if ( iPollTime != iSettings.CIRModePollTime() )
            {
            iPollTime = iSettings.CIRModePollTime();
            iIdleTimer->Start( iPollTime );
#ifndef _NO_IMPS_LOGGING_
            CImpsClientLogger::Log( _L( "CSPSession: PollTime reset %d" ), iPollTime );
#endif
            }
        }
    else if ( iPollTime > iSettings.iPollTime && iIdleTimer->IsActive() )
        {
        iPollTime = iSettings.iPollTime;
        iIdleTimer->Start( iPollTime );
#ifndef _NO_IMPS_LOGGING_
        CImpsClientLogger::Log( _L( "CSPSession: PollTime reset %d" ), iPollTime );
#endif
        }
    }

// -----------------------------------------------------------------------------
// CImpsCSPSession::IsLogged
// -----------------------------------------------------------------------------
//
TBool CImpsCSPSession::IsLogged(  )
    {
    return DoIsLogged();
    }

// -----------------------------------------------------------------------------
// CImpsCSPSession::IsPendingLogin
// -----------------------------------------------------------------------------
//
TBool CImpsCSPSession::IsPendingLogin()
    {
    return iCSPState == EImpsCSPLogging ? ETrue : EFalse;
    }

// -----------------------------------------------------------------------------
// CImpsCSPSession::IsNegotiated
// -----------------------------------------------------------------------------
//
TBool CImpsCSPSession::IsNegotiated(  )
    {
    return DoIsNegotiated();
    }

// -----------------------------------------------------------------------------
// CImpsCSPSession::Servicses
// -----------------------------------------------------------------------------
//
TImpsServices* CImpsCSPSession::Services(  )
    {
    return &iServices;  //lint !e1536 this pointer must be used with care
    }

// -----------------------------------------------------------------------------
// CImpsCSPSession::IsShuttingDown
// -----------------------------------------------------------------------------
//
TBool CImpsCSPSession::IsShuttingDown(  )
    {
    return DoIsShuttingDown();
    }

// -----------------------------------------------------------------------------
// CImpsCSPSession::IsLogging
// -----------------------------------------------------------------------------
//
TBool CImpsCSPSession::IsLogging(  )
    {
    return DoIsLogging();
    }

// -----------------------------------------------------------------------------
// CImpsCSPSession::UserId
// -----------------------------------------------------------------------------
//
TPtrC CImpsCSPSession::UserId(  )
    {
    return DoUserId();
    }

// -----------------------------------------------------------------------------
// CImpsCSPSession::SAP
// -----------------------------------------------------------------------------
//
TPtrC CImpsCSPSession::SAP(  )
    {
    return DoSAP();
    }

// -----------------------------------------------------------------------------
// CImpsCSPSession::SID
// -----------------------------------------------------------------------------
//
TPtrC CImpsCSPSession::SID(  )
    {
    return iCSPSessionId;
    }

// -----------------------------------------------------------------------------
// CImpsCSPSession::Password
// -----------------------------------------------------------------------------
//
TPtrC CImpsCSPSession::Password(  )
    {
    return LogPwd();
    }

// -----------------------------------------------------------------------------
// CImpsCSPSession::GiveNextRequestL
// -----------------------------------------------------------------------------
CReq* CImpsCSPSession::GiveNextRequestL()
    {

#ifndef _NO_IMPS_LOGGING_
    CImpsClientLogger::Log( _L( "CSPSession: GiveNextRequestL begins" ) );
#endif
    // If logginOff then this should be logout request
    TDblQueIter<CReq> iter ( iRequestList );
    iter.SetToFirst();

    while ( iter )
        {
        CReq* request = iter;
        // Get first and check if it is expired
        iter++;

        TTime myTime;
        myTime.HomeTime();
        if ( request->iExpiry < myTime )
            {
            // session is asked to discard request from its structures
            // Check TID match
#ifndef _NO_IMPS_LOGGING_
            CImpsClientLogger::Log( _L( "Server: EXPIRED entry to be removed" ) );
#endif
            TImpsMessageType msgType = ( TImpsMessageType ) request->iFields->MessageType();
            TImpsEventType myType = impsService( &iVariant, msgType );
            // expired request is destroyed in client sessions too.
            TImpsSessIdent csp( iCSPSessionId, DoSAP(), DoUserId() );
            iServer.DiscardRequest( request->iFields->TidL(), myType, KErrTimedOut, csp );

            // expired entry is deleted
            request->Destroy();
            TrMinus();

            // We want to push new messages from queued
            SendAllQueued();

            }  // expired
        else
            {
            return request;
            }
        }

    return ( CReq* )NULL;
    }


// -----------------------------------------------------------------------------
// CImpsCSPSession::NewState
// -----------------------------------------------------------------------------
void CImpsCSPSession::NewState( TImpsCSPState aNew )
    {
#ifndef _NO_IMPS_LOGGING_
    CImpsClientLogger::Log( _L( "CSPSession: NewState old=%d new=%d csp=%d" ),
                            iCSPState, aNew, ( TInt )this );
#endif
    // In  EImpsCSPDisconnecting iLogTid is still needed fore cancel-login
    if ( iCSPState >= EImpsCSPLogging && aNew < EImpsCSPDisconnecting )
        {
        delete iLogTid;
        iLogTid = NULL;
        }
    if ( aNew == EImpsCSPIdle )
        {
        iTr = 0;
        iCookie = KNullDesC;
        iCookie8 = KNullDesC8;
        iCSPSessionId = KNullDesC;
        iCSPSessionId8 = KNullDesC8;
        iLoginPhase = 1;
        }
    else if ( aNew <= EImpsCSPOnLine )
        {
        // PDP is opened sucessfully or CSP login not done or logging out.
        iPDPOpenTimer->Stop();
        }
    iCSPState = aNew;
    }


// -----------------------------------------------------------------------------
// CImpsCSPSession::TrMinus
// -----------------------------------------------------------------------------
void CImpsCSPSession::TrMinus()
    {
    if ( iTr > 0 )
        {
        iTr--;
        }
#ifndef _NO_IMPS_LOGGING_
    CImpsClientLogger::Log( _L( "CSPSession: iTr=%d csp=%d" ), iTr, ( TInt )this );
#endif
    }


// -----------------------------------------------------------------------------
// CImpsCSPSession::ResetSession
// -----------------------------------------------------------------------------
void CImpsCSPSession::ResetSession()
    {
#ifndef _NO_IMPS_LOGGING_
    CImpsClientLogger::Log( _L( "CSPSession: ResetSession csp=%d" ), ( TInt )this );
#endif
    // This is not needed since CSP session entity is not re-cycled?
    iSettings.iUDPWAPCIR = 1;
    iSettings.iSMSWAPCIR = 1;
    iSettings.iTCPSCIR = 1;
    iSettings.iUDPSCIR = 1;
    iSettings.iPollTime = KImpsPollTime;
    }


// -----------------------------------------------------------------------------
// CImpsCSPSession::MaxParserSize
// -----------------------------------------------------------------------------
TInt CImpsCSPSession::MaxParserSize()
    {
    return iServer.Settings()->MaximumParserSize();
    }

// -----------------------------------------------------------------------------
// CImpsCSPSession::MaxParserSize
// -----------------------------------------------------------------------------
TInt CImpsCSPSession::MaxMessageSize()
    {
    return iServer.Settings()->MaximumMessageSize();
    }

// -----------------------------------------------------------------------------
// CTransaction::CTransaction
// -----------------------------------------------------------------------------

CTransaction::CTransaction(
    TBool aOrphan,
    const TDesC& aTID,
    const TDesC& aSessionId,
    TImpsMessageType aMessageType,
    CImpsFields* aFields ) :
        iMessageType( aMessageType ),
        iFields ( aFields ),
        iOrphan ( aOrphan )
    {
    iTID = aTID;
    iSessionId = aSessionId;
    }

CTransaction::~CTransaction()
    {

    } //lint !e1540 iFields freed in Destroy

void CTransaction::Destroy()
    {
    iLink.Deque();
    delete iFields;
    iFields = NULL;
    delete this;
    }


// -----------------------------------------------------------------------------
// CReq::CReq
// -----------------------------------------------------------------------------

CReq::CReq( CImpsFields* aFields ) :
        iFields( aFields )
    {}

CReq::~CReq()
    {

    }   //lint !e1540 iFields freed in Destroy

void CReq::Destroy()
    {
    delete iFields;
    iFields = NULL;
    iLink.Deque();
    delete this;
    }

// -----------------------------------------------------------------------------
// CImpsCSPSession::IsLogoutResp()
// aFields must not be NULL
// -----------------------------------------------------------------------------
TImpsLogoutTrans CImpsCSPSession::IsLogoutResp( CImpsFields* aFields )
    {
    TImpsLogoutTrans ret = EImpsLogoutNone;

    // set pointers to received TID and to current pending Logout-request TID
    TPtrC recId;
    TPtrC logoutTid;
    logoutTid.Set( LogoutTID() );
    TRAPD( errxy, recId.Set( aFields->TidL() ) );
    if ( errxy )
        {
        return ret;
        }

    // Check if current logout transaction TID matches with received message.
    if ( iCSPState == EImpsCSPDisconnecting &&
         !logoutTid.Length() || ( logoutTid.Length() && !recId.Compare( logoutTid  ) ) )  // NOTE
        {
        if ( aFields->MessageType() == EImpsDisconnect )
            {
            // WV 1.1 logout response
            ret = EImpsLogoutTerminal;
            }
        else if ( aFields->MessageType() == EImpsStatus )
            {
            // WV 1.2 logout response
            ret = EImpsLogoutTerminal;
            }
        }
    else if ( aFields->MessageType() == EImpsDisconnect )
        {
        // SAP initiated CSP disconnect
        ret = EImpsLogoutSAP;
        }
#ifndef _NO_IMPS_LOGGING_
    CImpsClientLogger::Log( _L( "CSPSession: IsLogoutResp returns %d csp=%d" ),
                            ret, ( TInt )this );
#endif
    return ret;
    }

// -----------------------------------------------------------------------------
// CImpsCSPSession::StartLoginCancel()
// -----------------------------------------------------------------------------
void CImpsCSPSession::StartLoginCancel( )
    {
    // Cancel login transaction, either login+logout or login+cancelLogin.
    // DoPendingLogout() is called later to complete the client requests.
    if ( iReceiver2->CancelLoginTrans( LogTid() ) )
        {
        // Generate CSP Logout transaction
        // Clear buffers from old stuff
        DeleteRequests();
        DeleteTransactions();
        // Send Logout primitive and set state to EImpsCSPDisconnecting.
        TRAPD( errx, DoSendLogoutL( LogoutTID() ) );
        if ( errx )
            {
#ifndef _NO_IMPS_LOGGING_
            CImpsClientLogger::Log( _L( "CSPSession: DoSendLogoutL 2 error %d ***" ), errx );
#endif
            }
        else
            {
            // If CSP Logout transaction is sent then we wait TransportResponseL or
            // TransportErrorL callback methods to be called later.
            return;
            }
        }
    // Start to send events to clients if CSP Disconnect transaction is not sent.
    DoPendingLogout();
    }

// -----------------------------------------------------------------------------
// CImpsCSPSession::DoPendingLogout()
// -----------------------------------------------------------------------------
void CImpsCSPSession::DoPendingLogout( )
    {
#ifndef _NO_IMPS_LOGGING_
    CImpsClientLogger::Log( _L( "CSPSession: DoPendingLogout ***" ) );
#endif
    // Send critical response events to client sessions and start to logout
    // internally this CSP session entity.
    TImpsSessIdent csp( iCSPSessionId, DoSAP(), DoUserId() );
    if ( iPendingLogout )
        {
        // Send login response for pending request first
        iServer.DiscardRequest( LogTid(), EImpsEventServerLogin, KErrCancel, csp );
        // Send logout response, that is always successful
        iServer.DiscardLogout( LogoutTID(), csp );
        }

    if ( iCancelLogin  )
        {
        // Send cancel-login response to client
        iServer.DiscardRequest( LogTid(), EImpsEventServerLogin, KErrNone, csp );
        }

    iPendingLogout = EFalse;
    iCancelLogin = EFalse;
    DoLogout();
    }

//  End of File