IMPSengine/engsrv/src/impsserver.cpp
changeset 0 094583676ce7
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/IMPSengine/engsrv/src/impsserver.cpp	Thu Dec 17 08:41:52 2009 +0200
@@ -0,0 +1,1792 @@
+/*
+* Copyright (c) 2002-2006 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: Classes for IM server and Conn.
+*
+*
+*/
+
+
+
+// INCLUDE FILES
+#include    <e32math.h>
+#include    <ecom/ecom.h>
+#include    "impsserver.h"
+#include    "impssession.h"
+#include    "impssubsession.h"
+#include    "impsfields.h"
+#include    "impsutils.h"
+#include    "impserrors.h"
+#include    "impstimer.h"
+#include    "impsservices.h"
+#include    "impscommonenums.h"
+#include    "impssdatautils.h"
+#include    "impsmessageinterpreterapi.h"
+#include    "ImpsVariantAPI.h"
+#include    "impscspsession.h"
+#include    "impsorphans.h"
+#include    "impstoffobserver.h"
+#include    "WVEngineInternalCRKeys.h"
+
+
+#include    "impsserversecuritypolicy.h"
+
+
+// MACROS
+#ifndef _DEBUG
+#define _NO_IMPS_LOGGING_
+#endif
+
+// CONSTANTS
+// Shutdown idle wait time in seconds
+const TInt KImpsShutdownTime = 0;
+// Overhead estimate for XML message : total - transaction content
+const TInt KImpsBufOverhead = 100;
+
+// ================= MEMBER FUNCTIONS =======================
+
+void CImpsScheduler::Error( TInt anError ) const
+    {
+    // This is just for compiler to avoid warning
+    TInt err = anError;
+#ifndef _NO_IMPS_LOGGING_
+    CImpsClientLogger::Log( _L( "Scheduler: error=%d" ), anError );
+#endif
+    // This is just for another compiler to avoid warning
+    anError = err;
+    }
+
+// -----------------------------------------------------------------------------
+// CLASS CImpsConn
+// -----------------------------------------------------------------------------
+CImpsConn::CImpsConn( MImpsCSPSession* aSess ) :
+        iSess( aSess ), iRemover( NULL )
+    {}
+
+CImpsConn::~CImpsConn()
+    {
+
+    }   //lint !e1540 iSess freed in Destroy
+
+// Two-phased constructor.
+CImpsConn* CImpsConn::NewL( MImpsCSPSession* aSess, CImpsServer& aServer )
+    {
+    CImpsConn* self = new ( ELeave ) CImpsConn( aSess );
+    CleanupStack::PushL( self );
+    self->ConstructL( aServer );
+    CleanupStack::Pop();
+    return self;
+    }
+
+// Two-phased constructor.
+// It creates an active object to destroy CSP session asynchronously later.
+// It's better to create it now to avoid OOM errors in CSP closing.
+void CImpsConn::ConstructL( CImpsServer& aServer )
+    {
+    iRemover = new ( ELeave ) CImpsCSPDestroyer(
+        aServer, *iSess, CActive::EPriorityUserInput + 1 );
+    }
+
+// -----------------------------------------------------------------------------
+// CImpsConn::Destroy
+// -----------------------------------------------------------------------------
+void CImpsConn::Destroy()
+    {
+    iRemover->Cancel();
+    delete iRemover;
+    iSess->Destroy();
+    delete ( CImpsCSPSession* )iSess;
+    iSess = NULL;
+    iLink.Deque();
+    delete this;
+    }
+
+// -----------------------------------------------------------------------------
+// CImpsConn::Sess
+// -----------------------------------------------------------------------------
+MImpsCSPSession* CImpsConn::Sess()
+    {
+    return iSess;
+    }
+
+// -----------------------------------------------------------------------------
+// CImpsConn::DeleteCSPAsynch
+// -----------------------------------------------------------------------------
+void CImpsConn::DeleteCSPAsynch()
+    {
+    // iRemover cannot be NULL since it's created in contructor
+    if ( iRemover->IsActive() )
+        {
+        // asynchronous request already runnig, nothing to do
+        return;
+        }
+    iRemover->DeleteCSPAsynch( );
+    }
+
+// -----------------------------------------------------------------------------
+// CImpsConn::MatchCSP
+// -----------------------------------------------------------------------------
+TBool CImpsConn::MatchCSP( TImpsSessIdent aCSP )
+    {
+    if ( ( aCSP.UserId().Compare( iSess->UserId() ) ) ||
+         ( aCSP.SAP().Compare( iSess->SAP() ) ) )
+        // Notice: no need for this
+        // ( aCSP.SID().Length() && aCSP.SID().Compare( iSess->SID() )))
+        {
+        return EFalse;
+        }
+    return ETrue;
+    }
+
+
+// -----------------------------------------------------------------------------
+// CLASS CImpsCSPDestroyer
+// -----------------------------------------------------------------------------
+CImpsCSPDestroyer::CImpsCSPDestroyer(
+    CImpsServer& aServer, MImpsCSPSession& aSess, TInt aPriority )
+        : CActive( aPriority ),
+        iServer( aServer ),
+        iSess( aSess ),
+        iCanceled ( EFalse )
+    {
+    // Add this to the scheduler
+    CActiveScheduler::Add( this );
+    }
+
+CImpsCSPDestroyer::~CImpsCSPDestroyer()
+    {
+    Cancel();
+    }
+
+// -----------------------------------------------------------------------------
+// CImpsCSPDestroyer::DeleteCSPAsynch
+// -----------------------------------------------------------------------------
+void CImpsCSPDestroyer::DeleteCSPAsynch(  )
+    {
+#ifndef _NO_IMPS_LOGGING_
+    CImpsClientLogger::Log( _L( "CImpsCSPDestroyer: DeleteCSPAsynch" ) );
+#endif
+    // This yields the control to the server thread active scheduler
+    if ( !IsActive() )
+        {
+        iStatus = KRequestPending;
+        SetActive();
+        iCanceled = EFalse;
+        TRequestStatus* s = &iStatus;
+        User::RequestComplete( s, KErrNone );
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CImpsCSPDestroyer::DoCancel
+// -----------------------------------------------------------------------------
+void CImpsCSPDestroyer::DoCancel()
+    {
+    iCanceled = ETrue;
+    }
+
+// -----------------------------------------------------------------------------
+// CImpsCSPDestroyer::RunL
+// -----------------------------------------------------------------------------
+void CImpsCSPDestroyer::RunL()
+    {
+#ifndef _NO_IMPS_LOGGING_
+    CImpsClientLogger::Log( _L( "CImpsCSPDestroyer: RunL" ) );
+#endif
+    if ( iCanceled || iStatus.Int() != KErrNone )
+        {
+        return;
+        }
+    // Trigger a server thread to send a queued message
+    iServer.DeleteCSP( &iSess );
+    // It is extremely important that after the previous call this
+    // method does nothing since DeleteCSP actully deletes the
+    // current entity if this class!
+#ifndef _NO_IMPS_LOGGING_
+    CImpsClientLogger::Log( _L( "CImpsCSPDestroyer: RunL ends" ) );
+#endif
+    }
+
+// -----------------------------------------------------------------------------
+// CLASS CImpsServer
+// -----------------------------------------------------------------------------
+CImpsServer::CImpsServer()
+        : CPolicyServer( EPriorityUserInput /*EPriorityHigh*/, KImpsServerPolicy ),
+        iFs(),
+        iSettings( ),
+        iConAllowed( ETrue ),
+        iCSPVersion( EImpsCspVersion11 ),
+        iOperation( EImpsSrvNone ),
+        iOrphans( NULL ),
+        iCSPList( _FOFF( CImpsConn, iLink ) ), //lint !e413,
+        iObserver( NULL ),
+        iExpiryInterval( 0 )
+    {
+    }
+
+// Create and start a new server.
+
+CImpsServer* CImpsServer::New()
+    {
+#ifndef _NO_IMPS_LOGGING_
+    CImpsClientLogger::Log( _L( "Server: rel200614.4+" ) );
+#endif
+
+    CImpsServer* server = new CImpsServer();
+    if ( server )
+        {
+        if ( server->Start( KImpsServerName ) != KErrNone )
+            {
+            delete server;
+            server = NULL;
+            }
+        }
+
+#ifdef _DEBUG
+    if ( server && server->iFs.Connect() )
+        {
+        delete server;
+        server = NULL;
+        }
+#endif // _DEBUG               
+
+    return server;
+    }
+
+CImpsServer::~CImpsServer()
+    {
+    // deallocate all memory
+
+    delete iSnd;
+    delete iShutTimer;
+    delete iExpiryTimer;
+
+    delete iContainerIndex;
+    delete iVariant;
+    delete iOrphans;
+    delete iObserver;
+
+#ifdef _DEBUG
+    // close file session
+    iFs.Close();
+#endif // _DEBUG      
+    }
+
+// -----------------------------------------------------------------------------
+// CImpsServer::ConstructL()
+// -----------------------------------------------------------------------------
+void CImpsServer::ConstructL()
+    {
+#ifndef _NO_IMPS_LOGGING_
+    CImpsClientLogger::Log( _L( "Server:ConstructL begins" ) );
+#endif
+
+    iContainerIndex = CObjectConIx::NewL();
+
+    // Read static settings, use defaults if ini file not exist
+    iSettings.ReadStaticSettings();
+#ifdef _DEBUG
+    TInt errx = KErrNone;
+    TRAP( errx, iSettings.ReadIniFileL( iFs ) );
+#endif
+
+    iVariant = CImpsVariant::NewLC( );
+    CleanupStack::Pop( ); // >> iVariant
+
+    iSnd = CImpsFields::NewL();
+    iShutTimer = new ( ELeave ) CImpsShutdownTimer( *this,
+                                                    CActive::EPriorityUserInput + 1 );
+    iExpiryTimer = new ( ELeave ) CImpsExpiryTimer( *this,
+                                                    EImpsEventAll, CActive::EPriorityStandard );
+
+    // Get the supported WV CSP version for all sessions
+    GetCSPVersion();
+
+    // local variation
+    //----------------------------
+    if ( iVariant->IsFeatureSupportedL( EImLauncher ) )
+        {
+        iOrphans = CImpsOrphans::NewL();
+        }
+    //----------------------------
+
+    // Check terminal off line state
+    iObserver = CImpsTOffObserver::NewL( *this );
+    if ( !iObserver->CheckConnAllowed() )
+        {
+        SetConnAllowed( EFalse );
+        }
+
+#ifndef _NO_IMPS_LOGGING_
+    CImpsClientLogger::Log( _L( "Server:ConstructL ends" ) );
+#endif
+
+    }
+
+// -----------------------------------------------------------------------------
+// CImpsServer::NewSessionL()
+// -----------------------------------------------------------------------------
+CSession2* CImpsServer::NewSessionL(
+    const TVersion &aVersion, const RMessage2& aMessage ) const
+    {
+    // check that we're the right version
+    TVersion v( KImpsServMajorVersionNumber,
+                KImpsServMinorVersionNumber,
+                KImpsServBuildVersionNumber );
+    if ( !User::QueryVersionSupported( v, aVersion ) )
+        {
+        User::Leave( KErrNotSupported );
+        }
+
+    if ( iOperation == EImpsSrvShuttingDown )
+        {
+#ifndef _NO_IMPS_LOGGING_
+        CImpsClientLogger::Log( _L( "Server: NewSessionL in shut down ***" ) );
+#endif
+        User::Leave( KImpsErrorShuttingDown );
+        }
+
+    StopTimer();
+
+#ifndef _NO_IMPS_LOGGING_
+    CImpsClientLogger::Log( _L( "Server: NewSessionL ends" ) );
+#endif
+
+    // make a new session
+    RMessage2 msg = aMessage;
+    return new( ELeave ) CImpsSession( msg );
+    }
+
+// -----------------------------------------------------------------------------
+// CImpsServer::CloseSession()
+// -----------------------------------------------------------------------------
+void CImpsServer::CloseSession( TImpsSessIdent aCSP, TBool aComplete )
+    {
+
+#ifndef _NO_IMPS_LOGGING_
+    TInt temp1 = NbrSessions( ETrue );
+    TInt temp2 = NbrSessions( EFalse );
+    CImpsClientLogger::Log( _L( "Server: CloseSession nbrses=%d-%d aComplete=%d" ), temp1, temp2, aComplete );
+#endif
+
+    // CServer2 calls CImpsSession's desctrutor if its consctrutor fails
+    // but in that case NbrSessions() method does not see the failed entity.
+    // Thus in case of failed session creation the limit is 0, otherwise 1,
+    // i.e. the last client session to be closed starts the shut down timer.
+    TInt limit = aComplete ? 1 : 0;
+    MImpsCSPSession* ses = GetCSP( aCSP, ETrue );
+    if ( !ses )
+        {
+        // If the last client session and no CSP sessions
+        // then start final count down
+        if ( NbrSessions( EFalse ) <= limit )
+            {
+            // There is nobody listening to expiry events
+            iExpiryTimer->Stop( );
+            if ( !NbrCSPs() )
+                {
+                // start the final count down
+                iOperation = EImpsSrvFinish;
+                iShutTimer->Start( KImpsShutdownTime );
+                }
+            }
+        return;
+        }
+
+    // This is very last client session for the CSP connection.
+    // Disconnect CSP session on behalf of applications in this case.
+    TInt myCount = NbrSessions( EFalse, aCSP );
+    if ( myCount == 1 )
+        {
+        TRAPD( errx, ( void )ses->LogoutL( EFalse ) );
+        if ( !errx )
+            {
+            return;
+            }
+        }
+
+    }
+
+// -----------------------------------------------------------------------------
+// CImpsServer::ThreadStart()
+// -----------------------------------------------------------------------------
+EXPORT_C TInt CImpsServer::ThreadStart( TImpsSignal& aSignal )
+    {
+    // naming the server thread after the server helps to debug panics
+    RThread().RenameMe( KImpsServerExe );
+
+    TInt err = KErrNone;
+#ifndef _NO_IMPS_LOGGING_
+    CImpsClientLogger::Log( _L( "Server: ThreadStart begins" ) );
+    CImpsClientLogger::Log( _L( "Server: aSignal.iRate = %x" ), aSignal.iRate );
+#endif
+    __UHEAP_MARK;
+
+    CTrapCleanup* cleanup = NULL;
+    CImpsScheduler* scheduler = NULL;
+    CImpsServer* server = NULL;
+    cleanup = CTrapCleanup::New();
+
+#ifdef _DEBUG
+    TInt rate = aSignal.iRate;
+    if ( rate > 0 )
+        {
+        TRAP( err, __UHEAP_SETFAIL( RHeap::EFailNext, rate ) );
+        }
+#endif
+
+    scheduler = new CImpsScheduler;
+
+    if ( cleanup && scheduler )
+        {
+        CImpsScheduler::Install( scheduler );
+        server = CImpsServer::New();      // adds server in scheduler
+        }
+
+    if ( !cleanup || !scheduler || !server )
+        {
+        err = KErrNoMemory;
+        }
+    else
+        {
+        TRAP( err, server->ConstructL() );
+        }
+
+    if ( err )
+        {
+#ifndef _NO_IMPS_LOGGING_
+        CImpsClientLogger::Log( _L( "Server:ConstructL failed = %d" ), err );
+#endif
+        delete server;      //lint !e644 initialization ok
+        delete cleanup;     //lint !e644 initialization ok
+        delete scheduler;   //lint !e644 initialization ok
+        }
+
+    // signal that we've started
+    RProcess::Rendezvous( err );
+
+    // start fielding requests from clients
+    if ( err == KErrNone )
+        {
+        CImpsScheduler::Start();
+
+        // comes here when server shuts down
+
+#ifndef _NO_IMPS_LOGGING_
+        CImpsClientLogger::Log( _L( "Server: Scheduler is STOPPED" ) );
+#endif
+        delete server;      //lint !e644 initialization ok
+        delete scheduler;   //lint !e644 initialization ok
+        delete cleanup;     //lint !e644 initialization ok
+        }
+
+#ifdef _DEBUG
+    if ( rate > 0 )
+        {
+        TInt err2 = KErrNone;
+        TRAP( err2, __UHEAP_SETFAIL( RHeap::ENone, 0 ) );
+        }
+#ifndef _NO_IMPS_LOGGING_
+    CImpsClientLogger::Log( _L( "Server: MEM TEST begins" ) );
+#endif
+    __UHEAP_MARKEND;
+#ifndef _NO_IMPS_LOGGING_
+    CImpsClientLogger::Log( _L( "Server: MEM TEST OK" ) );
+#endif
+#endif
+
+    return( err );
+    }
+
+// -----------------------------------------------------------------------------
+// CImpsServer::LoginL
+// -----------------------------------------------------------------------------
+TPtrC CImpsServer::LoginL(
+    const TDesC& aUser,
+    const TDesC& aPassword,
+    const TDesC& aClientId,
+    const TDesC& aSAP,
+    TUint32 aAP,
+    const TDesC& aKey1,
+    const TDesC& aKey2,
+    CImpsSubSession* /*aSub*/,
+    const TTime aLoginExpiry,
+    TBool aReactive )
+    {
+#ifndef _NO_IMPS_LOGGING_
+    CImpsClientLogger::Log( _L( "Server: LoginL" ) );
+#endif
+
+    if ( iOperation == EImpsSrvShuttingDown )
+        {
+        User::Leave( KImpsErrorShuttingDown );
+        }
+
+    // multi: check if CSP already exists, otherwise create a new CSP session
+    TImpsSessIdent csp( KNullDesC, aSAP, aUser );
+    MImpsCSPSession* ses = GetCSP( csp, EFalse );
+    // multi: Check if another client is logging with this CSP session
+    if ( ses && ses->IsLogging() )
+        {
+#ifndef _NO_IMPS_LOGGING_
+        CImpsClientLogger::Log( _L( "Server: CSP is logging ****" ) );
+#endif
+        }
+    else if ( !ses  )
+        {
+        ses = NewCSPL( csp, iCSPVersion );
+        }
+
+    // Before starting actual transport data transfer we start expiry timer
+    SetExpiryTimer( 0, ETrue );
+
+    // This leaves if already logged or if performing logging currently
+    // Certain error types means that CSP sessions is already doing something,
+    // rest of the error codes means that initialization has been failed and
+    // thus the entity has to deleted
+    TPtrC p( KNullDesC );
+    TRAPD( errx, p.Set( ses->LoginL( aUser, aPassword, aClientId, aSAP, aAP,
+                                     aKey1, aKey2, aLoginExpiry, aReactive ) ) );
+    if ( errx )
+        {
+        // These are means that CSP entity is running and in use, don't delete it yet.
+        if ( errx != KErrNotReady && errx != KImpsErrorAlreadyLogged )
+            {
+            DeleteCSPAsynch( ses );
+            }
+        User::Leave( errx );
+        }
+    return p;
+    }
+
+// -----------------------------------------------------------------------------
+// CImpsServer::LogoutL
+// -----------------------------------------------------------------------------
+TPtrC CImpsServer::LogoutL(
+    TBool aCancel,
+    TImpsSessIdent aCSP )
+    {
+#ifndef _NO_IMPS_LOGGING_
+    CImpsClientLogger::Log( _L( "Server: LogoutL" ) );
+#endif
+
+    // Just leave if other client sessions use still this CSP session
+    // or if server is shutting down.
+    // KImpsErrorTerminalOffLine is handled in a special way in a client session class.
+    // That's because of Logout should not fail if sessions existed.
+    //
+    if ( NbrSessions( ETrue, aCSP ) > 1 ||
+         iOperation == EImpsSrvShuttingDown )
+        {
+#ifndef _NO_IMPS_LOGGING_
+        CImpsClientLogger::Log( _L( "Server: LogoutL LEAVES 1 KImpsErrorTerminalOffLine  ***" ) );
+#endif
+        User::Leave( KImpsErrorTerminalOffLine );
+        }
+
+    // Leave also if there is no CSP session or CSP session state is improper
+    MImpsCSPSession* ses = GetCSP( aCSP, EFalse );
+    if ( !ses || ( !IsLogged( aCSP, NULL ) && !IsPendingLogin( aCSP ) ) )
+        {
+        // The following is not needed:
+        //   Send error messages for existing requests
+        //   DiscardRequests( EImpsEventAll, KImpsErrorNotLogged, aCSP );
+        // This error code is handled in a special way in a sub-session.
+#ifndef _NO_IMPS_LOGGING_
+        CImpsClientLogger::Log( _L( "Server: LogoutL LEAVES 2 KImpsErrorTerminalOffLine  ***" ) );
+#endif
+        User::Leave( KImpsErrorTerminalOffLine );
+        }
+
+    // Be 100% sure that expiry timer is running
+    if ( !iExpiryTimer->IsActive() )
+        {
+        TInt expiryInterval = iSettings.iAccessExp;
+        iExpiryTimer->Start( expiryInterval / 2 );
+        }
+
+    return ses->LogoutL( aCancel );
+    }
+
+// -----------------------------------------------------------------------------
+// CImpsServer::CirMessageL
+// -----------------------------------------------------------------------------
+void CImpsServer::CirMessageL(
+    const TDesC8& aCookie )
+    {
+#ifndef _NO_IMPS_LOGGING_
+    CImpsClientLogger::Log( _L( "Server: CirMessageL" ) );
+#endif
+
+    // Call Session
+
+    // multi: scan all sessions until session cookie matches
+    TDblQueIter<CImpsConn> rIter( iCSPList );
+    rIter.SetToFirst();
+    while ( rIter )
+        {
+        CImpsConn* conn = rIter;
+        rIter++;
+        TRAPD( errx, conn->Sess()->CirMessageL( aCookie ) );
+        if ( !errx )
+            {
+            // If no error then the CSP session was a right one
+            break;
+            }
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CImpsServer::SendDataL
+// aSession MUST NOT be NULL
+// -----------------------------------------------------------------------------
+TPtrC CImpsServer::SendDataL(
+    CImpsSubSession* aSession, TImpsSessIdent aCSP )
+    {
+
+#ifndef _NO_IMPS_LOGGING_
+    CImpsClientLogger::Log( _L( "Server: SendDataL begins" ) );
+#endif
+
+    // multi:
+    MImpsCSPSession* ses = GetCSP( aCSP, EFalse );
+    if ( !ses )
+        {
+        User::Leave( KImpsErrorNotLogged );
+        }
+
+    TInt expiryTime = aSession->ExpiryTime();
+
+    // iSnd is for own creations, but this is created in a session
+    CImpsFields* fields = NULL;
+    fields = aSession->ImpsFields();
+
+    __ASSERT_DEBUG( fields, User::Panic( KImpsPanicCategory, EImpsCorrupted ) );
+
+    TBool ownerCh( EFalse );
+    TPtrC ptr = ses->SendDataL( fields, expiryTime, ownerCh );
+    if ( ownerCh )
+        {
+        // Transport adapter is busy so the request is queued and
+        // data owner is changed
+        aSession->NewFieldsL();
+        }
+    return ptr;
+    }
+
+// -----------------------------------------------------------------------------
+// CImpsServer::StopTimer
+// -----------------------------------------------------------------------------
+void CImpsServer::StopTimer() const
+    {
+    iShutTimer->Stop();
+    }
+
+// -----------------------------------------------------------------------------
+// CImpsServer::CheckRequestsL
+// -----------------------------------------------------------------------------
+void CImpsServer::CheckRequestsL(
+    CImpsFields* aFields,
+    TBool& aFound,
+    TImpsSessIdent aCSP )
+    {
+
+#ifndef _NO_IMPS_LOGGING_
+    CImpsClientLogger::Log( _L( "Server: CheckRequests begins " ) );
+#endif
+
+    aFound = EFalse;
+
+    // Block some message types for push message, not MO CSP transactions,
+    // to speed up performance
+    // Notice: update list as needed
+    TInt messageType = aFields->MessageType();
+    if ( messageType == EImpsNewMessage ||
+         messageType == EImpsDeliveryReportReq ||
+         // This may be requested or SAP initiated
+         // so, don't do that :messageType == EImpsLeaveGroupRes ||
+         messageType == EImpsInviteUserReq ||
+         messageType == EImpsInviteRes ||
+         messageType == EImpsCancelInviteUserReq ||
+         messageType == EImpsPresenceNotification ||
+         messageType == EImpsGroupChangeNotice )
+        {
+#ifndef _NO_IMPS_LOGGING_
+        CImpsClientLogger::Log( _L( "Server: CheckRequests cancelled" ) );
+#endif
+        return;
+        }
+
+    // Go through all sessions (each having an own request list)
+
+    iSessionIter.SetToFirst();
+    TInt myOpId = 0;
+    TImpsServRequest reqType = EImpsServNone;
+    TImpsMessageType msgType = EImpsMessageNone;
+
+    TUint subHandle = 0;
+
+    // Check TID match
+    while ( iSessionIter )
+        {
+        CSession2* session = iSessionIter;
+        iSessionIter++;
+        // return handle of matching subsession and give it as parameter
+        subHandle = ( ( CImpsSession* )session )->CheckRequests( aFields->TidL(),
+                                                                 myOpId, reqType, msgType, aCSP );
+        if ( subHandle )
+            {
+            // Do not delete request until corresponding event is sent.
+            // If event sending fails then expiration will take place later.
+            ( ( CImpsSession* )session )->SendEvent(
+                aFields, myOpId, reqType, msgType, subHandle );
+
+            ( ( CImpsSession* )session )->DeleteRequest( myOpId, subHandle );
+            aFound = ETrue;
+            // multi: do not stop searching because of there may be
+            // multiple login requests with the same TID.
+            // break;
+            }
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CImpsServer::CheckNotifications
+// -----------------------------------------------------------------------------
+TBool CImpsServer::CheckNotifications(
+    CImpsFields* aFields,
+    TImpsSessIdent aCSP )
+    {
+
+#ifndef _NO_IMPS_LOGGING_
+    CImpsClientLogger::Log( _L( "Server: CheckNotifications begins" ) );
+#endif
+
+    // Check if IM message max size is exceeded
+    if ( aFields->MessageType() == EImpsNewMessage &&
+         aFields->Size() > iSettings.MaximumMessageSize() )
+        {
+#ifndef _NO_IMPS_LOGGING_
+        CImpsClientLogger::Log( _L( "Server: error: IM Message max size exceeded ***" ) );
+#endif
+        // This is not saved in an orphan queue either
+        return ETrue;
+        }
+
+    TBool retVal( EFalse );
+    // Go through all sessions
+    iSessionIter.SetToFirst();
+    // Check notification events
+    while ( iSessionIter )
+        {
+        CSession2* session = iSessionIter;
+        iSessionIter++;
+        if ( ( ( CImpsSession* )session )->CheckNotifications( aFields, aCSP ) )
+            {
+            retVal = ETrue;
+            }
+        }
+    return retVal;
+    }
+
+// -----------------------------------------------------------------------------
+// CImpsServer::CheckExpiryL
+// -----------------------------------------------------------------------------
+void CImpsServer::CheckExpiryL(
+    TImpsEventType aType, TTime aExpiry  )
+    {
+    if ( iOrphans )
+        {
+        TInt errx = KErrNone;
+        TRAP( errx, iOrphans->CheckExpiryL() );
+        }
+    // multi: check all csp sessions
+    TDblQueIter<CImpsConn> rIter( iCSPList );
+    rIter.SetToFirst();
+    while ( rIter )
+        {
+        CImpsConn* conn = rIter;
+        rIter++;
+        conn->Sess()->CheckExpiry(  aType, aExpiry );
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CImpsServer::CheckExpiryL
+// -----------------------------------------------------------------------------
+void CImpsServer::CheckExpiryL(
+    TImpsEventType aType  )
+    {
+#ifndef _NO_IMPS_LOGGING_
+    CImpsClientLogger::Log( _L( "Server: CheckExpiryL begins" ) );
+#endif
+    TTime myExpiry;
+    myExpiry.HomeTime();
+    CheckExpiryL( aType, myExpiry );
+    }
+
+// -----------------------------------------------------------------------------
+// CImpsServer::DiscardRequests
+// -----------------------------------------------------------------------------
+void CImpsServer::DiscardRequests( TImpsEventType aType, TTime aExpiry,
+                                   TImpsSessIdent aCSP, MImpsCSPSession* aSess )
+    {
+    iSessionIter.SetToFirst();
+    while ( iSessionIter )
+        {
+        CSession2* session = iSessionIter;
+        iSessionIter++;
+        ( ( CImpsSession* )session )->DiscardRequests(
+            aExpiry,
+            aType,
+            aCSP, aSess );
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CImpsServer::DiscardRequests
+// -----------------------------------------------------------------------------
+void CImpsServer::DiscardRequests( TImpsEventType aType, TInt aError,
+                                   TImpsSessIdent aCSP, MImpsCSPSession* aSess )
+    {
+    iSessionIter.SetToFirst();
+    while ( iSessionIter )
+        {
+        CSession2* session = iSessionIter;
+        iSessionIter++;
+        ( ( CImpsSession* )session )->DiscardRequests(
+            aError,
+            aType,
+            aCSP,
+            aSess );
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CImpsServer::DiscardLogout
+// -----------------------------------------------------------------------------
+void CImpsServer::DiscardLogout(
+    const TDesC& aTID,
+    TImpsSessIdent aCSP )
+    {
+#ifndef _NO_IMPS_LOGGING_
+    CImpsClientLogger::Log( _L( "Server: DiscardLogoutL begins" ) );
+#endif
+    TUint subHandle = 0;
+    // This is a special case to handle logout error
+    // Check TID match
+    iSessionIter.SetToFirst();
+    while ( iSessionIter )
+        {
+        CSession2* session = iSessionIter;
+        iSessionIter++;
+        TInt myHit = 0;     // opId
+        // output params
+        TImpsServRequest reqType = EImpsServNone;
+        TImpsMessageType msgType = EImpsMessageNone;
+
+        // return handle of matching subsession and give it as parameter
+        subHandle = ( ( CImpsSession* )session )->CheckRequests( aTID,
+                                                                 myHit, reqType, msgType, aCSP );
+        // call SendLogoutevent
+        if ( subHandle )
+            {
+            // Send event to client
+            ( ( CImpsSession* )session )->SendLogoutEvent(
+                KErrNone, myHit, NULL, subHandle );
+
+            // Delete client request after successful event sending
+            ( ( CImpsSession* )session )->DeleteRequest( myHit, subHandle );
+            break;
+            }
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CImpsServer::HandleOrphanL
+// -----------------------------------------------------------------------------
+void CImpsServer::HandleOrphanL( CImpsFields* aFields, TImpsSessIdent aCSP )
+    {
+#ifndef _NO_IMPS_LOGGING_
+    CImpsClientLogger::Log( _L( "Server: HandleOrphanL" ) );
+#endif
+    if ( iOrphans )
+        {
+        // CSP identification
+        iOrphans->NewOrphanL( aFields, aCSP );
+        }
+    else
+        {
+        User::Leave( KErrNotSupported );
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CImpsServer::NextOrphanLC
+// -----------------------------------------------------------------------------
+CImpsFields* CImpsServer::NextOrphanLC( const TDesC& aCID,
+                                        TImpsEventType aServiceType,
+                                        TImpsSessIdent aCSP )
+    {
+#ifndef _NO_IMPS_LOGGING_
+    CImpsClientLogger::Log( _L( "Server: NextOrphanL" ) );
+#endif
+    if ( !iOrphans )
+        {
+        return NULL;
+        }
+    // CSP session and application id identification
+    return iOrphans->NextOrphanLC( aCID, aServiceType, aCSP );
+    }
+
+// -----------------------------------------------------------------------------
+// CImpsServer::HandleAllOrphans
+// -----------------------------------------------------------------------------
+void CImpsServer::HandleAllOrphans( )
+    {
+#ifndef _NO_IMPS_LOGGING_
+    CImpsClientLogger::Log( _L( "Server: HandleAllOrphans" ) );
+#endif
+    if ( !iOrphans )
+        {
+        return;
+        }
+    // loop each session
+    iSessionIter.SetToFirst();
+    while ( iSessionIter )
+        {
+        CSession2* session = iSessionIter;
+        iSessionIter++;
+        ( ( CImpsSession* )session )->HandleAllOrphans();
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CImpsServer::IsLogged
+// -----------------------------------------------------------------------------
+TBool CImpsServer::IsLogged( TImpsSessIdent aCSP, TPtrC* aPsw )
+    {
+    MImpsCSPSession* csp = GetCSP( aCSP, EFalse );
+    TBool ret =  ( csp ? csp->IsLogged() : EFalse );
+    if ( ret && aPsw )
+        {
+        aPsw->Set( csp->Password() );
+        }
+    return ret;
+    }
+
+// -----------------------------------------------------------------------------
+// CImpsServer::SID()
+// -----------------------------------------------------------------------------
+TPtrC CImpsServer::SID( TImpsSessIdent aCSP )
+    {
+    if ( aCSP.IsZero() )
+        {
+        return TPtrC();
+        }
+    else
+        {
+        MImpsCSPSession* csp = GetCSP( aCSP, EFalse );
+        return ( csp ? csp->SID() : TPtrC() );
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CImpsServer::GetCSP
+// -----------------------------------------------------------------------------
+MImpsCSPSession* CImpsServer::GetCSP( TImpsSessIdent aCSP, TBool aAll )
+    {
+    TDblQueIter<CImpsConn> rIter( iCSPList );
+    rIter.SetToFirst();
+    while ( rIter )
+        {
+        CImpsConn* conn = rIter;
+        rIter++;
+        if ( conn->MatchCSP( aCSP ) )
+            {
+            if ( ( !aAll && !conn->Sess()->IsShuttingDown() ) ||
+                 ( aAll ) )
+                {
+                return conn->Sess();
+                }
+            }
+        }
+    return NULL;
+    }
+
+// -----------------------------------------------------------------------------
+// CImpsServer::NewCSPL
+// -----------------------------------------------------------------------------
+MImpsCSPSession* CImpsServer::NewCSPL( TImpsSessIdent /*aCSP*/, TImpsCspVersion aVer )
+    {
+#ifndef _NO_IMPS_LOGGING_
+    CImpsClientLogger::Log( _L( "Server: NewCSPL" ) );
+#endif
+    CImpsCSPSession* ses = CImpsCSPSession::NewL( *this,
+                                                  iSettings, iFs, *iVariant, aVer );
+    CleanupStack::PushL( ses );
+    CImpsConn* conn = CImpsConn::NewL( ses, *this );
+    iCSPList.AddLast( *conn );
+    CleanupStack::Pop( 1 );
+    return ses;
+    }
+
+// -----------------------------------------------------------------------------
+// CImpsServer::DeleteCSP
+// -----------------------------------------------------------------------------
+void CImpsServer::DeleteCSP( MImpsCSPSession* aSess )
+    {
+#ifndef _NO_IMPS_LOGGING_
+    CImpsClientLogger::Log( _L( "Server: DeleteCSP" ) );
+#endif
+    TDblQueIter<CImpsConn> rIter( iCSPList );
+    rIter.SetToFirst();
+    while ( rIter )
+        {
+        CImpsConn* conn = rIter;
+        rIter++;
+        if ( conn->Sess() == aSess )
+            {
+            conn->Destroy();
+            break;
+            }
+        }
+    // Check also if all the client sessions are closed and if this is the
+    // last CSP session. Then start final count down.
+    if ( !NbrSessions( EFalse ) && !NbrCSPs() )
+        {
+        iOperation = EImpsSrvFinish;
+        iShutTimer->Start( KImpsShutdownTime );
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CImpsServer::DeleteCSPAsynch
+// -----------------------------------------------------------------------------
+void CImpsServer::DeleteCSPAsynch( MImpsCSPSession* aSess )
+    {
+#ifndef _NO_IMPS_LOGGING_
+    CImpsClientLogger::Log( _L( "Server: DeleteCSPAsynch" ) );
+#endif
+    TDblQueIter<CImpsConn> rIter( iCSPList );
+    rIter.SetToFirst();
+    while ( rIter )
+        {
+        CImpsConn* conn = rIter;
+        rIter++;
+        if ( conn->Sess() == aSess )
+            {
+            conn->DeleteCSPAsynch();
+            return;
+            }
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CImpsServer::CloseAllCSPs
+// -----------------------------------------------------------------------------
+void CImpsServer::CloseAllCSPs()
+    {
+#ifndef _NO_IMPS_LOGGING_
+    CImpsClientLogger::Log( _L( "Server: CloseAllCSPs" ) );
+#endif
+    TDblQueIter<CImpsConn> rIter( iCSPList );
+    rIter.SetToFirst();
+    while ( rIter )
+        {
+        CImpsConn* conn = rIter;
+        rIter++;
+        conn->Sess()->DoLogout();
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CImpsServer::NbrCSPs
+// -----------------------------------------------------------------------------
+TInt CImpsServer::NbrCSPs( )
+    {
+    TDblQueIter<CImpsConn> rIter( iCSPList );
+    rIter.SetToFirst();
+    TInt count = 0;
+    while ( rIter )
+        {
+        rIter++;
+        count++;
+        }
+    return count;
+    }
+
+// -----------------------------------------------------------------------------
+// CImpsServer::NbrSessions
+// -----------------------------------------------------------------------------
+TInt CImpsServer::NbrSessions( TBool aIgnoreCIR )
+    {
+    iSessionIter.SetToFirst();
+    TInt myRet = 0;
+
+    // Check TID match
+    while ( iSessionIter )
+        {
+        if ( aIgnoreCIR )
+            {
+            CSession2* session = iSessionIter;
+            iSessionIter++;
+            if ( !( ( CImpsSession* )session )->IsCIRWatcherSession() )
+                {
+                myRet++;
+                }
+            }
+        else
+            {
+            iSessionIter++;
+            myRet++;
+            }
+        }
+    return myRet;
+
+    }
+
+// -----------------------------------------------------------------------------
+// CImpsServer::NbrSessions
+// -----------------------------------------------------------------------------
+TInt CImpsServer::NbrSessions( TBool aIgnoreCIR, TImpsSessIdent aCSP )
+    {
+    iSessionIter.SetToFirst();
+    TInt myRet = 0;
+
+    // Check TID match
+    while ( iSessionIter )
+        {
+        CSession2* session = iSessionIter;
+        iSessionIter++;
+        if ( aIgnoreCIR )
+            {
+            if ( ( ( CImpsSession* )session )->MatchSession( aCSP ) &&
+                 !( ( CImpsSession* )session )->IsCIRWatcherSession() )
+                {
+                myRet++;
+                }
+            }
+        else if ( ( ( CImpsSession* )session )->MatchSession( aCSP ) )
+            {
+            myRet++;
+            }
+        }
+    return myRet;
+
+    }
+
+// -----------------------------------------------------------------------------
+// CImpsServer::CancelTrans
+// -----------------------------------------------------------------------------
+void CImpsServer::CancelTrans( const TDesC& aTID, TImpsSessIdent aCSP )
+    {
+    MImpsCSPSession* sess = GetCSP( aCSP, EFalse );
+    CancelTrans( aTID, sess );
+    }
+
+// -----------------------------------------------------------------------------
+// CImpsServer::CancelTrans
+// -----------------------------------------------------------------------------
+void CImpsServer::CancelTrans( const TDesC& aTID, MImpsCSPSession* aSess )
+    {
+    if ( aSess )
+        {
+        aSess->CancelTrans( aTID );
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CImpsServer::DoLogoutSrv
+// -----------------------------------------------------------------------------
+void CImpsServer::DoLogoutSrv( TInt aInt, TBool aCSPDis,
+                               MImpsCSPSession* aSess )
+    {
+    // aSess is never NULL
+    TImpsSessIdent csp( KNullDesC, aSess->SAP(), aSess->UserId() );
+    DoLogoutNow( NULL, aInt, aCSPDis, csp );
+    }
+
+// -----------------------------------------------------------------------------
+// CImpsServer::DoLogoutNow
+// -----------------------------------------------------------------------------
+void CImpsServer::DoLogoutNow( CImpsSubSession* aSub,
+                               TInt aOpId, TBool aCSPDis,
+                               TImpsSessIdent aCSP )
+    {
+
+#ifndef _NO_IMPS_LOGGING_
+    CImpsClientLogger::Log( _L( "Server: DoLogoutNow subses=%d opid=%d dis=%d" ),
+                            aSub, aOpId, aCSPDis );
+#endif
+
+    iExpiryTimer->Stop();
+
+    // Clean all pending requests from all sessions
+    // Logout response must have beed delivered
+    iSessionIter.SetToFirst();
+    // Delete requests from the corresponding client sessions only.
+    while ( iSessionIter )
+        {
+        CSession2* session = iSessionIter;
+        iSessionIter++;
+        ( ( CImpsSession* )session )->DeleteAllRequests( &aCSP );
+        }
+
+    // Call logout callback methods only if CSP did exist.
+    if ( aCSPDis )
+        {
+        // send the appropriate opid to the requesting client
+        SendLogoutEvents( aSub, aOpId, aCSP );
+        }
+
+    // Send not_logged state events. This also cleans WV CSP SID in client sessions
+    // belonging to the CSP session.
+    SendStatusEvents( EInternal_NOT_LOGGED, aCSP );
+
+    // If no sessions then start countdown
+    if ( !NbrSessions( EFalse ) && !NbrCSPs() )
+        {
+        iOperation = EImpsSrvFinish;
+        iShutTimer->Start( KImpsShutdownTime );
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CImpsServer::IsPendingLogin
+// -----------------------------------------------------------------------------
+TBool CImpsServer::IsPendingLogin( TImpsSessIdent aCSP )
+    {
+    MImpsCSPSession* csp = GetCSP( aCSP, EFalse );
+    return ( csp ? csp->IsPendingLogin() : EFalse );
+    }
+
+// -----------------------------------------------------------------------------
+// CImpsServer::ExpiryTime
+// Generate default expiry time
+// -----------------------------------------------------------------------------
+TTime CImpsServer::ExpiryTime( TImpsMessageType aMsgType )
+    {
+    TImpsEventType srv = impsService( iVariant, aMsgType );
+    return ExpiryTime( srv );
+    }
+
+// -----------------------------------------------------------------------------
+// CImpsServer::ExpiryTime
+// Generate default expiry time
+// -----------------------------------------------------------------------------
+TTime CImpsServer::ExpiryTime( TImpsEventType aSrv )
+    {
+    TInt extra = ExpirySeconds( aSrv );
+    return ExpiryTime( extra );
+    }
+
+// ---------------------------------------------------------
+// CImpsServer::ExpiryTime
+// ---------------------------------------------------------
+TTime CImpsServer::ExpiryTime( TInt aExpiry )
+    {
+    TTime time;        // time in microseconds since 0AD nominal Gregorian
+    time.HomeTime();   // set time to now
+    // add expiry seconds to the time
+    TTimeIntervalSeconds expirySeconds( aExpiry );
+    time += expirySeconds;
+    return time;
+    }
+
+// -----------------------------------------------------------------------------
+// CImpsServer::ExpirySeconds
+// Generate default expiry time
+// -----------------------------------------------------------------------------
+TInt CImpsServer::ExpirySeconds( TImpsEventType aSrv )
+    {
+    TInt extra = 0;
+
+    switch ( aSrv )
+        {
+        case EImpsEventServerLogin:
+        case EImpsEventNone:        // used for PollRequest e.g.
+            extra = iSettings.iAccessExp;
+            break;
+        case EImpsEventMessage:
+            extra = iSettings.iImExp;
+            break;
+        case EImpsEventPresence:
+        case EImpsEventPresencePure:
+        case EImpsEventPure:
+            extra = iSettings.iPrExp;
+            break;
+        case EImpsEventGroup:
+            extra = iSettings.iGrExp;
+            break;
+        case EImpsEventCommon:
+            extra = iSettings.iFuExp;
+            break;
+        default:
+            break;
+        }
+
+    return extra;
+    }
+
+// -----------------------------------------------------------------------------
+// CImpsServer::SendStatusEvents
+// -----------------------------------------------------------------------------
+void CImpsServer::SendStatusEvents( EImpsInternalStatus aStatus,
+                                    TImpsSessIdent aCSP )
+    {
+#ifndef _NO_IMPS_LOGGING_
+    CImpsClientLogger::Log( _L( "Server: SendStatusEvents begins" ) );
+#endif
+
+    iSessionIter.SetToFirst();
+
+    // Scan thru sessions and send event if they have registered an
+    // status observer
+    while ( iSessionIter )
+        {
+        CSession2* session = iSessionIter;
+        iSessionIter++;
+        if ( ( ( CImpsSession* )session )->MatchSession( aCSP ) )
+            {
+            ( ( CImpsSession* )session )->SendEvent( aStatus );
+            }
+        }
+    }
+
+// ---------------------------------------------------------
+// CImpsServer::TransportStatus
+// ---------------------------------------------------------
+//
+void CImpsServer::TransportStatus(
+    EImpsInternalStatus aConnectionState,
+    MImpsCSPSession* aSess )
+    {
+
+#ifndef _NO_IMPS_LOGGING_
+    CImpsClientLogger::Log( _L( "Server: TransportStatus=%d" ),
+                            ( TInt ) aConnectionState );
+#endif
+
+    TInt errx = KErrNone;
+    TRAP( errx, DoTransportStatusL( aConnectionState, aSess ) );
+
+#ifndef _NO_IMPS_LOGGING_
+    CImpsClientLogger::Log( _L( "Server: TransportStatus ends" ) );
+#endif
+
+    }
+
+// ---------------------------------------------------------
+// CImpsServer::DoTransportStatusL
+// ---------------------------------------------------------
+//
+void CImpsServer::DoTransportStatusL(
+    EImpsInternalStatus aConnectionState,
+    MImpsCSPSession* aSess )
+    {
+    TImpsSessIdent csp( KNullDesC, aSess->SAP(), aSess->UserId() );
+    TInt nbrSes = NbrSessions( ETrue, csp );
+
+    // Logout particular CSP session if there is no corresponding client-sessions.
+    if ( aConnectionState != EInternal_NO_IAP && !nbrSes )
+        {
+        aSess->LogoutL( EFalse );
+        return;
+        }
+    else if ( aConnectionState == EInternal_NO_IAP )
+        {
+        // start to delete CSP session asynchronously
+        DeleteCSPAsynch( aSess );
+        return;
+        }
+
+    // Send status events only if the state has changed.
+    // OFF_LINE events are not send since client API does not support them.
+    if ( aConnectionState != EInternal_OFF_LINE )
+        {
+        SendStatusEvents( aConnectionState, csp );
+        }
+    }
+
+// ---------------------------------------------------------
+// CImpsServer::BufferSize
+// ---------------------------------------------------------
+//
+TInt CImpsServer::BufferSize( )
+    {
+    return iSettings.MaximumParserSize() - KImpsBufOverhead;
+    }
+
+// ---------------------------------------------------------
+// CImpsServer::SetConnAllowed
+// ---------------------------------------------------------
+//
+void CImpsServer::SetConnAllowed( TBool aParam )
+    {
+#ifndef _NO_IMPS_LOGGING_
+    CImpsClientLogger::Log( _L( "Server: SetConnAllowed %d" ), aParam );
+#endif
+    iConAllowed = aParam;
+    // Logout internally all CSP sessions if connection not allowed
+    TDblQueIter<CImpsConn> rIter( iCSPList );
+    rIter.SetToFirst();
+    while ( rIter )
+        {
+        CImpsConn* conn = rIter;
+        rIter++;
+        conn->Sess()->SetConnAllowed( aParam );
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CImpsServer::SendErrorEvent
+// -----------------------------------------------------------------------------
+//
+void CImpsServer::SendErrorEvent(
+    TImpsEventType aType,
+    TInt aCode,
+    TInt aOpId,
+    TImpsSessIdent aCSP )
+    {
+
+#ifndef _NO_IMPS_LOGGING_
+    CImpsClientLogger::Log( _L( "Server: SendErrorEvent begins" ) );
+#endif
+    // Create error event
+    iSnd->Reset();
+    iSnd->SetStatus( aCode );
+
+    // Search proper session type for an error not response for
+    // a client request.
+    iSessionIter.SetToFirst();
+    while ( iSessionIter )
+        {
+        CSession2* session = iSessionIter;
+        iSessionIter++;
+        if ( ( ( CImpsSession* )session )->Types( ) && aType &&
+             ( ( CImpsSession* )session )->MatchSession( aCSP ) )
+            {
+            // Send event to client
+            ( ( CImpsSession* )session )->SendEvent(
+                iSnd,
+                aOpId,
+                EImpsServNone,
+                EImpsMessageNone,
+                0 );
+            }
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CImpsServer::NewContainerL
+// -----------------------------------------------------------------------------
+//
+CObjectCon* CImpsServer::NewContainerL()
+    {
+    return iContainerIndex->CreateL();
+    }
+
+// -----------------------------------------------------------------------------
+// CImpsServer::RemoveContainer
+// -----------------------------------------------------------------------------
+//
+void CImpsServer::RemoveContainer( CObjectCon* aCon )
+    {
+    iContainerIndex->Remove( aCon );
+    }
+
+
+// -----------------------------------------------------------------------------
+// CImpsServer::DiscardRequest
+// -----------------------------------------------------------------------------
+//
+void CImpsServer::DiscardRequest(
+    const TDesC& aTid, TImpsEventType aType, TInt aCode,
+    TImpsSessIdent aCSP )
+    {
+#ifndef _NO_IMPS_LOGGING_
+    CImpsClientLogger::Log( _L( "Server: DiscardRequest code=%d" ), aCode );
+#endif
+
+    iSessionIter.SetToFirst();
+    while ( iSessionIter )
+        {
+        CSession2* session = iSessionIter;
+        iSessionIter++;
+        if ( ( ( CImpsSession* )session )->DiscardRequest(
+                 aTid, aType, aCode, aCSP ) )
+            {
+            break;
+            }
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CImpsServer::SendLogoutEvents
+// -----------------------------------------------------------------------------
+//
+void CImpsServer::SendLogoutEvents( CImpsSubSession* aSub, TInt aOpId,
+                                    TImpsSessIdent aCSP )
+    {
+#ifndef _NO_IMPS_LOGGING_
+    CImpsClientLogger::Log( _L( "Server: SendLogoutEvents" ) );
+#endif
+    iSessionIter.SetToFirst();
+    while ( iSessionIter )
+        {
+        CSession2* session = iSessionIter;
+        iSessionIter++;
+        if ( ( ( CImpsSession* )session )->MatchSession( aCSP ) )
+            {
+            ( ( CImpsSession* )session )->SendLogoutEvent(
+                KErrNone, aOpId, aSub, 0 );
+            }
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CImpsServer::DoShutDown
+// -----------------------------------------------------------------------------
+//
+void CImpsServer::DoShutDown()
+    {
+#ifndef _NO_IMPS_LOGGING_
+    CImpsClientLogger::Log( _L( "Server: DoShutDown begins" ) );
+#endif
+    StopTimer();
+    if ( iOrphans )
+        {
+        iOrphans->Stop();
+        }
+
+    // Free ECOM plugins
+    REComSession::FinalClose();
+
+#ifndef _NO_IMPS_LOGGING_
+    CImpsClientLogger::Log( _L( "Server: DoShutDown ends" ) );
+#endif
+    CImpsScheduler::Stop();
+    }
+
+// -----------------------------------------------------------------------------
+// CImpsServer::IsNegotiated
+// -----------------------------------------------------------------------------
+//
+TBool CImpsServer::IsNegotiated( TImpsSessIdent aCSP )
+    {
+    MImpsCSPSession* csp = GetCSP( aCSP, EFalse );
+    if ( !csp )
+        {
+        return EFalse;
+        }
+    return csp->IsNegotiated();
+    }
+
+// -----------------------------------------------------------------------------
+// CImpsServer::Services
+// -----------------------------------------------------------------------------
+//
+TImpsServices* CImpsServer::Services( TImpsSessIdent aCSP )
+    {
+    MImpsCSPSession* csp = GetCSP( aCSP, EFalse );
+    if ( !csp )
+        {
+        return NULL;
+        }
+    return csp->Services();
+    }
+
+// -----------------------------------------------------------------------------
+// CImpsServer::TidSeed
+// -----------------------------------------------------------------------------
+//
+TInt CImpsServer::TidSeed()
+    {
+    ++iSeed;
+    if ( iSeed == KMaxTInt )
+        {
+        iSeed = 0;
+        }
+    return iSeed;
+    }
+
+// -----------------------------------------------------------------------------
+// CImpsServer::LogoutAll
+// -----------------------------------------------------------------------------
+//
+void CImpsServer::LogoutAll()
+    {
+    // Set server state as SHUTTING_DOWN
+    iOperation = EImpsSrvShuttingDown;
+
+    // Send SHUTTING_DOWN events to clients
+    iSessionIter.SetToFirst();
+
+    // Check TID match
+    while ( iSessionIter )
+        {
+        CSession2* session = iSessionIter;
+        iSessionIter++;
+        ( ( CImpsSession* )session )->SendEvent( EInternal_SHUTTING_DOWN );
+        }
+
+    // Search each CSP session logged in and logout them
+    CloseAllCSPs();
+    }
+
+// -----------------------------------------------------------------------------
+// CImpsServer::CustomSecurityCheckL
+// This is used for connect request only
+// -----------------------------------------------------------------------------
+//
+
+CPolicyServer::TCustomResult CImpsServer::CustomSecurityCheckL(
+    const RMessage2& aMsg, TInt& /*aAction*/, TSecurityInfo& /*aMissing*/ )
+    {
+    CPolicyServer::TCustomResult test;
+    if ( aMsg.HasCapability( ECapabilityNetworkServices ) )
+        {
+        test = EPass;
+        }
+    else
+        {
+        test = EFail;
+        }
+#ifndef _NO_IMPS_LOGGING_
+    CImpsClientLogger::Log( _L( "Server: CustomSecurityCheckL returns %d" ), test );
+#endif
+    return test;
+    }
+
+
+// -----------------------------------------------------------------------------
+// CImpsServer::GetCSPVersion
+// -----------------------------------------------------------------------------
+//
+void CImpsServer::GetCSPVersion()
+    {
+    // Get supported CSP WV version in the terminal.
+    // Default is 1.1 version, thus only 1.2 needs to be handled here
+    TReal ver ( 0 );
+    TRAPD( errx, ver = TImpsDataUtils::GetCenRepRealValueL(
+                           KCRUIDWVEngineVariation, KWVEngineCspVersion ) );
+    if ( !errx && ver == 1.2 )
+        {
+        iCSPVersion = EImpsCspVersion12;
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CImpsServer::SetExpiryTimer
+// -----------------------------------------------------------------------------
+//
+void CImpsServer::SetExpiryTimer( TInt aExpiry, TBool aInit )
+    {
+    // search the minimum value from Cent Rep values
+    TInt expiryInterval = iSettings.iAccessExp;
+    if ( iSettings.iFuExp < expiryInterval )
+        {
+        expiryInterval = iSettings.iFuExp;
+        }
+    if ( iSettings.iGrExp < expiryInterval )
+        {
+        expiryInterval = iSettings.iGrExp;
+        }
+    if ( iSettings.iImExp < expiryInterval )
+        {
+        expiryInterval = iSettings.iImExp;
+        }
+    if ( iSettings.iPrExp < expiryInterval )
+        {
+        expiryInterval = iSettings.iPrExp;
+        }
+    // Then compare the given value and select minimum
+    if ( aExpiry )
+        {
+        if ( aExpiry < expiryInterval )
+            {
+            expiryInterval = aExpiry;
+            }
+        }
+    if ( !iExpiryInterval || iExpiryInterval > expiryInterval )
+        {
+        iExpiryInterval = expiryInterval;
+        }
+    if ( aInit && !iExpiryTimer->IsActive() )
+        {
+        // Add 1 so that it can alwayd be divided.
+        iExpiryTimer->Start( ( iExpiryInterval + 1 ) / 2 );
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CImpsServer::ResetExpiryTimer
+// -----------------------------------------------------------------------------
+//
+void CImpsServer::ResetExpiryTimer( TInt aExpiry )
+    {
+    if ( aExpiry >= iExpiryInterval )
+        {
+        // no need to change the value
+        return;
+        }
+
+    TInt expiryInterval = 0;
+    // Do not start expiry timer if it is not runnig.
+    if ( iExpiryTimer->IsActive() )
+        {
+        // Search minimum expiry time from sub-sessions
+        TInt exp = 0;
+        while ( iSessionIter )
+            {
+            CSession2* session = iSessionIter;
+            iSessionIter++;
+            exp = ( ( CImpsSession* )session )->ExpiryTime( );
+            if ( ( exp && exp < expiryInterval ) || !expiryInterval )
+                {
+                expiryInterval = exp;
+                }
+            }
+        SetExpiryTimer( expiryInterval, EFalse );
+        }
+    }
+
+// ================= OTHER EXPORTED FUNCTIONS ==============
+
+// -----------------------------------------------------------------------------
+// ThreadFunction()
+// Needed only in WINS build
+// -----------------------------------------------------------------------------
+
+#ifdef __WINS__
+
+EXPORT_C TInt ThreadFunction( TAny* aThreadParams )
+    {
+    // increase dll's user count so it can't get unloaded when the client application
+    // terminates
+
+    RLibrary lib;
+    lib.Load( KImpsLibName ); //
+
+    return CImpsServer::ThreadStart( *( TImpsSignal* )aThreadParams );
+    }
+
+#endif
+
+
+
+
+
+
+//  End of File