PECengine/StorageManager2/ServerSrc/CPEngStorageServer.cpp
changeset 0 094583676ce7
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/PECengine/StorageManager2/ServerSrc/CPEngStorageServer.cpp	Thu Dec 17 08:41:52 2009 +0200
@@ -0,0 +1,1256 @@
+/*
+* Copyright (c) 2002 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:  Implementation of class CPEngStorageServer
+*
+*/
+
+
+//  Include Files
+#include <e32svr.h>
+#include <badesca.h>
+#include <s32mem.h>
+
+
+#include "CPEngStorageServer.h"
+#include "CPEngStorageSession.h"
+#include "CPEngStorageFolder.h"
+#include "PEngStorageServerCommon.h"
+#include "TPEngServerParams.h"
+#include "CPEngHandlerListenEvents.h"
+#include "PEngInternalGlobalConsts.h"
+#include "CPEngTimer.h"
+#include "CPEngActiveScheduler.h"
+
+// Session Slot utility
+#include "CPEngSessionSlotId.h"
+#include "CPEngSessionSlotState.h"
+#include "CPEngSessionSlotEvent.h"
+#include "RObjectArray.h"
+
+// Hash Tool
+#include "PEngHashTool.h"
+
+// Debug Prints
+#include "PresenceDebugPrint.h"
+
+
+// CONSTANTS
+
+// Init size of the buffer for client server communications
+static const TInt KBufferInitSize = 100;
+
+// Static data for Capability check configuration
+static const TInt KPEngStoreServRangeCount = 2;
+
+/**
+ * Ranges for the Request values
+ * All requests will fall in one range
+ */
+static const TInt PEngStoreServRanges[ KPEngStoreServRangeCount ] =
+    {
+    // Range from EMainSessShutdownServer to EFolderSubSessNotifyChangedSIDs
+    0,
+
+    // range is from EHighestStoreServerRequest request to KMaxInt
+    EHighestStoreServerRequest
+    };
+
+/**
+ * Element indexes for the defined ranges
+ * we have only one range and for it is defined only one Element
+ */
+static const TUint8 KPEngStoreServElementsIndex[ KPEngStoreServRangeCount ] =
+    {
+    // First element in the element array will be applied for this range
+    0,
+    // Not supported will be applied for this range
+    CPolicyServer::ENotSupported
+    };
+
+// Policy elements
+static const CPolicyServer::TPolicyElement KPEngStoreServElements[] =
+    {
+        {
+        _INIT_SECURITY_POLICY_C2( ECapabilityReadUserData,
+        ECapabilityWriteUserData ),
+        CPolicyServer::EFailClient
+        }
+    };
+
+static const CPolicyServer::TPolicy KPEngServerPolicy =
+    {
+    // The index into Elements,that is used to check a connection attempt
+
+    0,
+
+    // Number of ranges in the iRanges array
+    KPEngStoreServRangeCount,
+
+    // A pointer to an array of ordered ranges of request numbers
+    PEngStoreServRanges,
+
+    // A pointer to an array of TUint8 values specifying
+    // the appropriate action to take for each range in iRanges
+    KPEngStoreServElementsIndex,
+
+    // A pointer to an array of distinct policy elements
+    KPEngStoreServElements
+    };
+
+// MACROS
+#define RETURN_IF_ERROR( aError )\
+    if( aError != KErrNone )\
+        {\
+        return aError;\
+        }
+
+
+// ============================ MEMBER FUNCTIONS ===============================
+
+// -----------------------------------------------------------------------------
+// CPEngStorageServer::CPEngStorageServer
+// C++ default constructor can NOT contain any code, that might leave.
+// -----------------------------------------------------------------------------
+//
+CPEngStorageServer::CPEngStorageServer( TInt aPriority )
+        : CPolicyServer( aPriority, KPEngServerPolicy ),
+        iRunning( EFalse )
+    {
+    }
+
+// -----------------------------------------------------------------------------
+// CPEngStorageServer::ConstructL
+// Symbian 2nd phase constructor can leave.
+// -----------------------------------------------------------------------------
+//
+void CPEngStorageServer::ConstructL()
+    {
+    StartL( KStorageServerName );
+    iBuff16.CreateL( KBufferInitSize );
+    iBuff8.CreateL( KBufferInitSize );
+    // create container collection
+    iContainerIx = CObjectConIx::NewL();
+    iSubSessionCnt = iContainerIx->CreateL();
+    iFoldersCnt = iContainerIx->CreateL();
+    iObserversCnt = iContainerIx->CreateL();
+
+    // set up file system enviroment
+    User::LeaveIfError( iFs.Connect() );// connect to file server
+    // set session to the private folder
+    TInt err( iFs.CreatePrivatePath( EDriveC ) );
+    if ( err != KErrAlreadyExists )
+        {
+        User::LeaveIfError( err );
+        }
+    User::LeaveIfError( iFs.SetSessionToPrivate( EDriveC ) );
+    TFileName name;
+    iFs.SessionPath( name );
+    name.Append( KPEngStorageTempFolder );
+    iTempFolder = name.AllocL();
+
+    // make sure we have Storage folder, flush it first and then created
+    CFileMan* fileMan = CFileMan::NewL( iFs );
+    CleanupStack::PushL( fileMan );
+    fileMan->RmDir( *iTempFolder );
+    // ignore errors
+    iFs.Delete( *iTempFolder );
+    CleanupStack::PopAndDestroy(); // fileMan
+    // try to create temp folder
+    TInt er ( iFs.MkDirAll( *iTempFolder ) );
+    if ( er != KErrAlreadyExists )
+        {
+        User::LeaveIfError( er );
+        }
+    }
+
+
+// -----------------------------------------------------------------------------
+// CPEngStorageServer::NewLC
+// Two-phased constructor.
+// -----------------------------------------------------------------------------
+//
+CPEngStorageServer* CPEngStorageServer::NewL( TInt aPriority )
+    {
+    CPEngStorageServer* self = CPEngStorageServer::NewLC( aPriority );
+    CleanupStack::Pop();
+
+    return self;
+    }
+
+// -----------------------------------------------------------------------------
+// CPEngStorageServer::NewLC
+// Two-phased constructor.
+// -----------------------------------------------------------------------------
+//
+CPEngStorageServer* CPEngStorageServer::NewLC(  TInt aPriority )
+    {
+    CPEngStorageServer* self = new( ELeave ) CPEngStorageServer( aPriority );
+    CleanupStack::PushL( self );
+    self->ConstructL();
+    return self;
+    }
+
+// Destructor (virtual by CBase)
+CPEngStorageServer::~CPEngStorageServer()
+    {
+    // clean all containers from the objects in it
+    // close all elements of the array
+    if ( iFoldersCnt )
+        {
+        for ( TInt x( iFoldersCnt->Count() - 1 ) ; x >= 0  ; --x )
+            {
+            ( *iFoldersCnt )[ x ]->Close();
+            }
+        }
+
+
+    // close all elements of the array
+    if ( iObserversCnt )
+        {
+        for ( TInt y( iObserversCnt->Count() - 1 ) ; y >= 0  ; --y )
+            {
+            ( *iObserversCnt )[ y ]->Close();
+            }
+        }
+
+    // all containers are deleted with the collection
+    delete iContainerIx;
+    // clean file enviroment
+    iFs.Close();
+    delete iTempFolder;
+    // shut down plugin server
+    delete iTimeOut;
+    iBuff16.Close();
+    iBuff8.Close();
+    }
+
+
+// =============================================================================
+// =============== Functions from base class ===================================
+// =============================================================================
+
+
+// -----------------------------------------------------------------------------
+// CPEngStorageServer::ExecuteServerL()
+// -----------------------------------------------------------------------------
+//
+TInt CPEngStorageServer::ExecuteServerL( TPEngServerParams& aParams )
+    {
+    //Renaming must be done as early as possible
+    aParams.RenameMainThread( KStorageServerName );
+
+    TInt res( KErrNone );
+
+    // start scheduler and server
+    CPEngActiveScheduler* pA = new( ELeave )CPEngActiveScheduler;
+    CleanupStack::PushL( pA );
+    CPEngActiveScheduler::Install( pA );
+
+    //If exe server, call RunServerL directly.
+    TRAP( res, RunServerL( aParams ) );
+
+    CPEngActiveScheduler::Install( NULL );
+    CleanupStack::PopAndDestroy();//pA
+    return res;
+    }
+
+
+
+// -----------------------------------------------------------------------------
+// CPEngStorageServer::StopServer()
+// -----------------------------------------------------------------------------
+//
+void CPEngStorageServer::StopServer()
+    {
+    if ( iRunning )
+        {
+        CPEngActiveScheduler::Stop();
+        }
+    iRunning = EFalse;
+    }
+
+
+
+// -----------------------------------------------------------------------------
+// CPEngStorageServer::RunServerL()
+// -----------------------------------------------------------------------------
+//
+void CPEngStorageServer::RunServerL( TPEngServerParams& aParams )
+    {
+    PENG_DP( D_PENG_LIT( "CPEngStorageServer::RunServerL()" ) );
+
+    //One instance of server must be allocated here.
+    CPEngStorageServer* server = CPEngStorageServer::NewLC( KServerPriority );
+
+    //must die if can't signal client
+    aParams.Signal();
+    // start fielding requests from clients
+    //Thread is ended when CPEngActiveScheduler::Stop is called.
+    server->StartServer();
+
+
+    CleanupStack::PopAndDestroy();//server
+    // finished
+    }
+
+
+// =============================================================================
+// =============== Functions from the MPEngStorageServer class =================
+// =============================================================================
+
+// -----------------------------------------------------------------------------
+// CPEngStorageServer::AddSubSessionL()
+// -----------------------------------------------------------------------------
+//
+void CPEngStorageServer::AddSubSessionL(
+    CObject& aSubSession )
+    {
+    iSubSessionCnt->AddL( &aSubSession );
+    }
+
+// -----------------------------------------------------------------------------
+// CPEngStorageServer::RemoveSubSessionL()
+// -----------------------------------------------------------------------------
+//
+void CPEngStorageServer::RemoveSubSessionL(
+    CObject& aSubSession )
+    {
+    iSubSessionCnt->Remove( & aSubSession );
+    }
+
+// -----------------------------------------------------------------------------
+// CPEngStorageServer::RegisterGlobEventListenerL()
+// -----------------------------------------------------------------------------
+//
+void CPEngStorageServer::RegisterGlobEventListenerL(
+    const RPEngMessage& /* aMessage */,
+    TUint32 aSessionId )
+    {
+    CPEngHandlerListenEvents* reqHandler = FindRequestHandler( aSessionId ,
+                                                               EMainSessListenGlobalEvents );
+    if ( reqHandler )
+        {
+        // this handler already exists, not allowed by multiple
+        User::Leave( KErrAlreadyExists );
+        }
+    // create new handler
+    reqHandler = CPEngHandlerListenEvents::NewLC( aSessionId );
+    iObserversCnt->AddL( reqHandler );
+    CleanupStack::Pop(); // newHandler
+    }
+
+
+// -----------------------------------------------------------------------------
+// CPEngStorageServer::CancelRequestL()
+// -----------------------------------------------------------------------------
+//
+void CPEngStorageServer::CancelRequestL(
+    const RPEngMessage& aMessage,
+    TUint32 aSessionId )
+    {
+    CPEngRequestHandler* reqHandler = FindRequestHandler( aSessionId,
+                                                          static_cast<TPEngStorageServerMessages> ( aMessage.Int0() ) );
+    // ignore if such a request does not exists
+    if ( reqHandler )
+        {
+        reqHandler->CancelRequestD();
+        }
+    }
+
+
+// -----------------------------------------------------------------------------
+// CPEngStorageServer::CancelRequestL()
+// -----------------------------------------------------------------------------
+//
+void CPEngStorageServer::CancelAllSessionRequests(
+    TUint32 aSessionId )
+    {
+    for ( TInt x( iObserversCnt->Count() - 1 ) ;  x >= 0  ; --x )
+        {
+        CPEngRequestHandler* handler = static_cast<CPEngRequestHandler*>( ( *iObserversCnt )[ x ] );
+        if ( handler->SessionId() == aSessionId )
+            {
+            handler->CancelRequestD();
+            }
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CPEngStorageServer::ReloadAsynchronousScoutL()
+// Reload Asynchronous scout of the async observer
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+void CPEngStorageServer::ReloadAsynchronousScoutL(
+    const RPEngMessage& aMessage,
+    TUint32 aSessionId )
+    {
+    CPEngRequestHandler* reqHandler = FindRequestHandler( aSessionId,
+                                                          static_cast<TPEngStorageServerMessages> ( aMessage.Int0() ) );
+    if ( !reqHandler )
+        {
+        // there is not such a request to be reloaded
+        User::Leave( KErrArgument );
+        }
+    reqHandler->ReloadScoutWithNewMessageL( aMessage );
+    }
+
+
+// -----------------------------------------------------------------------------
+// CPEngStorageServer::CreateSessionFolderL()
+// -----------------------------------------------------------------------------
+//
+void CPEngStorageServer::CreateSessionFolderL(
+    const RPEngMessage& aMessage )
+    {
+    CPEngSessionSlotId* sessId = TranslateSessionIdLC( aMessage );
+    CPEngSessionSlotState* state = NULL;
+    CPEngStorageFolder* folder = NULL;
+    HBufC* stateFile = NULL;
+    // load state
+    TInt cleanUp ( LoadSessionStateLCX( *sessId, ETrue,
+                                        state, folder, stateFile ) );
+
+    // update state with the new application ID
+    aMessage.ReadOneDescriptorL( KMessageSlot1, iBuff16 );
+
+    // also create session slot global event for notification
+    CPEngSessionSlotEvent* globEvent =  PackGlobEventLC( *state,
+                                                         EPEngEventNWSessionSlotCreated,
+                                                         iBuff16 );
+
+    TPtr stateFileName( stateFile->Des() );
+    UpdateSessionSltStateL( folder, *state, *globEvent, stateFileName );
+
+    // notify about event
+    globEvent->PackEventL( iBuff8 );
+    NotifyGlobalEvent( iBuff8 );
+
+    // clean globEvent, (state), stateFile, sessId
+    CleanupStack::PopAndDestroy( 2 + cleanUp );
+    }
+
+
+// -----------------------------------------------------------------------------
+// CPEngStorageServer::RemoveSessionFolderL()
+// -----------------------------------------------------------------------------
+//
+void CPEngStorageServer::RemoveSessionFolderL(
+    const RPEngMessage& aMessage )
+    {
+    CPEngSessionSlotId* sessId = TranslateSessionIdLC( aMessage );
+    CPEngSessionSlotState* state = NULL;
+    CPEngStorageFolder* folder = NULL;
+    HBufC* stateFile = NULL;
+    // load state
+    TInt cleanUp ( LoadSessionStateLCX( *sessId,
+                                        EFalse,
+                                        state,
+                                        folder,
+                                        stateFile ) );
+
+    if ( folder )
+        {
+        // folder is active, refuse any deletion
+        User::Leave( KErrInUse );
+        }
+    // remove registered ID from the session
+    aMessage.ReadOneDescriptorL( KMessageSlot1, iBuff16 );
+
+    // also create session slot global event for notification
+    CPEngSessionSlotEvent* globEvent =  PackGlobEventLC(
+                                            *state,
+                                            EPEngEventNWSessionSlotRemoved,
+                                            iBuff16 );
+
+    TPtr stateFileName( stateFile->Des() );
+    UpdateSessionSltStateL( folder, *state, *globEvent, stateFileName );
+
+    // notify about event
+    globEvent->PackEventL( iBuff8 );
+    NotifyGlobalEvent( iBuff8 );
+
+    // clean globEvent, (state), stateFile, sessId
+    CleanupStack::PopAndDestroy( 2 + cleanUp );
+    }
+
+
+// -----------------------------------------------------------------------------
+// CPEngStorageServer::SessionStateL()
+// -----------------------------------------------------------------------------
+//
+void CPEngStorageServer::SessionStateL(
+    const RPEngMessage& aMessage )
+    {
+    CPEngSessionSlotId* sessId = TranslateSessionIdLC( aMessage );
+    CPEngStorageFolder* folder = FindStorageFolder( *sessId );
+    CPEngSessionSlotState* state = NULL;
+    if ( folder )
+        {
+        state = &( folder->SessionSlotState() );
+        }
+    else
+        {
+        HBufC* stateFile = NULL;
+        state = ReadSessionStatePermanentLC( *sessId, stateFile );
+        }
+
+    state->PackDataL( EPureState, iBuff8 );
+
+    TInt err( aMessage.WriteOneDescriptor( KMessageSlot1, iBuff8 ) );
+    if ( err == KErrOverflow )
+        {
+        User::Leave( iBuff8.Length() );
+        }
+    User::LeaveIfError( err );
+
+    if ( !folder )
+        {
+        CleanupStack::PopAndDestroy( 2 ); // state, stateFile
+        }
+    CleanupStack::PopAndDestroy(); // sessId
+    }
+
+
+
+// -----------------------------------------------------------------------------
+// CPEngStorageServer::AllSessionStatesL()
+// -----------------------------------------------------------------------------
+//
+void CPEngStorageServer::AllSessionStatesL(
+    const RPEngMessage& aMessage )
+    {
+    // pack all states to one big buffer
+    // this takes all active folders and adds sessions not active
+    CDir* dirList = NULL;
+    TFileName dir;
+    User::LeaveIfError( iFs.PrivatePath( dir ) );
+    // insert drive leter on the beginning
+    dir.Insert( 0, KPEngStorageDrive );
+
+    User::LeaveIfError( iFs.GetDir( dir,
+                                    KEntryAttNormal,
+                                    ESortByName,
+                                    dirList ) );
+    CleanupStack::PushL( dirList );
+    TInt count( dirList->Count() );
+    RObjectArray<CPEngSessionSlotState> states;
+    CleanupClosePushL( states );
+    // 4 for the count of the states
+    TInt size( 4 );
+    for ( TInt x( 0 ) ; x < count  ; x++ )
+        {
+        const TEntry& entry = ( *dirList )[ x ];
+        if ( ! entry.IsDir() )
+            {
+            CPEngSessionSlotState* state = CPEngSessionSlotState::NewLC();
+            ReadFileL( entry.iName, iBuff8 );
+            state->UnpackDataL( iBuff8, EPermanentData );
+            states.AppendL( state );
+            size += state->Size( EPermanentData );
+            CleanupStack::Pop(); // state
+            }
+        }
+    // now go through all session and if they are loaded as folders
+    // and pack them to the buffer
+    // get buffer for transfer
+    CBufFlat* buf = CBufFlat::NewL( size );
+    CleanupStack::PushL( buf );
+    RBufWriteStream ws;
+    CleanupClosePushL( ws );
+    ws.Open( *buf );                            // CSI: 65 #
+
+    // write count of all sessions
+    count = states.Count();
+    ws.WriteInt32L( count );
+
+    for ( TInt i( 0 ) ; i < count ; i++ )
+        {
+        CPEngStorageFolder* folder = FindStorageFolder(
+                                         states[ i ]->SessionSlotId() );
+        if ( folder )
+            {
+            // there is loaded folder, take state from there
+            folder->SessionSlotState().ExternalizeL( ws, EWholeState );
+            }
+        else
+            {
+            states[ i ]->ExternalizeL( ws, EWholeState );
+            }
+        }
+    // write data to the client side
+    TInt err( aMessage.WriteOneDescriptor( KMessageSlot0, buf->Ptr( 0 ) ) );
+    if ( err == KErrOverflow )
+        {
+        User::Leave( buf->Ptr( 0 ).Length() );
+        }
+    User::LeaveIfError( err );
+    CleanupStack::PopAndDestroy( 4 ); // ws, buf, states, dirList,
+    }
+
+
+// -----------------------------------------------------------------------------
+// CPEngStorageServer::StorageFolderL()
+// -----------------------------------------------------------------------------
+//
+CPEngStorageFolder* CPEngStorageServer::StorageFolderL(
+    const RPEngMessage& aMessage )
+    {
+    CPEngSessionSlotId* sessId = TranslateSessionIdLC( aMessage );
+    CPEngStorageFolder* folder = LoadStorageFolderL( *sessId );
+    CleanupStack::PopAndDestroy(); // sessId
+    return folder;
+    }
+
+
+// -----------------------------------------------------------------------------
+// CPEngStorageServer::NotifyGlobalEvent()
+// -----------------------------------------------------------------------------
+//
+void CPEngStorageServer::NotifyGlobalEvent(
+    const TDesC8& aGlobalEvent )
+    {
+    // better to go through array from end
+    for ( TInt x( iObserversCnt->Count() - 1 ) ; x >= 0 ; x-- )
+        {
+        CPEngHandlerListenEvents* handler =
+            static_cast<CPEngHandlerListenEvents*>( ( *iObserversCnt )[ x ] );
+        handler->NotifyEvent( aGlobalEvent );
+        }
+    }
+
+
+// -----------------------------------------------------------------------------
+// CPEngStorageServer::NotifyError()
+// -----------------------------------------------------------------------------
+//
+void CPEngStorageServer::NotifyError(
+    TInt aError )
+    {
+    // better to go through array from end
+    for ( TInt x( iObserversCnt->Count() - 1 ) ; x >= 0 ; x-- )
+        {
+        CPEngHandlerListenEvents* handler =
+            static_cast<CPEngHandlerListenEvents*>( ( *iObserversCnt )[ x ] );
+        handler->NotifyError( aError );
+        }
+    }
+
+
+// -----------------------------------------------------------------------------
+// CPEngStorageServer::IsAppIdRegisteredL()
+// -----------------------------------------------------------------------------
+//
+void CPEngStorageServer::IsAppIdRegisteredL(
+    const RPEngMessage& aMessage )
+    {
+    CPEngSessionSlotId* sessId = TranslateSessionIdLC( aMessage );
+    aMessage.ReadOneDescriptorL( KMessageSlot1, iBuff16 );
+
+    CPEngSessionSlotState* state = NULL;
+    CPEngStorageFolder* folder = NULL;
+    HBufC* stateFile = NULL;
+    // load state
+    TInt cleanUp ( LoadSessionStateLCX( *sessId, ETrue,
+                                        state, folder, stateFile ) );
+    // check if appId is registered
+    state->ApplicationRegisteredL( iBuff16 );
+    // clean (state),stateFile,appId,sessId
+    CleanupStack::PopAndDestroy( cleanUp + 2 );
+    }
+
+
+// -----------------------------------------------------------------------------
+// CPEngStorageServer::BackUpActive()
+// -----------------------------------------------------------------------------
+//
+TBool CPEngStorageServer::BackUpActive()
+    {
+    return iBackUpActive;
+    }
+
+
+// -----------------------------------------------------------------------------
+// CPEngStorageServer::WipeSessionSlotFolderL()
+// -----------------------------------------------------------------------------
+//
+void CPEngStorageServer::WipeSessionSlotFolderL(
+    const RPEngMessage& aMessage )
+    {
+    CPEngSessionSlotId* sessId = TranslateSessionIdLC( aMessage );
+    CPEngSessionSlotState* state = NULL;
+    CPEngStorageFolder* folder = NULL;
+    HBufC* stateFile = NULL;
+    // load state
+    TInt cleanUp ( LoadSessionStateLCX( *sessId,
+                                        EFalse,
+                                        state,
+                                        folder,
+                                        stateFile ) );
+
+    if ( folder )
+        {
+        // folder is active, refuse any deletion
+        User::Leave( KErrInUse );
+        }
+
+    TPtr stateFileName( stateFile->Des() );
+    User::LeaveIfError( CleanStorageFromSessionL( stateFileName ) );
+
+    // clean  globEvent, (state), stateFile, sessId
+    CleanupStack::PopAndDestroy( 1 + cleanUp );
+    }
+
+
+// =============================================================================
+// ======== New function of the CPEngStorageServer =====================
+// =============================================================================
+
+
+// -----------------------------------------------------------------------------
+// CPEngStorageServer::SessionCreated()
+// Session has been created
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+void CPEngStorageServer::SessionCreated()
+    {
+    iSessCount++;
+    }
+
+
+// -----------------------------------------------------------------------------
+// CPEngStorageServer::SessionDied()
+// -----------------------------------------------------------------------------
+//
+void CPEngStorageServer::SessionDied()
+    {
+    iSessCount--;
+    if ( iSessCount == 0 )
+        {
+        //  Start timer
+        delete iTimeOut;
+        iTimeOut = NULL;
+
+        TRAP_IGNORE(
+            {
+            iTimeOut = CPEngTimer::NewL( *this );
+            iTimeOut->After( KServerCloseTimeOut );
+            } );
+        }
+    }
+
+
+// -----------------------------------------------------------------------------
+// CPEngStorageServer::TimeExpired()
+// -----------------------------------------------------------------------------
+//
+void CPEngStorageServer::TimeExpired()
+    {
+    if ( iSessCount == 0 )
+        {
+        // stop server
+        StopServer();
+        }
+    }
+
+
+// =============================================================================
+// =============== Functions from the MBackupOperationObserver class ===========
+// =============================================================================
+
+// -----------------------------------------------------------------------------
+// CPEngStorageServer::HandleBackupOperationEventL()
+// Called when a backup or restore operation either starts or ends.
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+// Restore is not implemented before new API won't be delivered
+/*
+void CPEngStorageServer::HandleBackupOperationEventL(
+                        const TBackupOperationAttributes& aBackupOperationAttributes)
+    {
+    }
+*/
+// =============================================================================
+// =============== Functions from the CServer2 class ===========================
+// =============================================================================
+
+// -----------------------------------------------------------------------------
+// CPEngStorageServer::NewSessionL()
+// -----------------------------------------------------------------------------
+//
+CSession2* CPEngStorageServer::NewSessionL(
+    const TVersion &aVersion,
+    const RMessage2& /*aMessage*/ ) const
+    {
+    if ( !User::QueryVersionSupported( aVersion, TVersion(
+                                           KRequiredVersionMajor,
+                                           KRequiredVersionMinor,
+                                           KRequiredVersionBuild ) ) )
+        {
+        User::Leave( KErrNotSupported );
+        }
+
+    return CPEngStorageSession::NewL( const_cast<CPEngStorageServer&>( *this ) );
+    }
+
+
+// =============================================================================
+// =============== New Private methods from class ==============================
+// =============================================================================
+
+// -----------------------------------------------------------------------------
+// CPEngStorageServer::StartServer()
+// Start Server
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+void CPEngStorageServer::StartServer()
+    {
+    iRunning = ETrue;
+    PENG_DP( D_PENG_LIT( "PECStorageServer::Started" ) );
+    CPEngActiveScheduler::Start();
+    PENG_DP( D_PENG_LIT( "PECStorageServer::Stopped" ) );
+    }
+
+
+// -----------------------------------------------------------------------------
+// CPEngStorageServer::TranslateSessionIdLC()
+// Read Session ID from the client's message
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+CPEngSessionSlotId* CPEngStorageServer::TranslateSessionIdLC(
+    const RPEngMessage& aMessage )
+    {
+    // 0 slot of the message has always session identification if required
+    CPEngSessionSlotId* sessId = CPEngSessionSlotId::NewLC();
+
+    aMessage.ReadOneDescriptorL( KMessageSlot0, iBuff8 );
+    sessId->UnPackL( iBuff8 );
+    return sessId;
+    }
+
+
+// -----------------------------------------------------------------------------
+// CPEngStorageServer::FindStorageFolder()
+// Try to find session Folder if it is active
+// if folder is not active, it returns NULL pointer
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+CPEngStorageFolder* CPEngStorageServer::FindStorageFolder(
+    const CPEngSessionSlotId& aSessionId )
+    {
+    // look for the session
+    TInt count( iFoldersCnt->Count() );
+    for ( TInt x( 0 ) ; x < count ; x++ )
+        {
+        CPEngStorageFolder* folder =
+            static_cast<CPEngStorageFolder*> ( ( *iFoldersCnt )[ x ] );
+        if ( KErrNone == folder->SessionSlotState().SessionSlotId().Match( aSessionId ) )
+            {
+            return  folder;
+            }
+        }
+    return NULL;
+    }
+
+
+// -----------------------------------------------------------------------------
+// CPEngStorageServer::LoadStorageFolderL()
+// Load storage folder,
+// there is open handle to the returner pointer
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+CPEngStorageFolder* CPEngStorageServer::LoadStorageFolderL(
+    const CPEngSessionSlotId& aSessionId )
+    {
+    CPEngStorageFolder* folder = FindStorageFolder( aSessionId );
+    if ( folder )
+        {
+        TInt val = folder->Open();             // CSI: 65 #
+        return folder;
+        }
+
+    // read session state from permanent store
+    HBufC* stateFile = NULL;
+    CPEngSessionSlotState* state = ReadSessionStatePermanentLC( aSessionId,
+                                                                stateFile );
+
+    // it makes directory if does not exists
+    TPtr fileName = stateFile->Des();
+    UpdateFileToFolderName( fileName );
+
+    // create folder class, pass state
+    CPEngStorageFolder* newFolder = CPEngStorageFolder::NewL( iFs,
+                                                              *iTempFolder,
+                                                              iBuff16 );
+    CleanupClosePushL( *newFolder );
+
+    // update Folder path to include, session part
+    TFileName sessPath;
+    User::LeaveIfError( iFs.SessionPath( sessPath ) );
+    stateFile = stateFile->ReAllocL( stateFile->Length() +
+                                     sessPath.Length() );
+    stateFile->Des().Insert( 0, sessPath );
+
+    CleanupStack::Pop(); //newFolder
+    CleanupStack::Pop( 2 ); // state, stateFile
+
+    // following functions are transfering ownership
+    newFolder->SetSessionSlotState( *state );
+    newFolder->SetSessionFolder( * stateFile );
+
+    // add folder to the folders container
+    CleanupClosePushL( * newFolder );
+    iFoldersCnt->AddL( newFolder );
+    CleanupStack::Pop(); // newFolder
+    return newFolder;
+    }
+
+
+// -----------------------------------------------------------------------------
+// CPEngStorageServer::LoadSessionStateLCX()
+// Load session slot state
+// If there is Storage folder for this session
+// then state is taken from it, while nothing is put on clean up stack
+// if not, then state is loaded from state file,
+// if file does not exist, depends on the aCreate flag, can be
+// created or it leave with KErrNotFound
+// order items on clan up stack is: aStateFileName,
+// or aStateFileName, aSessState
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+TInt CPEngStorageServer::LoadSessionStateLCX(
+    CPEngSessionSlotId& aSessId,
+    TBool aCreate,
+    CPEngSessionSlotState*& aSessState,
+    CPEngStorageFolder*& aStorageFolder,
+    HBufC*& aStateFileName )
+    {
+    aStorageFolder = FindStorageFolder( aSessId );
+    // was state folder found or not
+    if ( aStorageFolder )
+        {
+        aSessState = &( aStorageFolder->SessionSlotState() );
+        aStateFileName = PEngHashTool::HashStateNameL(              // CSI: 42 #
+                             aSessState->SessionSlotId().ServiceAddress(),
+                             aSessState->SessionSlotId().UserId() );
+        CleanupStack::PushL( aStateFileName );                      // CSI: 42 #
+        return 1;
+        }
+    if ( !aCreate )
+        {
+        aSessState = ReadSessionStatePermanentLC( aSessId, aStateFileName );    // CSI: 42 #
+        return 2;
+        }
+
+    // if it won't exist create it, so we need to trap leave
+    TRAPD( e,
+        {
+        aSessState = ReadSessionStatePermanentLC( aSessId,
+        aStateFileName );
+        // we need to fool TRAP CleanUp level check
+        CleanupStack::Pop( 2 );
+        } );
+
+    // put those elements back to CleanUpStack
+    if ( e == KErrNone )
+        {
+        CleanupStack::PushL( aStateFileName );                      // CSI: 42 #
+        CleanupStack::PushL( aSessState );                          // CSI: 42 #
+        }
+
+    // does even the file exist?
+    else if ( e == KErrNotFound )
+        {
+        // file does not exists, create state file and folder
+        aStateFileName = PEngHashTool::HashStateNameL( aSessId.ServiceAddress(),    // CSI: 42 #
+                                                       aSessId.UserId() );
+        CleanupStack::PushL( aStateFileName );                      // CSI: 42 #
+        aSessState = CPEngSessionSlotState::NewLC();                // CSI: 42 #
+        aSessState->SetSessionSlotId( aSessId, EFalse );
+        TPtr fileName = aStateFileName->Des();
+        CreateSessionDirectoryL( fileName );                        // CSI: 42 #
+        }
+    else
+        {
+        // was there some other error?
+        User::LeaveIfError( e );                                    // CSI: 42 #
+        }
+    return 2;
+    }
+
+
+// -----------------------------------------------------------------------------
+// CPEngStorageServer::ReadSessionStatePermanentLC()
+// Read State file from permanent store if it does exists
+// Function returns Session Slot state and des buffer with
+// session slot state file name ownership of both is transfered
+// to the calling client
+// both items are left on clean up stack, while state is topest one
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+CPEngSessionSlotState* CPEngStorageServer::ReadSessionStatePermanentLC(
+    const CPEngSessionSlotId& aSessionId,
+    HBufC*& aFileName )
+    {
+    // Folder is not activated yet, check if folder does exist in the store
+    // get folder name of the session
+    aFileName = PEngHashTool::HashStateNameL(
+                    aSessionId.ServiceAddress(),
+                    aSessionId.UserId() );
+    CleanupStack::PushL( aFileName );
+
+    // try to get state of the session if it exists
+    CPEngSessionSlotState* state = CPEngSessionSlotState::NewLC();
+    ReadFileL( *aFileName, iBuff8 );
+    state->UnpackDataL( iBuff8, EPermanentData );
+    return state;
+    }
+
+
+// -----------------------------------------------------------------------------
+// CPEngStorageServer::UpdateFileToFolderName()
+// Modify State file name to folder name
+// Functions remove state suffix from file name and replaces is with
+// folder delimiter characters
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+void CPEngStorageServer::UpdateFileToFolderName(
+    TDes& aFileName )
+    {
+    aFileName.SetLength( aFileName.Length() -
+                         KPEngStorageStateSuffix().Length() );
+    aFileName.Append( KDirDelim );
+    }
+
+
+// -----------------------------------------------------------------------------
+// CPEngStorageServer::CreateSessionDirectoryL()
+// Create session directory in the file system
+// Passed buffer is used, modified to sued session folder
+// and then back to the state as it was before
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+void CPEngStorageServer::CreateSessionDirectoryL(
+    TDes& aFileName )
+    {
+    // make directory if does not exists
+    UpdateFileToFolderName( aFileName );
+    TFileName folderName;
+    iFs.SessionPath( folderName );
+    folderName.Append( aFileName );
+    TInt err( iFs.MkDirAll( folderName ) );
+    // ignore KErrAlreadyExist
+    err = ( err == KErrAlreadyExists ? KErrNone : err );
+    User::LeaveIfError( err );
+    // modify folder name back to the state file name
+    aFileName.SetLength( aFileName.Length() - KDirDelimLength );
+    aFileName.Append( KPEngStorageStateSuffix );
+    }
+
+
+// -----------------------------------------------------------------------------
+// CPEngStorageServer::StoreFile()
+// Store data to the file
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+TInt CPEngStorageServer::StoreFile(
+    const TDesC& aFileName,
+    const TDesC8& aData )
+    {
+    // open temp file, write date into it and rename it to the correct file
+    RFile temp;
+    TFileName fName;
+    TInt err( temp.Temp( iFs, *iTempFolder, fName, EFileShareExclusive ) );
+    RETURN_IF_ERROR( err );
+    err = temp.Write( aData );
+    if ( ( err != KErrNone ) )
+        {
+        temp.Close();
+        return err;
+        }
+    err = temp.Flush();
+    temp.Close();
+    RETURN_IF_ERROR( err );
+
+    err = iFs.Delete( aFileName );
+    if ( ( err != KErrNone ) && ( err != KErrNotFound ) )
+        {
+        return err;
+        }
+    return iFs.Rename( fName, aFileName );
+    }
+
+
+// -----------------------------------------------------------------------------
+// CPEngStorageServer::ReadFileL()
+// Read data from the file
+// if file does not exists function will leave
+// returned buffer is left on the clean up stack
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+void CPEngStorageServer::ReadFileL(
+    const TDesC& aFileName,
+    RBuf8& aBuff )
+    {
+    RFile f;
+    User::LeaveIfError( f.Open( iFs, aFileName, EFileRead ) );
+    CleanupClosePushL( f );
+    TInt size( 0 );
+    User::LeaveIfError( f.Size( size ) );
+    if ( size > aBuff.MaxSize() )
+        {
+        aBuff.ReAllocL( size );
+        }
+    aBuff.Zero();
+    User::LeaveIfError( f.Read( aBuff ) );
+    CleanupStack::PopAndDestroy(); // f
+    }
+
+
+// -----------------------------------------------------------------------------
+// CPEngStorageServer::CleanStorageFromSessionL()
+// Clean storage from session
+// Function deletes session folder and session state
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+TInt CPEngStorageServer::CleanStorageFromSessionL( TDes& aFileName )
+    {
+    // delete directory
+    UpdateFileToFolderName( aFileName );
+    TFileName sessionFolder;
+    iFs.SessionPath( sessionFolder );
+    sessionFolder.Append( aFileName );
+
+    CFileMan* fileMan = CFileMan::NewL( iFs );
+    CleanupStack::PushL( fileMan );
+    TInt err( fileMan->RmDir( sessionFolder ) );
+    CleanupStack::PopAndDestroy(); // fileMan
+    RETURN_IF_ERROR( err );
+
+    // modify folder name back to the state file name
+    aFileName.SetLength( aFileName.Length() - KDirDelimLength );
+    aFileName.Append( KPEngStorageStateSuffix );
+
+    // try to delete file
+    return iFs.Delete( aFileName );
+    }
+
+
+// -----------------------------------------------------------------------------
+// CPEngStorageServer::PackGlobEventLC()
+// Create Buffer with global event from the passed
+// state and event enumeration, and application Id
+// Function deletes session folder and session state
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+CPEngSessionSlotEvent* CPEngStorageServer::PackGlobEventLC(
+    CPEngSessionSlotState& aState,
+    TPEngNWSessionSlotEvent aEvent,
+    const TDesC& aAppId )
+    {
+    CPEngSessionSlotEvent* newEvent = CPEngSessionSlotEvent::NewLC();
+    newEvent->SetSessionSlotId( &( aState.SessionSlotId() ), EFalse );
+    newEvent->SetAppIdL( aAppId );
+    newEvent->SetSessSltEvent( aEvent );
+    newEvent->SetAppSessSltState( aState.AppState( aAppId ) );
+    newEvent->SetGlobSessSltState( aState.SessionSlotState() );
+    return newEvent;
+    }
+
+
+// -----------------------------------------------------------------------------
+// CPEngStorageServer::UpdateSessionSltStateL()
+// Update Session Slot state
+// Passed session slot folder pointer can be NULL, then
+// session slot state reference is used instead
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+void CPEngStorageServer::UpdateSessionSltStateL(
+    CPEngStorageFolder* aFolder,
+    CPEngSessionSlotState& aState,
+    CPEngSessionSlotEvent& aEvent,
+    TDes& aFileName )
+    {
+    // do we need to do permanent store update?
+    if ( aState.UpdateStateL( aEvent ) )
+        {
+        // store changes
+        aState.PackDataL( EPermanentData, iBuff8 );
+
+        // open file and store there data
+        TInt e ( StoreFile( aFileName, iBuff8 ) );
+        if ( e != KErrNone )
+            {
+            // remove the ID from the sate, this is for case folder is active
+            aState.RollBackLastUpdate();
+            User::Leave( e );
+            }
+        }
+    aState.CommitLastUpdate();
+    if ( aFolder )
+        {
+        aFolder->CommiteStateUpdate();
+        }
+
+    // shall we clean storage?
+    if ( aState.RegisteredApplications().MdcaCount() == KErrNone )
+        {
+        CleanStorageFromSessionL( aFileName );
+        }
+    }
+
+
+
+// =============================================================================
+// ============= New notification engine functions =============================
+// =============================================================================
+
+// -----------------------------------------------------------------------------
+// CPEngStorageServer::FindRequestHandler()
+// Find Request Handler
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+CPEngHandlerListenEvents* CPEngStorageServer::FindRequestHandler(
+    TUint32 aSessionId,
+    TPEngStorageServerMessages aFunction )
+    {
+    TInt count( iObserversCnt->Count() );
+    for ( TInt x( 0 ) ; x < count ; x++ )
+        {
+        CPEngHandlerListenEvents* reqHandler = static_cast<CPEngHandlerListenEvents*>( ( *iObserversCnt )[ x ] );
+        if ( ( reqHandler->SessionId() == aSessionId )
+             && ( reqHandler->RequestFunction() == aFunction ) )
+            {
+            return reqHandler;
+            }
+        }
+    return NULL;
+    }
+
+//  End of File