ncdengine/provider/server/src/ncdoperationmanager.cpp
changeset 0 ba25891c3a9e
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ncdengine/provider/server/src/ncdoperationmanager.cpp	Thu Dec 17 08:51:10 2009 +0200
@@ -0,0 +1,1912 @@
+/*
+* Copyright (c) 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:   Implements CNcdOperationManager class
+*
+*/
+
+
+#include "ncdoperationmanager.h"
+
+#include <e32err.h>
+#include <s32mem.h>
+
+#include "ncdbaseoperation.h"
+#include "ncdstoragemanager.h"
+#include "ncdprotocol.h"
+#include "catalogshttpsession.h"
+#include "ncdnodemanager.h"
+#include "catalogsbasemessage.h"
+#include "ncdloadnodeoperationimpl.h"
+#include "ncdloadrootnodeoperationimpl.h"
+#include "ncdloadbundlenodeoperationimpl.h"
+#include "ncdnodefunctionids.h"
+#include "ncddownloadoperationimpl.h"
+#include "ncdnodeidentifier.h"
+#include "ncdproviderdefines.h"
+#include "ncdstoragemanager.h"
+#include "ncdpurchasehistorydbimpl.h"
+#include "ncdconfigurationmanager.h"
+#include "catalogssmssession.h"
+#include "ncdpurchaseoperationimpl.h"
+#include "ncdnodeimpl.h"
+#include "ncdnodelink.h"
+#include "catalogscontext.h"
+#include "catalogshttpconfig.h"
+#include "catalogsutils.h"
+#include "ncdproviderimpl.h"
+#include "ncdinstalloperationimpl.h"
+#include "ncdchildloadmode.h"
+#include "ncdrightsobjectoperationimpl.h"
+#include "ncdutils.h"
+#include "ncdsearchoperationimpl.h"
+#include "ncdnodefolder.h"
+#include "ncdsubscriptionoperationimpl.h"
+#include "ncdsubscriptionmanagerimpl.h"
+#include "ncdcontentdownloadoperation.h"
+#include "ncdstorageclient.h"
+#include "ncdstorage.h"
+#include "ncdstorageitem.h"
+#include "ncddatabasestorage.h"
+#include "ncdnodemetadataimpl.h"
+#include "ncdreportmanager.h"
+#include "ncdcreateaccesspointoperationimpl.h"
+#include "ncdsendhttprequestoperationimpl.h"
+#include "ncdconnectionmethod.h"
+#include "ncdserverreportoperationimpl.h"
+#include "ncdoperationtype.h"
+#include "ncdnodeidentifiereditor.h"
+#include "ncderrors.h"
+#include "ncdgeneralmanager.h"
+
+#include "catalogsdebug.h"
+
+
+// Because of security issues these capabilities are set for silent install
+static _LIT_SECURITY_POLICY_C1( KSilentInstallInfoPolicy,
+                                ECapabilityTrustedUI );
+
+
+// ---------------------------------------------------------------------------
+// NewL
+// ---------------------------------------------------------------------------
+//       
+CNcdOperationManager* CNcdOperationManager::NewL( 
+    CNcdProvider& aProvider,
+    CNcdGeneralManager& aGeneralManager,    
+    CNcdSubscriptionManager& aSubscriptionManager )
+    {
+    DLTRACEIN( ( "" ) );
+    CNcdOperationManager* self = new( ELeave ) CNcdOperationManager(
+        aProvider,
+        aGeneralManager,          
+        aSubscriptionManager );
+        
+    CleanupClosePushL( *self );
+    self->ConstructL();
+    CleanupStack::Pop( self );
+    DLTRACEOUT( ( "" ) );
+    return self;        
+    }
+
+
+// ---------------------------------------------------------------------------
+// Destructor
+// ---------------------------------------------------------------------------
+//       
+CNcdOperationManager::~CNcdOperationManager()
+    {
+    DLTRACEIN((""));
+    // Should we destroy the operations here if operations
+    // exist? operations should delete themselves when the operation
+    // is finished? This class may implement some interface that
+    // will be used to inform the manager when operation is
+    // finished...
+    // Close the cache array.
+    
+    DLTRACE(("Closing operations"));
+    
+    
+    for ( TInt i = 0; i < iOperationCache.Count(); ++i )
+        {        
+        iOperationCache[i]->Close();
+        }
+    
+
+    DLTRACE(("Operations closed"));
+    iOperationCache.Reset();
+    
+    iOperationQueue.Close();
+
+    DLTRACEOUT((""));
+    }
+
+    
+// ---------------------------------------------------------------------------
+// CreateOperationL
+// ---------------------------------------------------------------------------
+//       
+void CNcdOperationManager::CreateLoadNodeOperationRequestL(
+    MCatalogsBaseMessage& aMessage )
+    {
+        
+    DLTRACEIN((""));
+
+    // Get the session that will contain the handle of the node
+    MCatalogsSession& requestSession( aMessage.Session() );
+
+    DLTRACE(("create buffer"));
+
+    RBuf8 buf;
+    buf.CreateL( aMessage.InputLength() );
+    DLINFO(("input length=%d",aMessage.InputLength()));
+    CleanupClosePushL( buf );
+    User::LeaveIfError( aMessage.ReadInput( buf ) );
+    
+    
+    RDesReadStream stream( buf );
+    CleanupReleasePushL( stream );
+
+    DLTRACE(("get buffer data"));
+    
+    // Create node identifier from the stream    
+    CNcdNodeIdentifier* identifier = CNcdNodeIdentifier::NewLC( 
+        stream );
+        
+    if( ParallelOperationExistsForMetadataL( *identifier, aMessage.Session().Context() ) )
+        {
+        // Multiple simultaneous operations per one node are not supported, leave.
+        User::Leave( KNcdErrorParallelOperationNotAllowed );
+        }
+        
+    DLTRACE(("get load children flag"));
+    TBool loadChildren = stream.ReadInt32L();
+    DLTRACE(("get pageSize"));
+    TInt pageSize = stream.ReadInt32L();
+    DLTRACE(("get pageStart"));
+    TInt pageStart = stream.ReadInt32L();
+    DLTRACE(("get depth"));
+    TInt depth = stream.ReadInt32L();
+    DLTRACE(("get mode"));
+    TNcdChildLoadMode mode = static_cast<TNcdChildLoadMode>(stream.ReadInt32L());
+    DLTRACE(("get search flag"));
+    TBool search = stream.ReadInt32L();
+    CNcdSearchFilter* filter = NULL;
+    if ( search )
+        {
+        DLTRACE(("get search filter"));
+        filter = CNcdSearchFilter::NewLC();
+        filter->SetContentPurposes( stream.ReadUint32L() );
+        TInt keywordCount = stream.ReadInt32L();
+        for ( TInt i = 0 ; i < keywordCount ; i++ )
+            {
+            HBufC* keyword = NULL;
+            InternalizeDesL( keyword, stream );
+            CleanupStack::PushL( keyword );
+            filter->AddKeywordL( *keyword );
+            CleanupStack::PopAndDestroy( keyword );
+            }
+        MNcdSearchFilter::TSearchMode mode;
+        InternalizeEnumL( mode, stream );
+        filter->SetSearchMode( mode );
+        filter->SetRecursionDepthL( stream.ReadUint32L() );
+        }
+    
+    DLTRACE(( _L("id, size, start, depth: %S, %d, %d, %d"),
+              &identifier->NodeId(), pageSize, pageStart, depth ));
+    
+    
+    CNcdNode& node = iNodeManager.NodeL( *identifier );
+
+    DLTRACE(( _L("node found: %X"), &node ));
+    
+    TNcdResponseFilterParams filterParams;
+    filterParams.iPageSize = pageSize;
+    filterParams.iPageStart = pageStart;
+    filterParams.iStructureDepth = depth;
+    filterParams.iMetadataDepth = depth;
+    filterParams.iMetadataPerLevel = pageSize;
+                     
+    // create the operation
+    
+    CNcdLoadNodeOperationImpl* operation = NULL;
+    if( search )
+        {
+        DLTRACE(("Create search op"));
+        const CNcdNodeIdentifier* parentId = NULL;
+        if ( node.ClassId() == NcdNodeClassIds::ENcdSearchItemNodeClassId ||
+            node.ClassId() == NcdNodeClassIds::ENcdSearchFolderNodeClassId ||
+            node.ClassId() == NcdNodeClassIds::ENcdSearchRootNodeClassId ||
+            node.ClassId() == NcdNodeClassIds::ENcdSearchBundleNodeClassId )
+            {
+            DLTRACE(("search folder, use node's own parent"));
+            parentId = &node.CreateAndSetLinkL().ParentIdentifier();
+            }
+        else
+            {
+            DLTRACE(("not a search folder, set search root as parent"));
+            parentId = 
+                &iNodeManager.CreateSearchRootL(aMessage.Session().Context()).Identifier();
+            }
+        // create op
+        operation = CNcdSearchOperation::NewL(
+            *identifier,
+            *parentId,
+            *filter,
+            filterParams,
+            iGeneralManager, 
+            HttpSessionL( aMessage.Session().Context() ), 
+            this, this, aMessage.Session(), loadChildren, mode,
+            filter->RecursionDepth() );
+        }
+    else
+        {
+        DLTRACE(("Create load op"));
+        CNcdNodeFactory::TNcdNodePurpose parentPurpose = CNcdNodeFactory::ENcdNormalNode;
+        if ( !node.NodeLinkL().ParentIdentifier().ContainsEmptyFields() ) 
+            {
+            CNcdNode* parentNode = iNodeManager.NodePtrL( node.NodeLinkL().ParentIdentifier() );
+            if ( parentNode )
+                {                
+                parentPurpose = CNcdNodeFactory::NodePurposeL( *parentNode );
+                }
+            }
+        operation = CNcdLoadNodeOperationImpl::NewL(
+            *identifier,
+            node.NodeLinkL().ParentIdentifier(),
+            parentPurpose,
+            filterParams,
+            iGeneralManager, 
+            HttpSessionL( aMessage.Session().Context() ), 
+            this, this, aMessage.Session(), loadChildren, mode, EFalse, EFalse );
+        }
+
+    DLTRACE(( _L("operation created: %X"), operation ));
+    if( filter )
+        {
+        CleanupStack::PopAndDestroy( filter );
+        }
+    CleanupStack::PopAndDestroy( identifier );
+    CleanupStack::PopAndDestroy( &stream );
+    CleanupStack::PopAndDestroy( &buf );
+    
+    
+    CleanupStack::PushL( operation );
+    // Add the operation to the session and get the handle.
+    // If the operation already existed in the session we will still
+    // get a new handle to the same object.
+    TInt32 operationHandle( requestSession.AddObjectL( operation ) );
+    operation->SetHandle( operationHandle );
+    
+    // AddObjectL adds reference count by 1
+    operation->Close();
+    DLTRACE(("operation handle: %d", operationHandle ));
+
+    // Because we created a new operation, it should be added to the
+    // cache. 
+    iOperationCache.AppendL( operation );
+    CleanupStack::Pop( operation );    
+    
+    // Send the information to the client side
+    TRAPD( error, 
+           aMessage.CompleteAndReleaseL( operationHandle, KErrNone ) );
+    if( error != KErrNone )
+        {        
+        iOperationCache.Remove( iOperationCache.Count() - 1 );
+        // Is this ok?
+        User::Leave( error );
+        }
+    }
+    
+// ---------------------------------------------------------------------------
+// CreateOperationL
+// ---------------------------------------------------------------------------
+//       
+void CNcdOperationManager::CreateLoadRootNodeOperationRequestL(
+    MCatalogsBaseMessage& aMessage )
+    {
+        
+    DLTRACEIN((""));
+
+    // Get the session that will contain the handle of the node
+    MCatalogsSession& requestSession( aMessage.Session() );
+
+    
+    RBuf8 nodeIdentifierData;
+    nodeIdentifierData.CreateL( aMessage.InputLength() );
+    CleanupClosePushL( nodeIdentifierData );
+    User::LeaveIfError( aMessage.ReadInput( nodeIdentifierData ) );
+
+    // Create node identifier from the stream    
+    CNcdNodeIdentifier* identifier = CNcdNodeIdentifier::NewLC( 
+        nodeIdentifierData );
+            
+    if( ParallelOperationExistsForMetadataL( *identifier, aMessage.Session().Context(),
+            ETrue ) )
+        {
+        // Multiple simultaneous operations per one node are not supported, leave.
+        User::Leave( KNcdErrorParallelOperationNotAllowed );
+        }
+        
+    // create the operation
+    CNcdLoadRootNodeOperation* operation = CNcdLoadRootNodeOperation::NewL(
+        aMessage.Session().Context().FamilyId().iUid, 
+        iGeneralManager, 
+		HttpSessionL( aMessage.Session().Context() ), 
+		this, 
+		aMessage.Session() );
+    CleanupStack::PopAndDestroy( identifier );
+    CleanupStack::PopAndDestroy( &nodeIdentifierData );
+    
+    CleanupStack::PushL( operation );
+    // Add the operation to the session and get the handle.
+    // If the operation already existed in the session we will still
+    // get a new handle to the same object.
+    TInt32 operationHandle( requestSession.AddObjectL( operation ) );
+    
+    operation->SetHandle( operationHandle );
+    
+    operation->Close();
+    DLTRACE(("operation handle: %d", operationHandle ));
+
+    // Because we created a new operation, it should be added to the
+    // cache. 
+    iOperationCache.AppendL( operation );
+    CleanupStack::Pop( operation );    
+    
+    // Send the information to the client side
+    TRAPD( error, 
+           aMessage.CompleteAndReleaseL( operationHandle, KErrNone ) );
+    if( error != KErrNone )
+        {        
+        iOperationCache.Remove( iOperationCache.Count() - 1 );
+        }
+    } 
+
+
+// ---------------------------------------------------------------------------
+// CreateLoadBundleNodeOperationRequestL
+// ---------------------------------------------------------------------------
+//       
+void CNcdOperationManager::CreateLoadBundleNodeOperationRequestL(
+    MCatalogsBaseMessage& aMessage )
+    {
+        
+    DLTRACEIN((""));
+
+    // Get the session that will contain the handle of the node
+    MCatalogsSession& requestSession( aMessage.Session() );
+
+    RBuf8 nodeIdentifierData;
+    nodeIdentifierData.CreateL( aMessage.InputLength() );
+    CleanupClosePushL( nodeIdentifierData );
+    User::LeaveIfError( aMessage.ReadInput( nodeIdentifierData ) );
+
+    // Create node identifier from the stream    
+    CNcdNodeIdentifier* identifier = CNcdNodeIdentifier::NewLC( 
+        nodeIdentifierData );
+        
+    if( ParallelOperationExistsForMetadataL( *identifier, aMessage.Session().Context() ) )
+        {
+        // Multiple simultaneous operations per one node are not supported, leave.
+        User::Leave( KNcdErrorParallelOperationNotAllowed );
+        }
+    
+    // create the operation    
+    CNcdLoadBundleNodeOperation* operation = CNcdLoadBundleNodeOperation::NewL(
+        *identifier, 
+        iGeneralManager, 
+		HttpSessionL( aMessage.Session().Context() ), 
+		this, 
+		*this, 
+		aMessage.Session() );
+    CleanupStack::PopAndDestroy( identifier );
+    CleanupStack::PopAndDestroy( &nodeIdentifierData );
+    
+    CleanupStack::PushL( operation );
+    // Add the operation to the session and get the handle.
+    // If the operation already existed in the session we will still
+    // get a new handle to the same object.
+    TInt32 operationHandle( requestSession.AddObjectL( operation ) );
+    
+    operation->SetHandle( operationHandle );
+    
+    operation->Close();
+    DLTRACE(("operation handle: %d", operationHandle ));
+
+    // Because we created a new operation, it should be added to the
+    // cache. 
+    iOperationCache.AppendL( operation );
+    CleanupStack::Pop( operation );    
+    
+    // Send the information to the client side
+    TRAPD( error, 
+           aMessage.CompleteAndReleaseL( operationHandle, KErrNone ) );
+    if( error != KErrNone )
+        {        
+        iOperationCache.Remove( iOperationCache.Count() - 1 );
+        }
+    } 
+    
+// ---------------------------------------------------------------------------
+// CreateDownloadOperationL
+// ---------------------------------------------------------------------------
+//       
+void CNcdOperationManager::CreateDownloadOperationRequestL(
+    MCatalogsBaseMessage& aMessage )
+    {
+    
+    DLTRACEIN((""));
+
+    RCatalogsMessageReader reader;
+    reader.OpenLC( aMessage );
+        
+    // Read operation type    
+    TNcdDownloadDataType type = static_cast<TNcdDownloadDataType>( 
+        reader().ReadInt32L() );
+
+    DLINFO(( "Operation type: %d", type ));
+    // Create node identifier from the stream    
+    CNcdNodeIdentifier* identifier = CNcdNodeIdentifier::NewLC( 
+        reader() );
+    
+    if( ParallelOperationExistsForMetadataL( *identifier, aMessage.Session().Context(),
+        type == ENcdGenericFileDownload ) )
+        {
+        // Multiple simultaneous operations per one node are not supported, leave.
+        User::Leave( KNcdErrorParallelOperationNotAllowed );
+        }
+  
+    DLINFO(( _L("NodeId: %S::%S"), &identifier->NodeNameSpace(),
+        &identifier->NodeId() ));
+  
+    // Read download index
+    TInt downloadIndex = reader().ReadInt32L();
+    DLINFO(( "Download index: %d", downloadIndex ));
+    
+    // Check if the download already exists, completes the message
+    // if it does
+    if ( DownloadExistsL( aMessage, *identifier, type, downloadIndex ) )
+        {
+        DLTRACE(("Download already exists"));
+        CleanupStack::PopAndDestroy( 2, &reader ); // identifier, reader
+        return;        
+        }
+    
+    CleanupStack::Pop( identifier );
+    CleanupStack::PopAndDestroy( &reader ); // reader
+    CleanupStack::PushL( identifier );
+    
+    // Get current context
+    MCatalogsContext& context( aMessage.Session().Context() );
+  
+    HBufC* clientUid = context.FamilyId().Name().AllocLC();    
+  
+    MNcdStorageClient* storageClient = NULL;
+    // Generic file download doesn't use storage
+    if ( type != ENcdGenericFileDownload ) 
+        {
+        
+        // Quick fix: ensures that StorageManager has the client
+        MNcdStorage* storage = StorageL( *clientUid, 
+            identifier->NodeNameSpace() );
+        
+        // Find the correct storage for the client
+        storageClient = 
+            &iStorageManager.StorageClientL( *clientUid );
+        }
+        
+    
+    DLTRACE(("Creating the download operation"));
+    
+    // Try to get session handler
+    MNcdSessionHandler* sessionHandler = NULL;
+    TRAP_IGNORE(       
+        sessionHandler = &iProtocolHandler.SessionHandlerL( context ) );
+    
+    CNcdBaseOperation* operation = NULL;
+    if ( type != ENcdContentDownload ) 
+        {        
+        // Create operation according to it's type
+        operation = CNcdDownloadOperation::NewL(
+            *this,
+            type,
+            *identifier, 
+            iGeneralManager,         
+            HttpSessionL( context ),
+            sessionHandler,
+            storageClient,
+            context.FamilyId(),
+            downloadIndex,
+            aMessage.Session() );
+        }
+    else
+        {
+        MNcdStorage* dlStorage = StorageL( *clientUid, 
+            NcdProviderDefines::KDownloadNamespace );
+        
+        // Create operation according to it's type
+        operation = CNcdContentDownloadOperation::NewL(
+            *this,
+            *identifier, 
+            iGeneralManager,         
+            HttpSessionL( context ),
+            ReportManagerL( context ),
+            sessionHandler,
+            dlStorage->DatabaseStorageL( 
+                NcdProviderDefines::KDefaultDatabaseUid ),
+            aMessage.Session(),
+            downloadIndex );
+        }
+    DLTRACE(("Download operation created"));
+    CleanupStack::PopAndDestroy( clientUid );
+    CleanupStack::PopAndDestroy( identifier );    
+    CleanupStack::PushL( operation );
+    
+    // Get the session that will contain the handle of the node
+    MCatalogsSession& requestSession( aMessage.Session() );    
+    
+    // Add the operation to the session and get the handle.
+    // If the operation already existed in the session we will still
+    // get a new handle to the same object.
+    TInt32 operationHandle( requestSession.AddObjectL( operation ) );
+    operation->SetHandle( operationHandle );
+    operation->Close();
+    DLTRACE(("operation handle: %d", operationHandle ));
+
+    // Because we created a new operation, it should be added to the
+    // cache. 
+    iOperationCache.AppendL( operation );
+    CleanupStack::Pop( operation );    
+    
+    // Send the information to the client side
+    TRAPD( error, 
+           aMessage.CompleteAndReleaseL( operationHandle, KErrNone ) );
+    if( error != KErrNone )
+        {        
+        iOperationCache.Remove( iOperationCache.Count() - 1 );
+        }
+    DLTRACEOUT((""));
+    }
+    
+
+
+// ---------------------------------------------------------------------------
+// CreatePurchaseOperationL
+// ---------------------------------------------------------------------------
+//       
+void CNcdOperationManager::CreatePurchaseOperationRequestL(
+    MCatalogsBaseMessage& aMessage )
+    {
+    DLTRACEIN((""));
+
+    // Get the session that will contain the handle of the node
+    MCatalogsSession& requestSession( aMessage.Session() );
+
+    // Should use 8 bit version when client-server session supports it
+    RBuf8 buf;
+    buf.CreateL( aMessage.InputLength() );
+    DLINFO(("input length=%d",aMessage.InputLength()));
+    CleanupClosePushL( buf );
+    User::LeaveIfError( aMessage.ReadInput( buf ) );
+
+    RDesReadStream stream( buf );
+
+    CleanupReleasePushL( stream );
+
+    // Create node identifier from the stream    
+    CNcdNodeIdentifier* identifier = CNcdNodeIdentifier::NewLC( 
+        stream );
+    
+    if( ParallelOperationExistsForMetadataL( *identifier, aMessage.Session().Context() ) )
+        {
+        // Multiple simultaneous operations per one node are not supported, leave.
+        User::Leave( KNcdErrorParallelOperationNotAllowed );
+        }
+
+    HBufC* purchaseOptionId = NULL;
+    TInt length = InternalizeDesL( purchaseOptionId, stream );
+    CleanupStack::PushL( purchaseOptionId );
+   
+    if( length < 1 )
+        {
+        User::Leave( KErrArgument );
+        }
+
+    // create the operation
+    CNcdPurchaseOperationImpl* operation = CNcdPurchaseOperationImpl::NewL(
+        identifier->NodeNameSpace(), 
+        identifier->NodeId(),
+        identifier->ClientUid(),
+        *purchaseOptionId,
+        iGeneralManager, 
+        HttpSessionL( aMessage.Session().Context() ),
+        SmsSessionL( aMessage.Session().Context() ),
+        iSubscriptionManager,
+        this,
+        aMessage.Session() );
+
+    
+    CleanupStack::PopAndDestroy( purchaseOptionId );
+    CleanupStack::PopAndDestroy( identifier );
+    CleanupStack::PopAndDestroy( &stream );
+    CleanupStack::PopAndDestroy( &buf );
+
+
+    CleanupStack::PushL( operation );
+    // Add the operation to the session and get the handle.
+    // If the operation already existed in the session we will still
+    // get a new handle to the same object.
+    TInt32 operationHandle( requestSession.AddObjectL( operation ) );
+    operation->SetHandle( operationHandle );
+    
+    // AddObjectL adds reference count by 1
+    operation->Close();
+
+    DLTRACE(("operation handle: %d", operationHandle ));
+
+    // Because we created a new operation, it should be added to the
+    // cache. 
+    iOperationCache.AppendL( operation );
+    CleanupStack::Pop( operation );    
+
+    // Send the information to the client side
+    TRAPD( error, 
+           aMessage.CompleteAndReleaseL( operationHandle, KErrNone ) );
+    if( error != KErrNone )
+        {        
+        iOperationCache.Remove( iOperationCache.Count() - 1 );
+        }
+    }
+
+
+
+// ---------------------------------------------------------------------------
+// Create install operation
+// ---------------------------------------------------------------------------
+//       
+void CNcdOperationManager::CreateInstallOperationRequestL(
+    MCatalogsBaseMessage& aMessage )
+    {        
+    DLTRACEIN((""));
+
+    // Get the session that will contain the handle of the node
+    MCatalogsSession& requestSession( aMessage.Session() );
+
+    
+    RBuf8 nodeIdentifierData;
+    nodeIdentifierData.CreateL( aMessage.InputLength() );
+    CleanupClosePushL( nodeIdentifierData );
+    User::LeaveIfError( aMessage.ReadInput( nodeIdentifierData ) );
+
+    // Create node identifier from the stream    
+    CNcdNodeIdentifier* identifier = CNcdNodeIdentifier::NewLC( 
+        nodeIdentifierData );
+    
+    if( ParallelOperationExistsForMetadataL( *identifier, aMessage.Session().Context() ) )
+        {
+        // Multiple simultaneous operations per one node are not supported, leave.
+        User::Leave( KNcdErrorParallelOperationNotAllowed );
+        }            
+    
+    // create the operation
+    MCatalogsContext& context( requestSession.Context() );
+    CNcdInstallOperation* operation = CNcdInstallOperation::NewL(
+        *this,
+        *identifier,
+        iGeneralManager,
+        HttpSessionL( context ),        
+        ReportManagerL( context ),
+        aMessage.Session() );
+
+    CleanupStack::PopAndDestroy( identifier );
+    CleanupStack::PopAndDestroy( &nodeIdentifierData );
+    
+    
+    CleanupStack::PushL( operation );
+    // Add the operation to the session and get the handle.
+    // If the operation already existed in the session we will still
+    // get a new handle to the same object.
+    TInt32 operationHandle( requestSession.AddObjectL( operation ) );
+    operation->SetHandle( operationHandle );
+    
+    // AddObjectL adds reference count by 1
+    operation->Close();
+
+    DLTRACE(("operation handle: %d", operationHandle ));
+
+    // Because we created a new operation, it should be added to the
+    // cache. 
+    iOperationCache.AppendL( operation );
+    CleanupStack::Pop( operation );    
+    
+    // Send the information to the client side
+    TRAPD( error, 
+           aMessage.CompleteAndReleaseL( operationHandle, KErrNone ) );
+    if( error != KErrNone )
+        {        
+        iOperationCache.Remove( iOperationCache.Count() - 1 );
+        }
+    DLTRACEOUT((""));
+    }
+
+
+// ---------------------------------------------------------------------------
+// Create silent install operation
+// ---------------------------------------------------------------------------
+//       
+void CNcdOperationManager::CreateSilentInstallOperationRequestL(
+    MCatalogsBaseMessage& aMessage )
+    {        
+    DLTRACEIN((""));
+
+    if ( !aMessage.CheckSecurityPolicy( KSilentInstallInfoPolicy() ) )
+        {
+        DLTRACE(("Not enough capabilities for silent install"));
+        User::Leave( KErrPermissionDenied );
+        }
+
+    // If there are enough capabilities, then just create a normal
+    // install operation
+    CreateInstallOperationRequestL( aMessage );
+
+    DLTRACEOUT((""));
+    }
+
+
+
+// ---------------------------------------------------------------------------
+// Create rights object download and install operation
+// ---------------------------------------------------------------------------
+//       
+void CNcdOperationManager::CreateRightsObjectOperationRequestL(
+    MCatalogsBaseMessage& aMessage )
+    {        
+    DCHECK_CSTACK;
+    DLTRACEIN((""));
+
+    // Read input data buffer
+    RBuf8 buf;
+    buf.CreateL( aMessage.InputLength() );
+    DLINFO(("input length=%d",aMessage.InputLength()));
+    CleanupClosePushL( buf );
+    User::LeaveIfError( aMessage.ReadInput( buf ) );
+
+    // Create a stream for reading out of the buffer
+    RDesReadStream stream( buf );
+    CleanupClosePushL( stream );
+
+    // Read uri
+    HBufC* downloadUri = NULL;
+    InternalizeDesL( downloadUri, stream );
+    CleanupStack::PushL( downloadUri );
+    DLINFO((_L("Uri %S"), downloadUri ));
+
+    // Read mime type
+    HBufC* mimeType = NULL;
+    InternalizeDesL( mimeType, stream );
+    CleanupStack::PushL( mimeType );
+    DLINFO((_L("Mime type %S"), mimeType ));
+
+    // Read access point id
+    TNcdConnectionMethod method;
+    method.InternalizeL( stream );
+
+    // Get the session that will contain the handle of the node
+    MCatalogsSession& requestSession( aMessage.Session() );
+
+    // create the operation
+    CNcdRightsObjectOperation* operation = CNcdRightsObjectOperation::NewL(
+        iGeneralManager,
+        *downloadUri,
+        *mimeType,
+        method,
+        *this,
+        HttpSessionL( aMessage.Session().Context() ),
+        aMessage.Session() );
+    CleanupStack::PushL( operation );
+
+    // Add the operation to the session and get the handle.
+    // If the operation already existed in the session we will still
+    // get a new handle to the same object.
+    TInt32 operationHandle( requestSession.AddObjectL( operation ) );
+
+    operation->SetHandle( operationHandle );
+    
+    // AddObjectL adds reference count by 1
+    operation->Close();
+
+    DLINFO(("operation handle: %d", operationHandle ));
+
+    // Because we created a new operation, it should be added to the
+    // cache. 
+    iOperationCache.AppendL( operation );
+    CleanupStack::Pop( operation );
+    
+    // Send the information to the client side
+    TRAPD( error,
+           aMessage.CompleteAndReleaseL( operationHandle, KErrNone ) );
+
+    if( error != KErrNone )
+        {        
+        iOperationCache.Remove( iOperationCache.Count() - 1 );
+        }
+
+    CleanupStack::PopAndDestroy( 4 ); // mimeType, downloadUri, stream-close, buf-close
+
+    DLTRACEOUT((""));
+    }
+
+
+// ---------------------------------------------------------------------------
+// Create subscription operation
+// ---------------------------------------------------------------------------
+//       
+void CNcdOperationManager::CreateSubscriptionOperationRequestL(
+    MCatalogsBaseMessage& aMessage )
+    {
+    DLTRACEIN((""));
+
+    // Get the session that will contain the handle of the node
+    MCatalogsSession& requestSession( aMessage.Session() );
+
+    DLTRACE(("create buffer"));
+
+    RBuf8 buf;
+    buf.CreateL( aMessage.InputLength() );
+    DLINFO(( "input length=%d", aMessage.InputLength() ));
+    CleanupClosePushL( buf );
+    User::LeaveIfError( aMessage.ReadInput( buf ) );
+    
+    RDesReadStream stream( buf );
+    CleanupReleasePushL( stream );
+
+    DLTRACE(("get buffer data"));
+    
+    MNcdSubscriptionOperation::TType subscriptionOperationType =
+        (MNcdSubscriptionOperation::TType)stream.ReadInt32L();
+
+    CNcdSubscriptionOperation* operation( NULL );
+
+    switch ( subscriptionOperationType )
+        {            
+        case MNcdSubscriptionOperation::EUnsubscribe:
+            {
+    
+            DLINFO(( "-> EUnsubscribe" ));
+
+            HBufC* subscriptionPurchaseOptionId( NULL );
+            HBufC* subscriptionEntityId( NULL );
+            HBufC* subscriptionNamespace( NULL );
+            HBufC* subscriptionServerUri( NULL );
+
+            InternalizeDesL( subscriptionPurchaseOptionId, stream );
+            CleanupStack::PushL( subscriptionPurchaseOptionId );
+
+            InternalizeDesL( subscriptionEntityId, stream );
+            CleanupStack::PushL( subscriptionEntityId );
+
+            InternalizeDesL( subscriptionNamespace, stream );
+            CleanupStack::PushL( subscriptionNamespace );
+
+            InternalizeDesL( subscriptionServerUri, stream );
+            CleanupStack::PushL( subscriptionServerUri );
+            
+            operation =
+                CNcdSubscriptionOperation::NewL(
+                    MNcdSubscriptionOperation::EUnsubscribe,
+                    *subscriptionPurchaseOptionId,
+                    *subscriptionEntityId,
+                    *subscriptionNamespace,
+                    *subscriptionServerUri,
+                    iGeneralManager,
+                    iSubscriptionManager,
+                    HttpSessionL( aMessage.Session().Context() ),
+                    *this,
+                    requestSession );
+            
+            CleanupStack::PopAndDestroy( subscriptionServerUri );
+            CleanupStack::PopAndDestroy( subscriptionNamespace );
+            CleanupStack::PopAndDestroy( subscriptionEntityId );
+            CleanupStack::PopAndDestroy( subscriptionPurchaseOptionId );
+
+            break;
+            }
+
+        case MNcdSubscriptionOperation::ERefreshSubscriptions:
+            {
+            DLINFO(( "-> ERefreshSubscriptions" ));
+
+            operation =
+                CNcdSubscriptionOperation::NewL(
+                    MNcdSubscriptionOperation::ERefreshSubscriptions,
+                    iGeneralManager,
+                    iSubscriptionManager,
+                    HttpSessionL( aMessage.Session().Context() ),
+                    *this,
+                    requestSession );
+
+            break;
+            }
+
+        default:
+            {            
+            User::Leave( KErrNotSupported );
+
+            break;
+            }
+        }
+
+    CleanupStack::PopAndDestroy( &stream );
+    CleanupStack::PopAndDestroy( &buf );
+
+    CleanupClosePushL( *operation );
+
+    DLTRACE(( _L("operation created: %X"), operation ));
+    
+    // Add the operation to the session and get the handle.
+    // If the operation already existed in the session we will still
+    // get a new handle to the same object.
+    TInt32 operationHandle( requestSession.AddObjectL( operation ) );
+    operation->SetHandle( operationHandle );
+    
+    // AddObjectL adds reference count by 1
+    operation->Close();
+    DLTRACE(( "operation handle: %d", operationHandle ));
+
+    // Because we created a new operation, it should be added to the
+    // cache. 
+    iOperationCache.AppendL( operation );
+    CleanupStack::Pop( operation );    
+    
+    // Send the information to the client side
+    TRAPD( error, aMessage.CompleteAndReleaseL( operationHandle, KErrNone ) );
+    if( error != KErrNone )
+        {        
+        iOperationCache.Remove( iOperationCache.Count() - 1 );
+        // Is this ok?
+        User::Leave( error );
+        }
+    }
+
+
+// ---------------------------------------------------------------------------
+// Create access point creation operation
+// ---------------------------------------------------------------------------
+//       
+void CNcdOperationManager::CreateCreateAccessPointOperationRequestL(
+    MCatalogsBaseMessage& aMessage )
+    {            
+    DLTRACEIN((""));
+
+    RCatalogsMessageReader reader;
+    reader.OpenLC( aMessage );
+
+    HBufC* accessPointData = NULL;
+    InternalizeDesL( accessPointData, reader() );
+
+    CleanupStack::PopAndDestroy( &reader );
+    CleanupStack::PushL( accessPointData );
+    
+    DLINFO((_L("Data: %S"), accessPointData ));
+
+    // create the operation
+    // Note that ownership of accessPointData is transferred
+    CNcdCreateAccessPointOperation* operation = CNcdCreateAccessPointOperation::NewL(
+        accessPointData,
+        *this,
+        iGeneralManager,
+        aMessage.Session() );
+    CleanupStack::Pop( accessPointData );
+    CleanupStack::PushL( operation );
+
+    // Get the session that will contain the handle of the node
+    MCatalogsSession& requestSession( aMessage.Session() );
+
+    // Add the operation to the session and get the handle.
+    // If the operation already existed in the session we will still
+    // get a new handle to the same object.
+    TInt32 operationHandle( requestSession.AddObjectL( operation ) );
+
+    operation->SetHandle( operationHandle );
+    
+    // AddObjectL adds reference count by 1
+    operation->Close();
+
+    DLINFO(("operation handle: %d", operationHandle ));
+
+    // Because we created a new operation, it should be added to the
+    // cache. 
+    iOperationCache.AppendL( operation );
+    CleanupStack::Pop( operation );
+    
+    // Send the information to the client side
+    TRAPD( error,
+           aMessage.CompleteAndReleaseL( operationHandle, KErrNone ) );
+
+    if( error != KErrNone )
+        {        
+        iOperationCache.Remove( iOperationCache.Count() - 1 );
+        }
+
+    DLTRACEOUT((""));
+    }
+
+
+
+// ---------------------------------------------------------------------------
+// Send HTTP request operation
+// ---------------------------------------------------------------------------
+//       
+void CNcdOperationManager::CreateSendHttpRequestOperationRequestL(
+    MCatalogsBaseMessage& aMessage )
+    {
+    DLTRACEIN((""));
+
+    RCatalogsMessageReader reader;
+    reader.OpenLC( aMessage );
+
+    TNcdConnectionMethod method;
+    method.InternalizeL( reader() );
+    
+    HBufC8* uri = NULL;
+    InternalizeDesL( uri, reader() );
+    CleanupStack::PushL( uri );    
+
+    HBufC8* request = NULL;    
+    InternalizeDesL( request, reader() );
+    
+    CleanupStack::PushL( request );
+    
+    DLINFO((_L("Data: %S"), request ));
+
+    // Get the session that will contain the handle of the node
+    MCatalogsSession& requestSession( aMessage.Session() );
+
+    // create the operation
+    // Note that ownership of accessPointData is transferred
+    CNcdSendHttpRequestOperation* operation = CNcdSendHttpRequestOperation::NewL(
+        uri,
+        request,
+        method,
+        iGeneralManager,
+        *this,
+        HttpSessionL( requestSession.Context() ),
+        aMessage.Session()  );
+    CleanupStack::Pop( 2, uri ); // request, uri
+    CleanupStack::PopAndDestroy( &reader );
+    CleanupStack::PushL( operation );
+
+
+    // Add the operation to the session and get the handle.
+    // If the operation already existed in the session we will still
+    // get a new handle to the same object.
+    TInt32 operationHandle( requestSession.AddObjectL( operation ) );
+
+    operation->SetHandle( operationHandle );
+    
+    // AddObjectL adds reference count by 1
+    operation->Close();
+
+    DLINFO(("operation handle: %d", operationHandle ));
+
+    // Because we created a new operation, it should be added to the
+    // cache. 
+    iOperationCache.AppendL( operation );
+    CleanupStack::Pop( operation );
+    
+    // Send the information to the client side
+    TRAPD( error,
+           aMessage.CompleteAndReleaseL( operationHandle, KErrNone ) );
+
+    if( error != KErrNone )
+        {        
+        iOperationCache.Remove( iOperationCache.Count() - 1 );
+        }
+
+
+    }
+
+
+// ---------------------------------------------------------------------------
+// Restore serialized downloads
+// ---------------------------------------------------------------------------
+//       
+void CNcdOperationManager::RestoreDownloadOperationsRequestL(
+    MCatalogsBaseMessage& aMessage )
+    {
+    DLTRACEIN((""));
+    
+    // Get current context
+    MCatalogsContext& context( aMessage.Session().Context() );
+  
+    HBufC* clientUid = context.FamilyId().Name().AllocLC();    
+      
+
+    // Get client's download storage
+    MNcdStorage* storage = StorageL( *clientUid, 
+        NcdProviderDefines::KDownloadNamespace );
+    
+        
+    CleanupStack::PopAndDestroy( clientUid );
+    DLTRACE(("Creating the download operation"));
+
+    // Get download db
+    MNcdDatabaseStorage& db( storage->DatabaseStorageL( 
+        NcdProviderDefines::KDefaultDatabaseUid ) );
+
+    // Write the handles of resumed operations and return 
+    // them to the client-side
+    RCatalogsBufferWriter writer;
+    writer.OpenLC();
+
+    
+    // Get all items from the db
+    RPointerArray<MNcdStorageItem> items;
+    db.StorageItemsL( items );
+    CleanupClosePushL( items );
+    
+    DLTRACE(("Internalizing %d downloads", items.Count() ));
+
+    MCatalogsHttpSession& httpSession( HttpSessionL( context ) );
+
+    CNcdReportManager& reportManager( ReportManagerL( context ) );
+
+    for ( TInt i = 0; i < items.Count(); ++i )
+        {
+        // Create operation
+        CNcdContentDownloadOperation* operation = 
+            CNcdContentDownloadOperation::NewLC( 
+                *this, 
+                iGeneralManager,
+                httpSession,
+                reportManager,
+                db,
+                aMessage.Session() );
+        
+        // Internalize from db
+        items[i]->SetDataItem( operation );
+        items[i]->ReadDataL();
+        
+        if ( operation->IsOk() && 
+             !ParallelOperationExistsForMetadataL( operation->NodeId(),
+                aMessage.Session().Context() ) )
+            {
+            TInt32 operationHandle( aMessage.Session().AddObjectL( operation ) );
+            DLTRACE(("operation handle: %d", operationHandle ));
+            operation->SetHandle( operationHandle );
+            operation->Close();
+            
+            // Add to operation cache
+            iOperationCache.AppendL( operation );
+
+            CleanupStack::Pop( operation );         
+            
+            // add object data
+            ExternalizeEnumL(
+                NcdProviderDefines::ENcdStreamDataObject, writer() );            
+            
+            // Write handle
+            writer().WriteInt32L( operationHandle );        
+            
+            // Write type
+            writer().WriteInt32L( ENcdContentDownload );
+            
+            // Write metadata id
+            
+            operation->MetadataId().ExternalizeL( writer() );                
+            
+            writer().WriteInt32L( operation->CurrentDownload() );            
+            
+            reportManager.SetReportsAsUsedL( operation->MetadataId() );
+            DLTRACE(("Download operation created"));            
+            }    
+        else
+            {            
+            DLTRACE(("Removing failed download"));    
+            TRAP_IGNORE( items[i]->RemoveFromStorageL() );
+            DLTRACE(("Pop&Destroy"));
+            CleanupStack::PopAndDestroy( operation );
+            }        
+        }
+    
+    if ( items.Count() )
+        {
+        DLTRACE(("Commit"));
+        db.CommitL();
+        }
+    
+    // mark stream end
+    ExternalizeEnumL( NcdProviderDefines::ENcdStreamDataEnd, writer() );
+    CleanupStack::PopAndDestroy( &items );
+    
+    // Delete downloads that were not restored
+    httpSession.DeleteRestoredDownloads();
+
+    reportManager.RemoveUnusedReportsL();
+        
+    TRAPD( error, 
+           aMessage.CompleteAndReleaseL( writer.PtrL(), KErrNone ) );
+    if( error != KErrNone )
+        {        
+        iOperationCache.Remove( iOperationCache.Count() - 1 );
+        }
+
+    // writer, operationHandles
+    CleanupStack::PopAndDestroy( &writer ); 
+       
+    DLTRACEOUT((""));
+
+    }
+
+// ---------------------------------------------------------------------------
+// Create server report operation
+// ---------------------------------------------------------------------------
+//       
+void CNcdOperationManager::CreateServerReportOperationRequestL(
+    MCatalogsBaseMessage& aMessage )
+    {        
+    DLTRACEIN((""));
+
+    // Get the session that will contain the handle of the node
+    MCatalogsSession& requestSession( aMessage.Session() );
+    
+    // create the operation
+    // Get current context
+    MCatalogsContext& context( aMessage.Session().Context() );
+    CNcdServerReportOperation* operation = CNcdServerReportOperation::NewL(
+        iGeneralManager,
+        *this,
+        ReportManagerL( context ),
+        aMessage.Session() );
+    
+    CleanupStack::PushL( operation );
+    // Add the operation to the session and get the handle.
+    // If the operation already existed in the session we will still
+    // get a new handle to the same object.
+    TInt32 operationHandle( requestSession.AddObjectL( operation ) );
+    operation->SetHandle( operationHandle );
+    
+    // AddObjectL adds reference count by 1
+    operation->Close();
+
+    DLTRACE(("operation handle: %d", operationHandle ));
+
+    // Because we created a new operation, it should be added to the
+    // cache. 
+    iOperationCache.AppendL( operation );
+    CleanupStack::Pop( operation );    
+    
+    // Send the information to the client side
+    TRAPD( error, 
+           aMessage.CompleteAndReleaseL( operationHandle, KErrNone ) );
+    if( error != KErrNone )
+        {        
+        iOperationCache.Remove( iOperationCache.Count() - 1 );
+        }
+    DLTRACEOUT((""));
+    }
+
+
+MCatalogsHttpSession& CNcdOperationManager::HttpSessionL( MCatalogsContext& aContext )
+    {
+    TNcdProviderContext providerContext;
+    iProvider.GetProviderContextL( aContext, providerContext );
+    return *providerContext.iHttpSession;
+    }
+
+MCatalogsSmsSession& CNcdOperationManager::SmsSessionL( MCatalogsContext& aContext )
+    {
+    TNcdProviderContext providerContext;
+    iProvider.GetProviderContextL( aContext, providerContext );
+    return *providerContext.iSmsSession;
+    }
+
+CNcdReportManager& CNcdOperationManager::ReportManagerL( MCatalogsContext& aContext )
+    {
+    TNcdProviderContext providerContext;
+    iProvider.GetProviderContextL( aContext, providerContext );
+    return *providerContext.iReportManager;
+    }
+
+
+// ---------------------------------------------------------------------------
+// ReceiveMessage
+// ---------------------------------------------------------------------------
+//       
+void CNcdOperationManager::ReceiveMessage( MCatalogsBaseMessage* aMessage,
+                                           TInt aFunctionNumber )
+    {
+    DLTRACEIN((""));
+
+    // The message is always required.
+    if( aMessage == NULL )
+        {
+        // Do not do anything here because we can not give any
+        // feedback
+        return;
+        }
+
+    TInt trapError( KErrNone );
+        
+    switch( aFunctionNumber )
+        {
+        case NcdNodeFunctionIds::ENcdOperationManagerCreateLoadNodeOperation:
+            DLTRACE(("Creating load node operation"));
+
+            TRAP( trapError, CreateLoadNodeOperationRequestL( *aMessage ) );
+            break;
+
+        case NcdNodeFunctionIds::ENcdOperationManagerCreateDownloadOperation:
+            DLTRACE(("Creating download operation"));
+
+            TRAP( trapError, CreateDownloadOperationRequestL( *aMessage ) );
+            break;
+            
+        case NcdNodeFunctionIds::ENcdOperationManagerCreateLoadRootNodeOperation:
+            DLTRACE(("Creating load root node operation"));
+            
+            TRAP( trapError, CreateLoadRootNodeOperationRequestL( *aMessage ) );
+            break;
+            
+        case NcdNodeFunctionIds::ENcdOperationManagerCreateLoadBundleNodeOperation:
+            DLTRACE(("Creating load bundle node operation"));
+            
+            TRAP( trapError, CreateLoadBundleNodeOperationRequestL( *aMessage ) );
+            break;
+        
+        case NcdNodeFunctionIds::ENcdOperationManagerCreatePurchaseOperation:
+            DLTRACE(("Creating purchase operation"));
+            
+            TRAP( trapError, CreatePurchaseOperationRequestL( *aMessage ) );
+            break;
+            
+        case NcdNodeFunctionIds::ENcdOperationManagerCreateRightsObjectOperation:
+            DLTRACE(("Creating rights object download and install operation"));
+            
+            TRAP( trapError, CreateRightsObjectOperationRequestL( *aMessage ) );
+            break;
+
+        case NcdNodeFunctionIds::ENcdOperationManagerCreateInstallOperation:
+            DLTRACE(("Creating install operation"));
+            
+            TRAP( trapError, CreateInstallOperationRequestL( *aMessage ) );
+            break;
+
+        case NcdNodeFunctionIds::ENcdOperationManagerCreateSilentInstallOperation:
+            DLTRACE(("Creating install operation"));
+            
+            TRAP( trapError, CreateSilentInstallOperationRequestL( *aMessage ) );
+            break;
+
+        case NcdNodeFunctionIds::ENcdOperationManagerCreateSubscriptionOperation:
+            DLTRACE(("Creating subscription operation"));
+            
+            TRAP( trapError, CreateSubscriptionOperationRequestL( *aMessage ) );
+            break;
+
+        case NcdNodeFunctionIds::ENcdOperationManagerRestoreContentDownloads:
+            DLTRACE(("Restoring downloads"));
+            
+            TRAP( trapError, RestoreDownloadOperationsRequestL( *aMessage ) );
+            break;
+
+        case NcdNodeFunctionIds::ENcdOperationManagerCreateCreateAccessPointOperation:
+            DLTRACE(("Creating create accesspoint operation"));
+            
+            TRAP( trapError, CreateCreateAccessPointOperationRequestL( *aMessage ) );
+            break;
+
+        case NcdNodeFunctionIds::ENcdOperationManagerCreateSendHttpRequestOperation:
+            DLTRACE(("Creating HTTP request sending operation"));
+            
+            TRAP( trapError, CreateSendHttpRequestOperationRequestL( *aMessage ) );
+            break;
+
+        case NcdNodeFunctionIds::ENcdOperationManagerCreateServerReportOperation:
+            DLTRACE(("Creating server report operation"));
+            
+            TRAP( trapError, CreateServerReportOperationRequestL( *aMessage ) );
+            break;
+            
+        case NcdNodeFunctionIds::ENcdRelease:
+            ReleaseRequest( *aMessage );
+            break;
+
+        default:
+            DASSERT( 0 );
+            break;
+        }
+
+    if ( trapError != KErrNone )
+        {
+        // Because something went wrong the complete has not been
+        // yet called for the message.
+        // So, inform the client about the error.
+        DLTRACE(("ERROR, Complete and release %d", trapError));
+        
+        aMessage->CompleteAndRelease( trapError );
+        }
+
+    DLTRACEOUT((""));
+    }
+
+
+// ---------------------------------------------------------------------------
+// CounterPartLost
+// ---------------------------------------------------------------------------
+//       
+void CNcdOperationManager::CounterPartLost( const MCatalogsSession& /*aSession*/ )
+    {
+    DLTRACEIN((""));
+    DLTRACEOUT((""));
+    
+    }
+    
+
+// ---------------------------------------------------------------------------
+// RemoveOperation
+// ---------------------------------------------------------------------------
+//           
+void CNcdOperationManager::RemoveOperation( CNcdBaseOperation& aOperation )
+    {
+    DLTRACEIN((""));
+    TInt index = iOperationCache.Find( &aOperation );
+    if ( index != KErrNotFound ) 
+        {
+        DLTRACE(("Removing operation"));
+        iOperationCache.Remove( index );
+        }
+        
+    index = iOperationQueue.Find( &aOperation );
+    if ( index != KErrNotFound )
+        {
+        // Should never come here.
+        DASSERT( EFalse );
+        iOperationQueue.Remove( index );
+        }
+    }
+    
+    
+// ---------------------------------------------------------------------------
+// QueueOperation
+// ---------------------------------------------------------------------------
+//           
+void CNcdOperationManager::QueueOperationL( CNcdBaseOperation& aOperation )
+    {
+    DLTRACEIN(("queue size: %d", iOperationQueue.Count()));
+    iOperationQueue.AppendL( &aOperation );
+    
+    // Start the operation if it is the only one in queue, or there are no load bundle
+    // node operations which may lock the database. If the operation is a load bundle operation
+    // it should not be started if the queue is not empty since there are other operations
+    // running.
+    if ( aOperation.Type() == ELoadBundleNodeOperation )
+        {
+        if ( iOperationQueue.Count() == 1 )
+            {
+            aOperation.RunOperation();
+            }
+        }
+    else
+        {
+        if ( !QueuedLoadBundleOperationsExists() )
+            {
+            aOperation.RunOperation();
+            }
+        }
+    }
+    
+// ---------------------------------------------------------------------------
+// QueueOperation
+// ---------------------------------------------------------------------------
+//           
+void CNcdOperationManager::QueuedOperationComplete( CNcdBaseOperation& aOperation )
+    {
+    DLTRACEIN(("operation-ptr: %x", &aOperation));
+    
+    TInt index = iOperationQueue.Find( &aOperation );
+    
+    if ( index != KErrNotFound )
+        {        
+        iOperationQueue.Remove( index );
+
+        // Start new operations only if the completed one was the first in queue since
+        // the first one is otherwise running still.
+        if ( index == 0 && iOperationQueue.Count() ) 
+            {
+            if ( iOperationQueue[ 0 ]->Type() == ELoadBundleNodeOperation )
+                {
+                // If the next in queue is load bundle node, it can be started since
+                // it is not started yet.
+                iOperationQueue[ 0 ]->ContinueOperationL();
+                }
+                                
+            else if ( aOperation.Type() == ELoadBundleNodeOperation ) 
+                {
+                // Completed operation was a bundle load op, so the next in queue are not
+                // started yet. Start the next operations in queue before the first load
+                // bundle node operation.
+                for ( TInt i = 0; i < iOperationQueue.Count(); i++ )
+                    {
+                    if ( iOperationQueue[ i ]->Type() != ELoadBundleNodeOperation )
+                        {
+                        iOperationQueue[ i ]->ContinueOperationL();
+                        }
+                    else
+                        {
+                        break;
+                        }
+                    }
+                }
+            }
+        }
+    }
+                    
+    
+    
+// ---------------------------------------------------------------------------
+// Constructor
+// ---------------------------------------------------------------------------
+//           
+CNcdOperationManager::CNcdOperationManager( 
+    CNcdProvider& aProvider,
+    CNcdGeneralManager& aGeneralManager,      
+    CNcdSubscriptionManager& aSubscriptionManager )
+	: 
+    CCatalogsCommunicable(),
+    iProvider( aProvider ),
+    iGeneralManager( aGeneralManager ),
+    iStorageManager( aGeneralManager.StorageManager() ),
+    iProtocolHandler( aGeneralManager.ProtocolManager() ),
+    iNodeManager( aGeneralManager.NodeManager() ),
+    iPurchaseHistory( aGeneralManager.PurchaseHistory() ),
+    iConfigurationManager( aGeneralManager.ConfigurationManager() ),
+    iAccessPointManager( aGeneralManager.AccessPointManager() ),
+    iSubscriptionManager( aSubscriptionManager )
+    {
+    }
+
+
+// ---------------------------------------------------------------------------
+// ConstructL
+// ---------------------------------------------------------------------------
+//       
+void CNcdOperationManager::ConstructL()
+    {
+    DLTRACEIN( ( "this: %X", this ) );
+    
+    DLTRACEOUT( ( "" ) );
+    }
+
+
+// ---------------------------------------------------------------------------
+// StorageL
+// ---------------------------------------------------------------------------
+//    
+MNcdStorage* CNcdOperationManager::StorageL( const TDesC& aClientUid,
+    const TDesC& aNamespace ) const
+    {    
+    DLTRACEIN((""));
+    MNcdStorage* storage = NULL;
+        
+    
+    DLTRACE(( _L("Namespace: %S"), &aNamespace ));
+    TRAPD( err, storage = &iStorageManager.StorageL( aClientUid, aNamespace ) );
+    
+    if ( err == KErrNotFound ) 
+        {
+        DLTRACE(("Creating storage for the client"));
+        err = KErrNone;
+        TRAP( err, storage = &iStorageManager.CreateStorageL( aClientUid, aNamespace ) );
+        
+        if ( err == KErrAlreadyExists )
+            {
+            err = KErrNone;
+            storage = &iStorageManager.StorageL( aClientUid, aNamespace );
+            }
+        }
+
+    if ( err != KErrNone )
+        {
+        DLTRACE(("Leaving: %i", err));
+        User::Leave( err );   
+        }
+        
+    DLTRACEOUT((""));
+    return storage;
+    }
+    
+    
+// ---------------------------------------------------------------------------
+// Release request
+// ---------------------------------------------------------------------------
+//    
+void CNcdOperationManager::ReleaseRequest( MCatalogsBaseMessage& aMessage ) const
+    {
+    DLTRACEIN((""));
+
+    // Decrease the reference count for this object.
+    // When the reference count reaches zero, this object will be destroyed
+    // and removed from the session.
+    MCatalogsSession& requestSession( aMessage.Session() );
+    TInt handle( aMessage.Handle() );
+    aMessage.CompleteAndRelease( KErrNone );
+    requestSession.RemoveObject( handle );
+                
+    DLTRACEOUT((""));
+    }
+    
+
+// ---------------------------------------------------------------------------
+// Checks if a download already exists
+// ---------------------------------------------------------------------------
+//    
+TBool CNcdOperationManager::DownloadExistsL( MCatalogsBaseMessage& aMessage, 
+    const CNcdNodeIdentifier& aIdentifier, 
+    TNcdDownloadDataType aType, 
+    TInt aIndex )
+    {
+    DLTRACEIN(("Op cache count: %d", iOperationCache.Count()));
+    TInt32 handle = 0;
+    
+    const CNcdNodeIdentifier* metaId = &aIdentifier;
+
+    // Use metadata id's for comparison since temp nodes have different
+    // node id's but same metadata id's as normal nodes
+    //
+    // Generic file downloads don't have node nor metadata. The given node id
+    // contains the URL and target filename
+    if ( aType != ENcdGenericFileDownload )
+        {
+        DLTRACE(("Not skin nor generic DL, getting metadata id"));        
+        
+        metaId = &iNodeManager.NodeL( aIdentifier ).NodeMetaDataL().Identifier();
+        }        
+    
+    for ( TInt i = 0; i < iOperationCache.Count(); ++i )
+        {
+        // Check other downloads but content
+        if ( aType != ENcdContentDownload && 
+             iOperationCache[i]->Type() == 
+                EDownloadOperation )
+            {
+            CNcdDownloadOperation* op = static_cast<CNcdDownloadOperation*>(
+                iOperationCache[i] );
+            if ( op->MatchDownload( *metaId, aType, aIndex ) )
+                {
+                DLTRACE(("Found a matching download"));
+                handle = op->Handle();
+                break;
+                }
+            }
+        // check content downloads
+        else if ( aType == ENcdContentDownload &&
+            iOperationCache[i]->Type() ==
+                EContentDownloadOperation )
+            {
+            CNcdContentDownloadOperation* op = static_cast<
+                CNcdContentDownloadOperation*>(
+                iOperationCache[i] );
+            if ( op->MatchDownload( *metaId, aType, aIndex ) )
+                {
+                DLTRACE(("Found a matching content download"));
+                handle = op->Handle();
+                break;
+                }
+            }            
+        }
+    if ( handle ) 
+        {
+        // Send the information to the client side
+        aMessage.CompleteAndReleaseL( handle, KErrNone );
+        return ETrue;
+        }
+    DLTRACEOUT(("No matching download"));
+    return EFalse;
+    }
+
+
+// ---------------------------------------------------------------------------
+// Checks if there are load bundle node operations in operation queue.
+// ---------------------------------------------------------------------------
+//        
+TBool CNcdOperationManager::QueuedLoadBundleOperationsExists() const
+    {
+    DLTRACEIN((""));
+    TInt queueSize = iOperationQueue.Count();
+    for ( TInt i = 0; i < queueSize; i++ )
+        {
+        if ( iOperationQueue[ i ]->Type() == ELoadBundleNodeOperation )
+            {
+            DLINFO(("queued load bundle op exists"));
+            return ETrue;
+            }
+        }
+        
+    DLINFO(("no queued load bundle op"));
+    return EFalse;
+    }
+
+// ---------------------------------------------------------------------------
+// Checks if there are on-going operations for the metadata for another client
+// ---------------------------------------------------------------------------
+// 
+TBool CNcdOperationManager::ParallelOperationExistsForMetadataL(
+    const CNcdNodeIdentifier& aNodeIdentifier,
+    const MCatalogsContext& aContext,
+    TBool aCompareIdsDirectly ) const
+    {
+    DLTRACEIN((""));
+    const CNcdNodeIdentifier* metaId = NULL;
+
+    // If parameter suggests that ids should not be compared directly,
+    // make a safety check.
+    if ( !aCompareIdsDirectly
+         && NcdNodeIdentifierEditor::IdentifiesSomeRoot( aNodeIdentifier ) )
+        {
+        // In the case of root nodes, the metadata does not
+        // exist. So, force direct comparing of node ids.
+        DLINFO(("Force direct comparing of node ids"));
+        aCompareIdsDirectly = ETrue;
+        }
+
+    if( !aCompareIdsDirectly )
+        {
+        // The node should always exist.
+        CNcdNode& node( iNodeManager.NodeL( aNodeIdentifier ) );
+
+        // Above, a root node check was made to force direct comparing 
+        // of ids for root nodes because they do not have metadata. So,
+        // in root node cases we do not come here.
+        // In normal cases, the metadata should always exist. 
+        // But, to be safe in all cases, check if metadata is NULL here.  
+        // Notice, ownership is not transferred here.
+        CNcdNodeMetaData* metadata( node.NodeMetaData() );
+
+        if ( metadata )
+            {
+            DLINFO(("Metadata existed for paralled operations checking"));
+            // Ownership is not transferred. Metadata owns its own identifier.
+            metaId = &metadata->Identifier();            
+            }
+        else
+            {
+            // Because metadata is NULL, 
+            // no operation should exist for it either.
+            DLTRACEOUT(("No metadata to compare parallel operations"));
+            return EFalse;
+            }
+        }
+        
+    // Check operation cache
+    for ( TInt i = 0; i < iOperationCache.Count(); i++ )
+        {
+        // Check is only done if the client is not the same
+        if( iOperationCache[i]->Session().Context().FamilyId() != aContext.FamilyId() ||
+            ( iOperationCache[i]->Session().Context().SecureId() == aContext.SecureId() && 
+              iOperationCache[i]->Session().Context().InstanceId() == aContext.InstanceId() ) )
+            {
+            continue;
+            }
+        // Try to get id from operation, not all operations are node specific.
+        const CNcdNodeIdentifier* id = GetNodeIdFromOperation( *iOperationCache[i] );
+        if( !id )
+            {
+            continue;
+            }
+        if( !aCompareIdsDirectly &&
+            NcdNodeIdentifierEditor::DoesMetaDataIdentifierMatchL( *metaId, *id ) )
+            {
+            return ETrue;
+            }
+        else if( aNodeIdentifier.Equals( *id ) )
+            {
+            return ETrue;
+            }
+        }
+    
+    // Check operation queue
+    for ( TInt i = 0; i < iOperationQueue.Count(); i++ )
+        {
+        // Check is only done if the client is not the same
+        if( iOperationQueue[i]->Session().Context().FamilyId() != aContext.FamilyId() ||
+            ( iOperationQueue[i]->Session().Context().SecureId() == aContext.SecureId() && 
+              iOperationQueue[i]->Session().Context().InstanceId() == aContext.InstanceId() ) )
+            {
+            continue;
+            }
+        // Try to get id from operation, not all operations are node specific.
+        const CNcdNodeIdentifier* id = GetNodeIdFromOperation( *iOperationQueue[i] );
+        if( !id )
+            {
+            continue;
+            }
+        if( !aCompareIdsDirectly &&
+            NcdNodeIdentifierEditor::DoesMetaDataIdentifierMatchL( *metaId, *id ) )
+            {
+            return ETrue;
+            }
+        else if( aNodeIdentifier.Equals( *id ) )
+            {
+            return ETrue;
+            }
+        }
+    return EFalse;
+    }
+    
+const CNcdNodeIdentifier* CNcdOperationManager::GetNodeIdFromOperation(
+    const CNcdBaseOperation& aOperation ) const
+    {
+    DLTRACEIN((""));
+    switch( aOperation.Type() )
+        {
+        case ELoadNodeOperation:
+        case ESearchOperation:
+            {
+            const CNcdLoadNodeOperationImpl& op =
+                static_cast<const CNcdLoadNodeOperationImpl&>( aOperation );
+            return op.NodeIdentifier();
+            }
+        case ELoadRootNodeOperation:
+            {
+            const CNcdLoadRootNodeOperation& op =
+                static_cast<const CNcdLoadRootNodeOperation&>( aOperation );
+            return &op.NodeIdentifier();
+            }
+        case ELoadBundleNodeOperation:
+            {
+            const CNcdLoadBundleNodeOperation& op =
+                static_cast<const CNcdLoadBundleNodeOperation&>( aOperation );
+            return &op.NodeIdentifier();
+            }
+        case EDownloadOperation:
+            {
+            const CNcdDownloadOperation& op =
+                static_cast<const CNcdDownloadOperation&>( aOperation );
+            return &op.NodeIdentifier();
+            }
+        case EInstallOperation:
+            {
+            const CNcdInstallOperation& op =
+                static_cast<const CNcdInstallOperation&>( aOperation );
+            return &op.NodeIdentifier();
+            }
+        case EPurchaseOperation:
+            {
+            const CNcdPurchaseOperationImpl& op =
+                static_cast<const CNcdPurchaseOperationImpl&>( aOperation );
+            return &op.NodeIdentifier();
+            }
+        case EContentDownloadOperation:
+            {
+            const CNcdContentDownloadOperation& op =
+                static_cast<const CNcdContentDownloadOperation&>( aOperation );
+            return &op.NodeId();
+            }
+        default:
+            {
+            return NULL;
+            }
+        // These operations are not node-specific, hence no id information can be
+        // retrieved from them:
+        /*EDownloadSubOperation,
+        EDescriptorDownloadSubOperation,
+        ESendNotificationSubOperation,
+        ERightsObjectOperation,
+        ECreateAccessPointOperation,
+        ESendHttpRequestOperation,
+        EServerReportOperation,
+        ESubscriptionOperation*/
+        }
+    }