diff -r 000000000000 -r ba25891c3a9e ncdengine/provider/server/src/ncdoperationmanager.cpp --- /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 +#include + +#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(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( + 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 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( + 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( aOperation ); + return op.NodeIdentifier(); + } + case ELoadRootNodeOperation: + { + const CNcdLoadRootNodeOperation& op = + static_cast( aOperation ); + return &op.NodeIdentifier(); + } + case ELoadBundleNodeOperation: + { + const CNcdLoadBundleNodeOperation& op = + static_cast( aOperation ); + return &op.NodeIdentifier(); + } + case EDownloadOperation: + { + const CNcdDownloadOperation& op = + static_cast( aOperation ); + return &op.NodeIdentifier(); + } + case EInstallOperation: + { + const CNcdInstallOperation& op = + static_cast( aOperation ); + return &op.NodeIdentifier(); + } + case EPurchaseOperation: + { + const CNcdPurchaseOperationImpl& op = + static_cast( aOperation ); + return &op.NodeIdentifier(); + } + case EContentDownloadOperation: + { + const CNcdContentDownloadOperation& op = + static_cast( 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*/ + } + }