--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/ncdengine/provider/server/src/ncdnodemetadataimpl.cpp Thu Dec 17 08:51:10 2009 +0200
@@ -0,0 +1,2639 @@
+/*
+* Copyright (c) 2006-2008 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 CNcdNodeMetaData class
+*
+*/
+
+
+#include "ncdnodemetadataimpl.h"
+#include "ncdnodeidentifier.h"
+#include "ncdnodedisclaimer.h"
+#include "ncdnodeiconimpl.h"
+#include "ncdnodescreenshotimpl.h"
+#include "ncdnodeskinimpl.h"
+#include "ncdnodeupgradeimpl.h"
+#include "ncdnodedependencyimpl.h"
+#include "ncdnodeuricontentimpl.h"
+#include "ncdnodecontentinfoimpl.h"
+#include "ncdnodepreviewimpl.h"
+#include "ncdpurchaseoptionimpl.h"
+#include "ncdpurchasedetails.h"
+#include "ncdpurchasehistorydbimpl.h"
+#include "ncdnodedownloadimpl.h"
+#include "ncdnodeinstallimpl.h"
+#include "ncdnodeuserdataimpl.h"
+#include "catalogssession.h"
+#include "catalogsbasemessage.h"
+#include "ncdnodefunctionids.h"
+#include "catalogsconstants.h"
+#include "ncd_pp_dataentity.h"
+#include "ncd_pp_dataentitycontent.h"
+#include "ncd_cp_query.h"
+#include "ncd_pp_download.h"
+#include "ncd_pp_purchaseoption.h"
+#include "ncdprotocoltypes.h"
+#include "catalogsutils.h"
+#include "ncdutils.h"
+#include "ncdkeyvaluepair.h"
+#include "ncdpanics.h"
+#include "ncdserversubscribablecontent.h"
+#include "ncdpurchasehistoryutils.h"
+#include "ncderrors.h"
+
+#include "catalogsdebug.h"
+
+
+CNcdNodeMetaData::CNcdNodeMetaData(
+ NcdNodeClassIds::TNcdNodeClassId aClassId,
+ CNcdNodeManager& aNodeManager )
+: CCatalogsCommunicable(),
+ iClassId( aClassId ),
+ iNodeManager( aNodeManager )
+ {
+ DLTRACEIN(("Meta class id: %d", aClassId));
+ }
+
+
+void CNcdNodeMetaData::ConstructL( const CNcdNodeIdentifier& aIdentifier )
+ {
+ DLTRACEIN((""));
+
+ // These two values has to be set. So, this metadata can be identified.
+ iIdentifier = CNcdNodeIdentifier::NewL( aIdentifier );
+
+ // The user data is part of the metadata. So, the ui may set its own info
+ // for the node by using this object.
+ iUserData = CNcdNodeUserData::NewL( *iIdentifier, iNodeManager );
+
+ iTimeStamp = KNullDesC().AllocL();
+ iName = KNullDesC().AllocL();
+ iDescription = KNullDesC().AllocL();
+ iLayoutType = KNullDesC().AllocL();
+
+ // This internalization is not related to purchase history so it's done
+ // separately
+ TRAP_IGNORE( InternalizeInstallFromContentInfoL() );
+
+
+ TRAPD( phError,
+ {
+ // Get purchase details
+ CNcdPurchaseDetails* details = PurchaseDetailsLC();
+
+ InternalizeContentInfoL( *details );
+
+ // Try to internalize URI content from purchase history
+ InternalizeUriContentL( *details );
+
+ InternalizeDependencyL( *details );
+ // Try to internalize node download from purchase history.
+ InternalizeDownloadL( *details );
+
+ // Try to internalize node install from purchase history
+ InternalizeInstallL( *details );
+
+ // Try to internalize node icon from purchase history
+ // (does not read icon data to memory)
+ InternalizeIconL( *details );
+
+ CleanupStack::PopAndDestroy( details );
+ });
+
+ if( phError != KErrNone &&
+ phError != KErrNotFound &&
+ phError != KNcdErrorNoPurchaseInformation )
+ {
+ DLERROR(( "phError: %d", phError ));
+ User::Leave( phError );
+ }
+
+ DLTRACEOUT((""));
+ }
+
+
+CNcdNodeMetaData::~CNcdNodeMetaData()
+ {
+ DLTRACEIN((""));
+
+ delete iIdentifier;
+ iIdentifier = NULL;
+
+ delete iTimeStamp;
+ iTimeStamp = NULL;
+
+ delete iName;
+ iName = NULL;
+
+ delete iDescription;
+ iDescription = NULL;
+
+ delete iLayoutType;
+ iLayoutType = NULL;
+
+ // Notice that CCatalogsCommunicable classes cannot be destroyed by
+ // calling delete! Instead call Close to them
+
+ if ( iUserData )
+ {
+ DLINFO(("Closing node user data"));
+ iUserData->Close();
+ iUserData = NULL;
+ }
+
+ if ( iDisclaimer != NULL )
+ {
+ iDisclaimer->Close();
+ iDisclaimer = NULL;
+ }
+
+ if ( iIcon != NULL )
+ {
+ iIcon->Close();
+ iIcon = NULL;
+ }
+
+ if ( iScreenshot != NULL )
+ {
+ iScreenshot->Close();
+ iScreenshot = NULL;
+ }
+
+ if ( iSkin != NULL )
+ {
+ iSkin->Close();
+ iSkin = NULL;
+ }
+
+ if( iUriContent != NULL )
+ {
+ iUriContent->Close();
+ iUriContent = NULL;
+ }
+
+ if( iContentInfo != NULL )
+ {
+ iContentInfo->Close();
+ iContentInfo = NULL;
+ }
+
+ if( iPreview != NULL )
+ {
+ iPreview->Close();
+ iPreview = NULL;
+ }
+
+ if ( iUpgrade != NULL )
+ {
+ iUpgrade->Close();
+ iUpgrade = NULL;
+ }
+
+ if ( iDependency != NULL )
+ {
+ iDependency->Close();
+ iDependency = NULL;
+ }
+
+ if ( iDownload )
+ {
+ DLINFO(("Closing node download"));
+ iDownload->Close();
+ iDownload = NULL;
+ }
+
+ if ( iInstall )
+ {
+ DLINFO(("Closing node install"));
+ iInstall->Close();
+ iInstall = NULL;
+ }
+
+ if ( iMoreInfo != NULL )
+ {
+ iMoreInfo->Close();
+ iMoreInfo = NULL;
+ }
+
+ iDetails.ResetAndDestroy();
+
+ delete iSubscribableContent;
+ iSubscribableContent = NULL;
+
+ ResetAndCloseArray( iPurchaseOptions );
+
+ DLTRACEOUT((""));
+ }
+
+
+CNcdNodeManager& CNcdNodeMetaData::NodeManager() const
+ {
+ return iNodeManager;
+ }
+
+
+const CNcdNodeIdentifier& CNcdNodeMetaData::Identifier() const
+ {
+ return *iIdentifier;
+ }
+
+
+NcdNodeClassIds::TNcdNodeClassId CNcdNodeMetaData::ClassId() const
+ {
+ return iClassId;
+ }
+
+const TDesC& CNcdNodeMetaData::TimeStamp() const
+ {
+ DASSERT( iTimeStamp );
+ return *iTimeStamp;
+ }
+
+
+const TDesC& CNcdNodeMetaData::NodeName() const
+ {
+ DASSERT( iName );
+ return *iName;
+ }
+
+void CNcdNodeMetaData::SetNodeNameL( const TDesC& aName )
+ {
+ HBufC* newName = aName.AllocL();
+ delete iName;
+ iName = newName;
+ }
+
+const TDesC& CNcdNodeMetaData::Description() const
+ {
+ DASSERT( iDescription );
+ return *iDescription;
+ }
+
+void CNcdNodeMetaData::SetDescriptionL(
+ const TDesC& aDescription )
+ {
+ HBufC* newDescription = aDescription.AllocL();
+ delete iDescription;
+ iDescription = newDescription;
+ }
+
+const TDesC& CNcdNodeMetaData::LayoutType() const
+ {
+ DASSERT( iLayoutType );
+ return *iLayoutType;
+ }
+
+const CNcdNodeDisclaimer& CNcdNodeMetaData::DisclaimerL() const
+ {
+ if ( iDisclaimer == NULL )
+ {
+ User::Leave( KErrNotFound );
+ }
+
+ return *iDisclaimer;
+ }
+
+void CNcdNodeMetaData::SetDisclaimer( CNcdNodeDisclaimer* aDisclaimer )
+ {
+ if ( iDisclaimer != NULL )
+ {
+ iDisclaimer->Close();
+ }
+ iDisclaimer = aDisclaimer;
+ }
+
+
+const CNcdNodeDisclaimer& CNcdNodeMetaData::MoreInfoL() const
+ {
+ if ( iMoreInfo == NULL )
+ {
+ User::Leave( KErrNotFound );
+ }
+
+ return *iMoreInfo;
+ }
+
+CNcdNodeIcon& CNcdNodeMetaData::IconL() const
+ {
+ if ( iIcon == NULL )
+ {
+ User::Leave( KErrNotFound );
+ }
+
+ return *iIcon;
+ }
+
+
+void CNcdNodeMetaData::SetIcon( CNcdNodeIcon* aIcon )
+ {
+ if ( iIcon )
+ {
+ iIcon->Close();
+ }
+ iIcon = aIcon;
+ }
+
+
+const CNcdNodeScreenshot& CNcdNodeMetaData::ScreenshotL() const
+ {
+ if ( iScreenshot == NULL )
+ {
+ User::Leave( KErrNotFound );
+ }
+
+ return *iScreenshot;
+ }
+
+
+const CNcdNodeSkin& CNcdNodeMetaData::SkinL() const
+ {
+ DASSERT( iSkin );
+ return *iSkin;
+ }
+
+
+CNcdNodePreview& CNcdNodeMetaData::PreviewL() const
+ {
+ if ( iPreview == NULL )
+ {
+ User::Leave( KErrNotFound );
+ }
+
+ return *iPreview;
+ }
+
+
+const CNcdNodeUpgrade& CNcdNodeMetaData::UpgradeL() const
+ {
+ if ( iUpgrade == NULL )
+ {
+ User::Leave( KErrNotFound );
+ }
+ return *iUpgrade;
+ }
+
+
+const CNcdNodeDependency& CNcdNodeMetaData::DependencyL() const
+ {
+ if ( iDependency == NULL )
+ {
+ User::Leave( KErrNotFound );
+ }
+ return *iDependency;
+ }
+
+
+const CNcdNodeContentInfo& CNcdNodeMetaData::ContentInfoL() const
+ {
+ if ( iContentInfo == NULL )
+ {
+ User::Leave( KErrNotFound );
+ }
+ return *iContentInfo;
+ }
+
+
+const CNcdServerSubscribableContent*
+ CNcdNodeMetaData::SubscribableContent() const
+ {
+ return iSubscribableContent;
+ }
+
+
+const RPointerArray<CNcdPurchaseOptionImpl>& CNcdNodeMetaData::PurchaseOptions() const
+ {
+ return iPurchaseOptions;
+ }
+
+CNcdPurchaseOptionImpl& CNcdNodeMetaData::PurchaseOptionByIdL(
+ const TDesC& aPurchaseOptionId ) const
+ {
+ DLTRACEIN((""));
+ for ( TInt i = 0; i < iPurchaseOptions.Count(); i++ )
+ {
+ if ( iPurchaseOptions[i]->Id() == aPurchaseOptionId )
+ {
+ return *iPurchaseOptions[i];
+ }
+ }
+
+ User::Leave( KErrNotFound );
+ CNcdPurchaseOptionImpl* foo( NULL );
+ return *foo;
+ }
+
+TBool CNcdNodeMetaData::AlwaysVisible() const
+ {
+ return iAlwaysVisible;
+ }
+
+
+void CNcdNodeMetaData::SetAlwaysVisible( TBool aValue )
+ {
+ iAlwaysVisible = aValue;
+ }
+
+
+void CNcdNodeMetaData::InternalizeL( MNcdPreminetProtocolDataEntity& aData )
+ {
+ DLTRACEIN((""));
+
+ // First create the new values
+ HBufC* tmpTimeStamp = aData.Timestamp().AllocLC();
+ HBufC* tmpName = aData.Name().AllocLC();
+ HBufC* tmpDescription = aData.Description().AllocLC();
+ HBufC* tmpLayoutType = aData.LayoutType().AllocLC();
+
+
+ DLTRACE(( _L("MetaData timestamp: %S"), tmpTimeStamp ));
+ DLTRACE(( _L("MetaData name: %S"), tmpName ));
+ DLTRACE(( _L("MetaData description: %S"), tmpDescription ));
+
+
+ delete iLayoutType;
+ iLayoutType = tmpLayoutType;
+ CleanupStack::Pop( tmpLayoutType );
+
+ delete iDescription;
+ iDescription = tmpDescription;
+ CleanupStack::Pop( tmpDescription );
+
+ delete iName;
+ iName = tmpName;
+ CleanupStack::Pop( tmpName );
+
+ delete iTimeStamp;
+ iTimeStamp = tmpTimeStamp;
+ CleanupStack::Pop( tmpTimeStamp );
+
+ if ( aData.Disclaimer() )
+ {
+ // New disclaimer info should be set
+
+ if ( iDisclaimer == NULL )
+ {
+ // Create disclaimer because it did not exist before.
+ iDisclaimer = CNcdNodeDisclaimer::NewL();
+ }
+ // Update disclaimer info.
+ iDisclaimer->InternalizeL( *aData.Disclaimer() );
+ }
+ else if ( iDisclaimer )
+ {
+ // Because new data does not contain disclaimer.
+ // Close old one and set the value NULL.
+ // Notice that CCatalogsCommunicalbe classes should be Closed
+ // instead of deleting.
+ // Because this object may still be left hanging for proxy object if it is used by UI,
+ // set the object obsolete. So, UI will know this if it is trying to internalize
+ // the hanging object.
+ iDisclaimer->SetAsObsolete( ETrue );
+ iDisclaimer->Close();
+ iDisclaimer = NULL;
+ }
+
+ if ( aData.Icon() )
+ {
+ // New icon info should be set.
+
+ if ( iIcon == NULL )
+ {
+ iIcon = CNcdNodeIcon::NewL( iNodeManager, *this );
+ }
+ iIcon->InternalizeL( aData );
+ }
+ else if ( iIcon != NULL )
+ {
+ // Notice that icons should not be deleted because
+ // all the CCatalogsCommunicable classes should be Closed instead.
+ // Because this object may still be left hanging for proxy object if it is used by UI,
+ // set the object obsolete. So, UI will know this if it is trying to internalize
+ // the hanging object.
+ iIcon->SetAsObsolete( ETrue );
+ iIcon->Close();
+ iIcon = NULL;
+ }
+
+ if ( aData.ScreenshotCount() > 0 )
+ {
+ // New screenshot info should be set.
+
+ if ( iScreenshot == NULL )
+ {
+ iScreenshot = CNcdNodeScreenshot::NewL( iNodeManager, *this );
+ }
+ iScreenshot->InternalizeL( aData );
+ }
+ else if ( iScreenshot != NULL )
+ {
+ // Notice that screenshots should not be deleted because
+ // all the CCatalogsCommunicable classes should be Closed instead.
+ // Because this object may still be left hanging for proxy object if it is used by UI,
+ // set the object obsolete. So, UI will know this if it is trying to internalize
+ // the hanging object.
+ iScreenshot->SetAsObsolete( ETrue );
+ iScreenshot->Close();
+ iScreenshot = NULL;
+ }
+
+ if ( aData.Skin() )
+ {
+ // New skin info should be set.
+
+ if ( iSkin == NULL )
+ {
+ iSkin = CNcdNodeSkin::NewL();
+ }
+ iSkin->InternalizeL( aData );
+ }
+ else if ( iSkin != NULL )
+ {
+ // Notice that skins should not be deleted because
+ // all the CCatalogsCommunicable classes should be Closed instead.
+ // Because this object may still be left hanging for proxy object if it is used by UI,
+ // set the object obsolete. So, UI will know this if it is trying to internalize
+ // the hanging object.
+ iSkin->SetAsObsolete( ETrue );
+ iSkin->Close();
+ iSkin = NULL;
+ }
+
+ if ( aData.DownloadableContent() )
+ {
+ // New content info should be set.
+
+ if ( iContentInfo == NULL )
+ {
+ iContentInfo = CNcdNodeContentInfo::NewL();
+ }
+ iContentInfo->InternalizeL( aData );
+ InternalizeInstallFromContentInfoL();
+ }
+ else if ( iContentInfo != NULL )
+ {
+ DLINFO(("No downloadable content"));
+ // Notice that content info should not be deleted because
+ // all the CCatalogsCommunicable classes should be Closed instead.
+ // Because this object may still be left hanging for proxy object if it is used by UI,
+ // set the object obsolete. So, UI will know this if it is trying to internalize
+ // the hanging object.
+ iContentInfo->SetAsObsolete( ETrue );
+ iContentInfo->Close();
+ iContentInfo = NULL;
+ }
+
+ if ( aData.PreviewCount() > 0 )
+ {
+ if ( iPreview == NULL )
+ {
+ iPreview = CNcdNodePreview::NewL( *this, iNodeManager );
+ }
+ iPreview->InternalizeL( aData );
+ }
+ else if ( iPreview != NULL )
+ {
+ // Because this object may still be left hanging for proxy object if it is used by UI,
+ // set the object obsolete. So, UI will know this if it is trying to internalize
+ // the hanging object.
+ iPreview->SetAsObsolete( ETrue );
+ iPreview->Close();
+ iPreview = NULL;
+ }
+
+ // Create upgrade object if necessary
+ if ( aData.DownloadableContent() != NULL )
+ {
+ if ( iUpgrade == NULL )
+ {
+ iUpgrade = CNcdNodeUpgrade::NewL( *this );
+ }
+ TPtrC version( KNullDesC );
+ if ( iContentInfo )
+ {
+ version.Set( iContentInfo->Version() );
+ }
+ TRAPD( upgradeErr, iUpgrade->InternalizeL( aData, version ) );
+ TBool upgradeExists = HandleContentUpgradeL();
+
+ // HandleContentUpgradeL checks CNcdNodeContentInfo and
+ // CNcdNodeInstall for the need of upgrade interfaces
+ if ( upgradeErr == KErrNotFound &&
+ !upgradeExists )
+ {
+ DLTRACE(("No upgrade"));
+ // The given data did not contain any information about upgrade.
+ // So, delete the created upgrade object.
+ // Because this object may still be left hanging for proxy object if it is used by UI,
+ // set the object obsolete. So, UI will know this if it is trying to internalize
+ // the hanging object.
+ iUpgrade->SetAsObsolete( ETrue );
+ iUpgrade->Close();
+ iUpgrade = NULL;
+ }
+
+ LeaveIfNotErrorL( upgradeErr, KErrNotFound );
+ }
+ else if ( iUpgrade != NULL )
+ {
+ // Because this object may still be left hanging for proxy object if it is used by UI,
+ // set the object obsolete. So, UI will know this if it is trying to internalize
+ // the hanging object.
+ iUpgrade->SetAsObsolete( ETrue );
+ iUpgrade->Close();
+ iUpgrade = NULL;
+ }
+
+
+ // Create dependency object if necessary
+ if ( aData.DownloadableContent() != NULL )
+ {
+ if ( iDependency == NULL )
+ {
+ iDependency = CNcdNodeDependency::NewL( *this );
+ }
+ TRAPD( dependencyErr, iDependency->InternalizeL( aData ) );
+ if ( dependencyErr == KErrNotFound )
+ {
+ DLTRACE(("No dependency, deleting the object"));
+ // The given data did not contain any information about dependency.
+ // So, delete the created object.
+ // Because this object may still be left hanging for proxy object if it is used by UI,
+ // set the object obsolete. So, UI will know this if it is trying to internalize
+ // the hanging object.
+ iDependency->SetAsObsolete( ETrue );
+ iDependency->Close();
+ iDependency = NULL;
+ }
+ else if ( dependencyErr != KErrNone )
+ {
+ // Some error occurred. So let this leave.
+ User::Leave( dependencyErr );
+ }
+ }
+ else if ( iDependency != NULL )
+ {
+ DLTRACE(("Removing old dependency"));
+ // Because this object may still be left hanging for proxy object if it is used by UI,
+ // set the object obsolete. So, UI will know this if it is trying to internalize
+ // the hanging object.
+ iDependency->SetAsObsolete( ETrue );
+ iDependency->Close();
+ iDependency = NULL;
+ }
+
+
+
+ // Subscribable content
+ const MNcdPreminetProtocolDataEntityContent* subscribableContent =
+ aData.SubscribableContent();
+
+ if ( subscribableContent != NULL )
+ {
+ DLINFO(( "Subscribable content element found from protocol-object" ));
+
+ if ( iSubscribableContent == NULL )
+ {
+ iSubscribableContent = CNcdServerSubscribableContent::NewL();
+ }
+ iSubscribableContent->InternalizeL( *subscribableContent );
+ }
+
+
+ if ( aData.MoreInfo() )
+ {
+ if ( iMoreInfo == NULL )
+ {
+ iMoreInfo = CNcdNodeDisclaimer::NewL();
+ }
+ iMoreInfo->InternalizeL( *aData.MoreInfo() );
+ }
+ else if ( iMoreInfo )
+ {
+ // Because this object may still be left hanging for proxy object if it is used by UI,
+ // set the object obsolete. So, UI will know this if it is trying to internalize
+ // the hanging object.
+ iMoreInfo->SetAsObsolete( ETrue );
+ iMoreInfo->Close();
+ iMoreInfo = NULL;
+ }
+
+ iDetails.ResetAndDestroy();
+
+ for ( TInt i = 0 ; i < aData.DetailCount() ; i++ )
+ {
+ DLTRACE(( _L("Detail id=%S, value=%S"),
+ &aData.DetailL( i ).Id(), &aData.DetailL( i ).Value()));
+ if( aData.DetailL( i ).Id() == KNullDesC )
+ {
+ DLTRACE(("Empty id -> not adding detail!"));
+ continue;
+ }
+ CNcdKeyValuePair* detail = CNcdKeyValuePair::NewLC(
+ aData.DetailL( i ).Id(), aData.DetailL( i ).Value() );
+ iDetails.AppendL( detail );
+ CleanupStack::Pop( detail );
+ }
+
+
+ // Create or reinternalize purchase options :
+
+ const TInt KPurchaseOptionCount( aData.PurchaseOptionCount() );
+
+ DLINFO(( "Amount of purchaseoptions found from protocol-object: %d",
+ KPurchaseOptionCount ));
+
+ TInt purchaseOptionIndex( 0 );
+ while ( purchaseOptionIndex < KPurchaseOptionCount )
+ {
+ const MNcdPreminetProtocolPurchaseOption& tmpOption =
+ aData.PurchaseOptionL( purchaseOptionIndex );
+ InternalizePurchaseOptionL( tmpOption );
+ ++purchaseOptionIndex;
+ }
+
+ // Remove purchase options that were removed from the server
+ RemoveNotUpdatedPurchaseOptions();
+
+ DLTRACEOUT((""));
+ }
+
+
+void CNcdNodeMetaData::InternalizeContentInfoL(
+ const MNcdPurchaseDetails& aDetails )
+ {
+ DLTRACEIN((""));
+
+ if ( !iContentInfo )
+ {
+ iContentInfo = CNcdNodeContentInfo::NewL();
+ }
+
+ iContentInfo->InternalizeL( aDetails );
+ }
+
+
+void CNcdNodeMetaData::InternalizeUriContentL(
+ const MNcdPurchaseDetails& aDetails )
+ {
+ DLTRACEIN((""));
+
+ if ( !iUriContent )
+ {
+ iUriContent = CNcdNodeUriContent::NewL();
+ if ( !iUriContent->InternalizeL( aDetails ) )
+ {
+ iUriContent->Close();
+ iUriContent = NULL;
+ }
+ }
+ else
+ {
+ iUriContent->InternalizeL( aDetails );
+ }
+
+ DLTRACEOUT((""));
+ }
+
+
+CNcdNodeDownload& CNcdNodeMetaData::DownloadL()
+ {
+ if( iDownload == NULL )
+ {
+ User::Leave( KErrNotFound );
+ }
+
+ return *iDownload;
+ }
+
+
+void CNcdNodeMetaData::InternalizeDownloadL( const MNcdPurchaseDetails& aDetails )
+ {
+ DLTRACEIN((""));
+
+ if ( !iDownload )
+ {
+ iDownload = CNcdNodeDownload::NewL();
+
+ // Delete node download if the internalization failed
+ if ( !iDownload->InternalizeL( aDetails ) )
+ {
+ iDownload->Close();
+ iDownload = NULL;
+ }
+ }
+ else
+ {
+ iDownload->InternalizeL( aDetails );
+ }
+ DLTRACEOUT((""));
+ }
+
+
+CNcdNodeInstall& CNcdNodeMetaData::InstallL()
+ {
+ if( iInstall == NULL )
+ {
+ User::Leave( KErrNotFound );
+ }
+
+ return *iInstall;
+ }
+
+
+void CNcdNodeMetaData::InternalizeInstallL( const MNcdPurchaseDetails& aDetails )
+ {
+ DLTRACEIN((""));
+
+ if ( !iInstall )
+ {
+ iInstall = CNcdNodeInstall::NewL( *this );
+ if ( !iInstall->InternalizeL( aDetails ) )
+ {
+ iInstall->Close();
+ iInstall = NULL;
+ }
+ }
+ else
+ {
+ iInstall->InternalizeL( aDetails );
+ }
+
+ // Get version of bought content from purchase history so that
+ // we can compare it with content info in HandleContentUpgradeL
+ TRAPD( err, TCatalogsVersion::ConvertL(
+ iBoughtContentVersion, aDetails.Version() ) );
+
+ LeaveIfNotErrorL( err, KErrArgument, KErrGeneral );
+
+ DLTRACEOUT((""));
+ }
+
+
+void CNcdNodeMetaData::InternalizeInstallFromContentInfoL()
+ {
+ DLTRACEIN((""));
+ if ( iContentInfo && iContentInfo->Uid() != TUid::Null() )
+ {
+ TBool create = !iInstall;
+ if ( create )
+ {
+ DLTRACE(("No install, creating"));
+ iInstall = CNcdNodeInstall::NewL( *this );
+ }
+
+ // Only delete install if it was created in this method
+ if ( !iInstall->InternalizeContentInfoL() && create )
+ {
+ DLTRACE(("App is not installed, deleting install"));
+ iInstall->Close();
+ iInstall = NULL;
+ }
+ }
+ DLTRACEOUT((""));
+ }
+
+
+void CNcdNodeMetaData::InternalizeDependencyL(
+ const MNcdPurchaseDetails& aDetails )
+ {
+ DLTRACEIN((""));
+ if ( !iDependency )
+ {
+ iDependency = CNcdNodeDependency::NewL( *this );
+ if ( !iDependency->InternalizeFromPurchaseDetailsL( aDetails ) )
+ {
+ iDependency->Close();
+ iDependency = NULL;
+ }
+ }
+ else
+ {
+ iDependency->InternalizeFromPurchaseDetailsL( aDetails );
+ }
+ DLTRACEOUT(("dependency internalized from purchasehistory"));
+ }
+
+void CNcdNodeMetaData::InternalizeIconL( const MNcdPurchaseDetails& aDetails )
+ {
+ DLTRACEIN((""));
+ if( aDetails.HasIcon() )
+ {
+ DLTRACE(("Purchase details have icon"));
+ // Only use icon from PH if there is no icon previously
+ // (icon may change on server whilst the icon in PH is the one that
+ // was available during purchase ).
+ if( !iIcon )
+ {
+ iIcon = CNcdNodeIcon::NewL( iNodeManager, *this, ETrue );
+ }
+ }
+ }
+
+CNcdPurchaseDetails* CNcdNodeMetaData::PurchaseDetailsLC( TBool aLoadIcon ) const
+ {
+ DLTRACEIN((""));
+
+ return NcdPurchaseHistoryUtils::PurchaseDetailsLC(
+ iNodeManager.PurchaseHistory(),
+ iIdentifier->ClientUid(),
+ *iIdentifier,
+ aLoadIcon );
+ }
+
+
+TBool CNcdNodeMetaData::HandleContentUpgradeL()
+ {
+ DLTRACEIN((""));
+ DLNODEID(( Identifier() ));
+ if ( iContentInfo )
+ {
+ DLTRACE(("Content info exists, check if content upgrades something"));
+
+ TCatalogsVersion version;
+ TRAPD( err, TCatalogsVersion::ConvertL(
+ version, iContentInfo->Version() ) );
+
+ LeaveIfNotErrorL( err, KErrArgument, KErrGeneral );
+
+ // First compare version number to purchase history because it's highest priority
+ if ( version == iBoughtContentVersion )
+ {
+ if ( iUpgrade )
+ {
+ // Reset content upgrade status
+ iUpgrade->SetContentUpgradesL(
+ EFalse,
+ TUid::Null(),
+ KNullDesC );
+ }
+ DLTRACEOUT(("Version in contentinfo matches bought version, no upgrade"));
+ return EFalse;
+ }
+
+
+ // ContentCount() ensures that there's actually something installed, otherwise
+ // we would end up checking against the same contentinfo if the content is
+ // a SIS app and some version of it is already installed
+ if ( iInstall && iInstall->ContentCount() )
+ {
+
+ TCatalogsVersion installVersion( iInstall->ContentVersion() );
+ DLTRACE(("Version from install: %d.%d.%d",
+ installVersion.iMajor, installVersion.iMinor, installVersion.iBuild ));
+
+ // IsAllContentInstalledL returns true if all content files are installed
+ if ( installVersion != TCatalogsVersion() &&
+ version > installVersion &&
+ iInstall->IsAllContentInstalledL() )
+ {
+
+ if ( !iUpgrade )
+ {
+ DLTRACE(("Creating upgrade"));
+ iUpgrade = CNcdNodeUpgrade::NewL( *this );
+ }
+
+ // content is an upgrade
+ iUpgrade->SetContentUpgradesL(
+ ETrue,
+ iContentInfo->Uid(),
+ iContentInfo->Version() );
+ return ETrue;
+ }
+ }
+ // If content is an application, check if it upgrades. "Else if" is necessary
+ // because otherwise content version check could be overridden by application version
+ // check
+ else if ( iContentInfo->Uid() != TUid::Null() )
+ {
+ TNcdApplicationStatus contentVersion(
+ ENcdApplicationNotInstalled );
+
+ TRAPD( err,
+ contentVersion = CNcdProviderUtils::IsApplicationInstalledL(
+ iContentInfo->Uid(),
+ iContentInfo->Version() ) );
+
+ // Ignore errors in version conversion
+ LeaveIfNotErrorL( err, KErrArgument, KErrGeneral );
+
+ if ( contentVersion == ENcdApplicationOlderVersionInstalled )
+ {
+ if ( !iUpgrade )
+ {
+ DLTRACE(("Creating upgrade"));
+ iUpgrade = CNcdNodeUpgrade::NewL( *this );
+ }
+
+ // Set upgrade data which will be available through the API
+ iUpgrade->SetContentUpgradesL(
+ ETrue,
+ iContentInfo->Uid(),
+ iContentInfo->Version() );
+
+ DLTRACEOUT(("Content upgrades"));
+ return ETrue;
+ }
+ }
+ }
+
+ if ( iUpgrade )
+ {
+ // Reset content upgrade status
+ iUpgrade->SetContentUpgradesL(
+ EFalse,
+ TUid::Null(),
+ KNullDesC );
+ }
+ return EFalse;
+ }
+
+
+void CNcdNodeMetaData::SetDeleteSoon( TBool aDeleteSoon )
+ {
+ iDeleteSoon = aDeleteSoon;
+ }
+
+
+TBool CNcdNodeMetaData::DeleteSoon() const
+ {
+ return iDeleteSoon;
+ }
+
+
+void CNcdNodeMetaData::ExternalizeL( RWriteStream& aStream )
+ {
+ DLTRACEIN((""));
+
+ // Set all the membervariable values to the stream. So,
+ // that the stream may be used later to create a new
+ // object.
+
+ // First insert data that node manager will use to
+ // create this class object
+ DLTRACE(("Meta extern class id: %d", iClassId));
+ aStream.WriteInt32L( iClassId );
+
+ // Write the data that will be used when internalize function
+ // is called.
+
+ ExternalizeDesL( TimeStamp(), aStream );
+ ExternalizeDesL( NodeName(), aStream );
+ ExternalizeDesL( Description(), aStream );
+ ExternalizeDesL( LayoutType(), aStream );
+
+ aStream.WriteInt8L( iAlwaysVisible );
+
+ if ( iDisclaimer )
+ {
+ aStream.WriteInt32L( 1 );
+ iDisclaimer->ExternalizeL( aStream );
+ }
+ else
+ {
+ aStream.WriteInt32L( 0 );
+ }
+
+ if ( iIcon )
+ {
+ aStream.WriteInt32L( 1 );
+ iIcon->ExternalizeL( aStream );
+ }
+ else
+ {
+ aStream.WriteInt32L( 0 );
+ }
+
+ if ( iScreenshot )
+ {
+ aStream.WriteInt32L( 1 );
+ iScreenshot->ExternalizeL( aStream );
+ }
+ else
+ {
+ aStream.WriteInt32L( 0 );
+ }
+
+ if ( iSkin )
+ {
+ aStream.WriteInt32L( 1 );
+ iSkin->ExternalizeL( aStream );
+ }
+ else
+ {
+ aStream.WriteInt32L( 0 );
+ }
+
+ if ( iPreview )
+ {
+ aStream.WriteInt32L( 1 );
+ iPreview->ExternalizeL( aStream );
+ }
+ else
+ {
+ aStream.WriteInt32L( 0 );
+ }
+
+ if ( iContentInfo )
+ {
+ aStream.WriteInt32L( 1 );
+ iContentInfo->ExternalizeL( aStream );
+ }
+ else
+ {
+ aStream.WriteInt32L( 0 );
+ }
+
+ if ( iUpgrade )
+ {
+ aStream.WriteInt32L( 1 );
+ iUpgrade->ExternalizeL( aStream );
+ }
+ else
+ {
+ aStream.WriteInt32L( 0 );
+ }
+
+ if ( iDependency )
+ {
+ aStream.WriteInt32L( 1 );
+ iDependency->ExternalizeL( aStream );
+ }
+ else
+ {
+ aStream.WriteInt32L( 0 );
+ }
+
+ // Subscribable content
+ if ( iSubscribableContent )
+ {
+ aStream.WriteInt32L( ETrue );
+ iSubscribableContent->ExternalizeL( aStream );
+ }
+ else
+ {
+ aStream.WriteInt32L( EFalse );
+ }
+
+
+ // Purchase options
+
+ TInt purchaseOptionCount( iPurchaseOptions.Count() );
+ DLINFO(("Externalizing purchase options: %d", purchaseOptionCount ));
+ aStream.WriteInt32L( purchaseOptionCount );
+
+ TInt purchaseOptionIndex( 0 );
+ while ( purchaseOptionIndex < purchaseOptionCount )
+ {
+ iPurchaseOptions[purchaseOptionIndex]->ExternalizeL( aStream );
+ ++purchaseOptionIndex;
+ }
+
+ if ( iMoreInfo )
+ {
+ aStream.WriteInt32L( 1 );
+ iMoreInfo->ExternalizeL( aStream );
+ }
+ else
+ {
+ aStream.WriteInt32L( 0 );
+ }
+
+ aStream.WriteInt32L( iDetails.Count() );
+ for( TInt i = 0 ; i < iDetails.Count() ; i++ )
+ {
+ iDetails[i]->ExternalizeL( aStream );
+ }
+
+ DLTRACEOUT((""));
+ }
+
+
+void CNcdNodeMetaData::InternalizeL( RReadStream& aStream )
+ {
+ DLTRACEIN((""));
+
+ // NOTICE that this internalize function supposes that
+ // classid, namespace and metadataid info, that are
+ // inserted during externalization, are already read from
+ // the stream before calling this function.
+
+ InternalizeDesL( iTimeStamp, aStream );
+ InternalizeDesL( iName, aStream );
+ InternalizeDesL( iDescription, aStream );
+ InternalizeDesL( iLayoutType, aStream );
+
+ iAlwaysVisible = aStream.ReadInt8L();
+
+ TInt32 disclaimerExists = aStream.ReadInt32L();
+ if ( disclaimerExists )
+ {
+ if ( iDisclaimer == NULL )
+ {
+ iDisclaimer = CNcdNodeDisclaimer::NewL();
+ }
+ iDisclaimer->InternalizeL( aStream );
+ }
+ else if ( iDisclaimer )
+ {
+ // Because icon should not exist, Close it.
+ iDisclaimer->Close();
+ iDisclaimer = NULL;
+ }
+
+ TInt32 iconExists = aStream.ReadInt32L();
+ if ( iconExists )
+ {
+ if ( iIcon == NULL )
+ {
+ iIcon = CNcdNodeIcon::NewL( iNodeManager, *this );
+ }
+ iIcon->InternalizeL( aStream );
+ }
+ else if ( iIcon )
+ {
+ // Because icon should not exist, delete it.
+ iIcon->Close();
+ iIcon = NULL;
+ }
+
+ TInt32 screenshotExists = aStream.ReadInt32L();
+ if ( screenshotExists )
+ {
+ if ( iScreenshot == NULL )
+ {
+ iScreenshot = CNcdNodeScreenshot::NewL( iNodeManager, *this );
+ }
+ iScreenshot->InternalizeL( aStream );
+ }
+ else if ( iScreenshot )
+ {
+ // Because screenshot should not exist, delete it.
+ iScreenshot->Close();
+ iScreenshot = NULL;
+ }
+
+ TInt32 skinExists = aStream.ReadInt32L();
+ if ( skinExists )
+ {
+ if ( iSkin == NULL )
+ {
+ iSkin = CNcdNodeSkin::NewL();
+ }
+ iSkin->InternalizeL( aStream );
+ }
+ else if ( iSkin )
+ {
+ // Because icon should not exist, Close it.
+ iSkin->Close();
+ iSkin = NULL;
+ }
+
+ TInt32 previewExists = aStream.ReadInt32L();
+ if ( previewExists )
+ {
+ if ( iPreview == NULL )
+ {
+ iPreview = CNcdNodePreview::NewL( *this, iNodeManager );
+ }
+ iPreview->InternalizeL( aStream );
+ }
+ else if ( iPreview )
+ {
+ // Because preview should not exist, Close it.
+ iPreview->Close();
+ iPreview = NULL;
+ }
+
+ DLTRACE(("Internalizing content info"));
+ TInt32 contentInfoExists = aStream.ReadInt32L();
+ if ( contentInfoExists )
+ {
+ if ( iContentInfo == NULL )
+ {
+ iContentInfo = CNcdNodeContentInfo::NewL();
+ }
+ iContentInfo->InternalizeL( aStream );
+ InternalizeInstallFromContentInfoL();
+ }
+ else if ( iContentInfo )
+ {
+ // Because content info should not exist, Close it.
+ iContentInfo->Close();
+ iContentInfo = NULL;
+ }
+
+ DLTRACE(("Internalizing upgrade for metadata:"));
+ DLNODEID(( Identifier() ));
+ TInt32 upgradeExists = aStream.ReadInt32L();
+ if ( upgradeExists )
+ {
+ if ( iUpgrade == NULL )
+ {
+ iUpgrade = CNcdNodeUpgrade::NewL( *this );
+ }
+ iUpgrade->InternalizeL( aStream );
+
+ // This requires that both CNcdNodeContentInfo &
+ // CNcdNodeInstall are up-to-date
+ HandleContentUpgradeL();
+ }
+ else
+ {
+ if ( iUpgrade )
+ {
+ // Because upgrade should not exist, Close it.
+ iUpgrade->Close();
+ iUpgrade = NULL;
+ }
+ // Upgrade situation may have changed due to software
+ // uninstallations so we update to current situation
+ // HandleContentUpgradeL creates iUpgrade if necessary
+ HandleContentUpgradeL();
+ }
+
+ TInt32 dependencyExists = aStream.ReadInt32L();
+ if ( dependencyExists )
+ {
+ if ( iDependency == NULL )
+ {
+ iDependency = CNcdNodeDependency::NewL( *this );
+ }
+ iDependency->InternalizeL( aStream );
+ }
+ else if ( iDependency )
+ {
+ // Because preview should not exist, Close it.
+ iDependency->Close();
+ iDependency = NULL;
+ }
+
+
+ // Subscribable content
+ TBool subscribable = aStream.ReadInt32L();
+ if ( subscribable )
+ {
+ if ( iSubscribableContent == NULL )
+ {
+ iSubscribableContent = CNcdServerSubscribableContent::NewL();
+ }
+ iSubscribableContent->InternalizeL( aStream );
+ }
+
+
+ // Create or reinternalize purchase options :
+
+ const TInt KPurchaseOptionCount( aStream.ReadInt32L() );
+
+ DLINFO(( "Amount of purchaseoptions found from the stream: %d",
+ KPurchaseOptionCount ));
+
+ TInt purchaseOptionIndex( 0 );
+ while ( purchaseOptionIndex < KPurchaseOptionCount )
+ {
+ InternalizePurchaseOptionL( aStream );
+ ++purchaseOptionIndex;
+ }
+
+ // Remove purchase options that were removed from the server
+ RemoveNotUpdatedPurchaseOptions();
+
+
+ TInt32 moreInfoExists = aStream.ReadInt32L();
+ if ( moreInfoExists )
+ {
+ if ( iMoreInfo == NULL )
+ {
+ iMoreInfo = CNcdNodeDisclaimer::NewL();
+ }
+ iMoreInfo->InternalizeL( aStream );
+ }
+ else if ( iMoreInfo )
+ {
+ // Because icon should not exist, Close it.
+ iMoreInfo->Close();
+ iMoreInfo = NULL;
+ }
+
+ iDetails.ResetAndDestroy();
+ TInt32 detailCount = aStream.ReadInt32L();
+ for( TInt i = 0 ; i < detailCount ; i++ )
+ {
+ CNcdKeyValuePair* detail = CNcdKeyValuePair::NewLC( aStream );
+ iDetails.AppendL( detail );
+ CleanupStack::Pop( detail );
+ }
+
+ DLTRACEOUT((""));
+ }
+
+
+void CNcdNodeMetaData::ReceiveMessage( MCatalogsBaseMessage* aMessage,
+ TInt aFunctionNumber )
+ {
+ DLTRACEIN((""));
+
+ DASSERT( aMessage );
+
+ // Now, we can be sure that rest of the time iMessage exists.
+ // This member variable is set for the CounterPartLost function.
+ iMessage = aMessage;
+
+ TInt trapError( KErrNone );
+
+ switch( aFunctionNumber )
+ {
+ case NcdNodeFunctionIds::ENcdInternalize:
+ TRAP( trapError, InternalizeRequestL( *aMessage ) );
+ break;
+
+ case NcdNodeFunctionIds::ENcdRelease:
+ ReleaseRequest( *aMessage );
+ break;
+
+ case NcdNodeFunctionIds::ENcdUserDataHandle:
+ TRAP( trapError, UserDataHandleRequestL( *aMessage ) );
+ break;
+
+ case NcdNodeFunctionIds::ENcdDisclaimerHandle:
+ TRAP( trapError, DisclaimerHandleRequestL( *aMessage ) );
+ break;
+
+ case NcdNodeFunctionIds::ENcdIconHandle:
+ TRAP( trapError, IconHandleRequestL( *aMessage ) );
+ break;
+
+ case NcdNodeFunctionIds::ENcdScreenshotHandle:
+ TRAP( trapError, ScreenshotHandleRequestL( *aMessage ) );
+ break;
+
+ case NcdNodeFunctionIds::ENcdSkinHandle:
+ TRAP( trapError, SkinHandleRequestL( *aMessage ) );
+ break;
+
+ case NcdNodeFunctionIds::ENcdUriContentHandle:
+ TRAP( trapError, UriContentHandleRequestL( *aMessage ) );
+ break;
+
+ case NcdNodeFunctionIds::ENcdPreviewHandle:
+ TRAP( trapError, PreviewHandleRequestL( *aMessage ) );
+ break;
+
+ case NcdNodeFunctionIds::ENcdContentInfoHandle:
+ TRAP( trapError, ContentInfoHandleRequestL( *aMessage ) );
+ break;
+
+ case NcdNodeFunctionIds::ENcdUpgradeHandle:
+ TRAP( trapError, UpgradeHandleRequestL( *aMessage ) );
+ break;
+
+ case NcdNodeFunctionIds::ENcdDependencyHandle:
+ TRAP( trapError, DependencyHandleRequestL( *aMessage ) );
+ break;
+
+ case NcdNodeFunctionIds::ENcdInternalizePurchaseHistory:
+ TRAP( trapError, InternalizePurchaseHistoryRequestL( *aMessage ) );
+ break;
+
+ case NcdNodeFunctionIds::ENcdInternalizePurchaseMeans:
+ TRAP( trapError, InternalizePurchaseMeansRequestL( *aMessage ) );
+ break;
+
+ case NcdNodeFunctionIds::ENcdPurchaseOptionIds:
+ TRAP( trapError, PurchaseOptionIdsRequestL( *aMessage ) );
+ break;
+
+ case NcdNodeFunctionIds::ENcdInstallHandle:
+ TRAP( trapError, InstallHandleRequestL( *aMessage ) );
+ break;
+
+ case NcdNodeFunctionIds::ENcdDownloadHandle:
+ TRAP( trapError, DownloadHandleRequestL( *aMessage ) );
+ break;
+
+ case NcdNodeFunctionIds::ENcdMoreInfoHandle:
+ TRAP( trapError, MoreInfoHandleRequestL( *aMessage ) );
+ break;
+
+ case NcdNodeFunctionIds::ENcdIsPurchaseSupported:
+ TRAP( trapError, IsPurchaseSupportedRequestL( *aMessage ) );
+ break;
+
+ default:
+ DLERROR(("Unidentified function request"));
+ DASSERT( EFalse );
+ 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.
+ aMessage->CompleteAndRelease( trapError );
+ }
+
+ // Because the message should not be used after this, set it NULL.
+ // So, CounterPartLost function will know that no messages are
+ // waiting the response at the moment.
+ iMessage = NULL;
+
+ if ( aFunctionNumber == NcdNodeFunctionIds::ENcdRelease )
+ {
+ // Because release was called for this object it may be time to
+ // delete this object. Inform manager about the release so it may
+ // close this object and clear the cache if needed.
+ // Notice that if the manager closes this object then this object will
+ // be deleted. It is safe to do here because no memeber variables are
+ // needed here after the call.
+ NodeManager().MetaDataReleased( *this );
+ }
+
+ DLTRACEOUT((""));
+ }
+
+
+void CNcdNodeMetaData::CounterPartLost( const MCatalogsSession& aSession )
+ {
+ // This function may be called whenever -- when the message is waiting
+ // response or when the message does not exist.
+ // iMessage may be NULL here, because in the end of the
+ // ReceiveMessage it is set to NULL. The life time of the message
+ // ends shortly after CompleteAndRelease is called.
+ if ( iMessage != NULL )
+ {
+ iMessage->CounterPartLost( aSession );
+ }
+ }
+
+void CNcdNodeMetaData::InternalizeRequestL( MCatalogsBaseMessage& aMessage ) const
+ {
+ DLTRACEIN((""));
+
+ CBufBase* buf = CBufFlat::NewL( KBufExpandSize );
+ CleanupStack::PushL( buf );
+
+ RBufWriteStream stream( *buf );
+ CleanupClosePushL( stream );
+
+
+ // Include all the necessary node data to the stream
+ ExternalizeDataForRequestL( stream );
+
+
+ // Commits data to the stream when closing.
+ CleanupStack::PopAndDestroy( &stream );
+
+
+ if ( buf->Size() > 0 )
+ {
+ DLINFO(( "Completing the message, buf len: %d", buf->Ptr(0).Length() ));
+ }
+ // If this leaves, ReceiveMessge will complete the message.
+ aMessage.CompleteAndReleaseL( buf->Ptr( 0 ), KErrNone );
+
+
+ DLINFO(("Deleting the buf"));
+ CleanupStack::PopAndDestroy( buf );
+
+ DLTRACEOUT((""));
+ }
+
+
+void CNcdNodeMetaData::ExternalizeDataForRequestL( RWriteStream& aStream ) const
+ {
+ DLTRACEIN((""));
+
+ DLINFO(("Class ID: %d", ClassId() ));
+ // Metadata existed. So, insert info that meta data was found.
+ aStream.WriteInt32L( ClassId() );
+
+ iIdentifier->ExternalizeL( aStream );
+ ExternalizeDesL( NodeName(), aStream );
+ ExternalizeDesL( Description(), aStream );
+ ExternalizeDesL( LayoutType(), aStream );
+
+ aStream.WriteInt8L( iAlwaysVisible );
+
+ aStream.WriteInt32L( iDetails.Count() );
+ for( TInt i = 0 ; i < iDetails.Count() ; i++ )
+ {
+ iDetails[i]->ExternalizeL( aStream );
+ }
+
+ DLTRACEOUT((""));
+ }
+
+
+void CNcdNodeMetaData::InternalizePurchaseMeansRequestL(
+ MCatalogsBaseMessage& aMessage ) const
+ {
+ DLTRACEIN((""));
+
+ // Parse the input message and create a descriptor array containing
+ // the purchase option ids which should be externalized for the request.
+ CDesCArray* purchaseOptionIds = new( ELeave ) CDesCArrayFlat( 5 );
+ CleanupStack::PushL( purchaseOptionIds );
+ HBufC8* input = HBufC8::NewLC( aMessage.InputLength() );
+ TPtr8 inputPtr = input->Des();
+ aMessage.ReadInput( inputPtr );
+ RDesReadStream inputStream( *input );
+ CleanupClosePushL( inputStream );
+
+ TInt poCount = inputStream.ReadInt32L();
+ for ( TInt i = 0; i < poCount; i++ )
+ {
+ HBufC* tmpId( NULL );
+ InternalizeDesL( tmpId, inputStream );
+ CleanupStack::PushL( tmpId );
+ purchaseOptionIds->AppendL( *tmpId );
+ CleanupStack::PopAndDestroy( tmpId );
+ }
+
+ CleanupStack::PopAndDestroy( &inputStream );
+ CleanupStack::PopAndDestroy( input );
+
+ CBufBase* buf = CBufFlat::NewL( KBufExpandSize );
+ CleanupStack::PushL( buf );
+
+ RBufWriteStream stream( *buf );
+ CleanupClosePushL( stream );
+
+ // Include all the necessary purchase data to the stream
+ MCatalogsSession& session = aMessage.Session();
+ ExternalizePurchaseMeansForRequestL( *purchaseOptionIds, stream, session );
+
+ // Commits data to the stream when closing.
+ CleanupStack::PopAndDestroy( &stream );
+
+
+ if ( buf->Size() > 0 )
+ {
+ DLINFO(( "Completing the message, buf len: %d", buf->Ptr(0).Length() ));
+ }
+ // If this leaves, ReceiveMessge will complete the message.
+ aMessage.CompleteAndReleaseL( buf->Ptr( 0 ), KErrNone );
+
+
+ DLINFO(("Deleting the buf"));
+ CleanupStack::PopAndDestroy( buf );
+ CleanupStack::PopAndDestroy( purchaseOptionIds );
+
+ DLTRACEOUT((""));
+ }
+
+
+void CNcdNodeMetaData::ExternalizePurchaseMeansForRequestL(
+ const CDesCArray& aPurchaseOptionIds,
+ RWriteStream& aStream,
+ MCatalogsSession& aSession ) const
+ {
+
+ // Subscribable content
+ if ( iSubscribableContent != NULL )
+ {
+ aStream.WriteInt32L( ETrue );
+ iSubscribableContent->ExternalizeL( aStream );
+ }
+ else
+ {
+ aStream.WriteInt32L( EFalse );
+ }
+
+
+ // this is the same as handle amount
+ TInt purchaseOptionAmount( aPurchaseOptionIds.Count() );
+ aStream.WriteInt32L( purchaseOptionAmount );
+
+ for ( TInt i = 0; i < purchaseOptionAmount; i++ )
+ {
+ CNcdPurchaseOptionImpl& tmpPurchaseOption = PurchaseOptionByIdL(
+ aPurchaseOptionIds[i] );
+ TInt tmpHandle( aSession.AddObjectL( &tmpPurchaseOption ) );
+
+ TRAPD( addError, aStream.WriteInt32L( tmpHandle ) );
+ if ( addError != KErrNone )
+ {
+ // Should all other added objects be removed from
+ // the session also?
+ aSession.RemoveObject( tmpHandle );
+ User::Leave( addError );
+ }
+ }
+ }
+
+
+void CNcdNodeMetaData::InternalizePurchaseHistoryRequestL( MCatalogsBaseMessage& aMessage ) const
+ {
+ DLTRACEIN((""));
+
+ CBufBase* buf = CBufFlat::NewL( KBufExpandSize );
+ CleanupStack::PushL( buf );
+
+ RBufWriteStream stream( *buf );
+ CleanupClosePushL( stream );
+
+
+ // Include all the necessary data to the stream
+ ExternalizePurchaseHistoryForRequestL( stream );
+
+
+ // Commits data to the stream when closing.
+ CleanupStack::PopAndDestroy( &stream );
+
+ if ( buf->Size() > 0 )
+ {
+ DLINFO(( "Completing the message, buf len: %d", buf->Ptr(0).Length() ));
+ }
+
+ // If this leaves ReceiveMessage function will complete the message.
+ aMessage.CompleteAndReleaseL( buf->Ptr( 0 ), KErrNone );
+
+
+ DLINFO(("Deleting the buf"));
+ CleanupStack::PopAndDestroy( buf );
+
+ DLTRACEOUT((""));
+ }
+
+void CNcdNodeMetaData::ExternalizePurchaseHistoryForRequestL( RWriteStream& aStream ) const
+ {
+ DLTRACEIN((""));
+
+ // Insert node class id just in case somebody wants to check that
+ // the data is of the right type
+ aStream.WriteInt32L( ClassId() );
+
+ // Get up to date purchase info straight from purchase history
+ CNcdPurchaseDetails* purchaseDetails = NULL;
+
+ TRAPD( error,
+ {
+ purchaseDetails = PurchaseDetailsLC();
+ CleanupStack::Pop( purchaseDetails );
+ });
+
+ // there's no problem in pushing a NULL pointer as long as it's
+ // pushed with PushL or CleanupDeletePushL
+ CleanupStack::PushL( purchaseDetails );
+
+ if ( error == KNcdErrorNoPurchaseInformation
+ || ( purchaseDetails &&
+ purchaseDetails->PurchaseOptionId() == KNullDesC ) )
+ {
+ // If no info is found it means that the node is
+ // not purchased.
+ // Also, purchase option id is checked here. In some situations,
+ // dummy purchase details may be inserted into the purchase history
+ // from outside the engine. So, then the purchase option id is most likely
+ // not set correctly.
+ aStream.WriteInt32L( EFalse );
+ CleanupStack::PopAndDestroy( purchaseDetails );
+ return;
+ }
+ else if ( error == KErrNone )
+ {
+ aStream.WriteInt32L( ETrue );
+ }
+ else
+ {
+ User::Leave( error );
+ }
+
+
+ const TDesC& purchasedOptionId = purchaseDetails->PurchaseOptionId();
+ ExternalizeDesL( purchasedOptionId, aStream );
+
+ TTime timeOfPurchase = purchaseDetails->PurchaseTime();
+ const TInt64& integerTimeOfPurchase = timeOfPurchase.Int64();
+ // Store framework provides the necessary implementation for
+ // the operator<< to externalise the 64-bit integer
+ aStream << integerTimeOfPurchase;
+
+ const TDesC& finalPrice = purchaseDetails->FinalPrice();
+ ExternalizeDesL( finalPrice, aStream );
+
+
+ CleanupStack::PopAndDestroy( purchaseDetails );
+ DLTRACEOUT((""));
+ }
+
+
+void CNcdNodeMetaData::PurchaseOptionIdsRequestL(
+ MCatalogsBaseMessage& aMessage ) const
+ {
+ DLTRACEIN((""));
+
+ CBufBase* buf = CBufFlat::NewL( KBufExpandSize );
+ CleanupStack::PushL( buf );
+
+ RBufWriteStream stream( *buf );
+ CleanupClosePushL( stream );
+
+ stream.WriteInt32L( iPurchaseOptions.Count() );
+ for ( TInt i = 0; i < iPurchaseOptions.Count(); i++ )
+ {
+ ExternalizeDesL( iPurchaseOptions[i]->Id(), stream );
+ }
+
+ CleanupStack::PopAndDestroy( &stream );
+
+ // If this leaves, ReceiveMessage will complete the message.
+ aMessage.CompleteAndReleaseL( buf->Ptr( 0 ), KErrNone );
+ CleanupStack::PopAndDestroy( buf );
+ }
+
+
+void CNcdNodeMetaData::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((""));
+ }
+
+
+void CNcdNodeMetaData::IconIdRequestL( MCatalogsBaseMessage& aMessage ) const
+ {
+ DLTRACEIN((""));
+
+ // If this leaves, ReceiveMessage will complete the message.
+
+ if ( ! iIcon )
+ {
+ User::Leave( KErrNotFound );
+ }
+
+ aMessage.CompleteAndReleaseL( iIcon->IconId(), KErrNone );
+
+ DLTRACEOUT((""));
+ }
+
+
+void CNcdNodeMetaData::IconDataRequestL( MCatalogsBaseMessage& aMessage ) const
+ {
+ DLTRACEIN((""));
+
+ // If this leaves, ReceiveMessage will complete the message.
+
+ if ( iIcon == NULL )
+ {
+ User::Leave( KErrNotFound );
+ }
+
+ HBufC8* icon = iIcon->IconDataL();
+ CleanupStack::PushL( icon );
+
+ aMessage.CompleteAndReleaseL( *icon, KErrNone );
+
+ CleanupStack::PopAndDestroy( icon );
+
+ DLTRACEOUT((""));
+ }
+
+
+void CNcdNodeMetaData::UserDataHandleRequestL( MCatalogsBaseMessage& aMessage ) const
+ {
+ DLTRACEIN((""));
+
+ if( iUserData == NULL )
+ {
+ DLINFO(("User data NULL"));
+ User::Leave( KErrNotFound );
+ }
+
+ // Get the session that will contain the handle of the node
+ MCatalogsSession& requestSession( aMessage.Session() );
+
+ // Add the node again to the session and get the new handle.
+ // If the node already existed in the session we will still
+ // get a new handle to the same object.
+ TInt32 handle( requestSession.AddObjectL( iUserData ) );
+
+ DLINFO(("User data handle: %d", handle ));
+
+ // Send the information to the client side
+ // If this leaves, ReceiveMessage will complete the message.
+ aMessage.CompleteAndReleaseL( handle, KErrNone );
+
+ DLTRACEOUT((""));
+ }
+
+
+void CNcdNodeMetaData::DisclaimerHandleRequestL( MCatalogsBaseMessage& aMessage ) const
+ {
+ DLTRACEIN((""));
+
+ if( iDisclaimer == NULL )
+ {
+ DLINFO(("Disclaimer NULL"));
+ User::Leave( KErrNotFound );
+ }
+
+ // Get the session that will contain the handle of the node.
+ MCatalogsSession& requestSession( aMessage.Session() );
+
+ // Add the icon to the session and get the handle.
+ // If the node already existed in the session we will still
+ // get a new handle to the same object.
+ TInt32 handle( requestSession.AddObjectL( iDisclaimer ) );
+
+ DLINFO(("Disclaimer handle: %d", handle ));
+
+ // Send the information to the client side
+ // If this leaves, ReceiveMessage will complete the message.
+ aMessage.CompleteAndReleaseL( handle, KErrNone );
+
+ DLTRACEOUT((""));
+ }
+
+
+void CNcdNodeMetaData::IconHandleRequestL( MCatalogsBaseMessage& aMessage ) const
+ {
+ DLTRACEIN((""));
+
+ if( iIcon == NULL )
+ {
+ DLINFO(("Icon NULL"));
+ User::Leave( KErrNotFound );
+ }
+
+ if ( !iIcon->IconDataReady() )
+ {
+ DLINFO(("Icon data not ready"));
+ User::Leave( KErrNotFound );
+ }
+
+ if ( iIcon->IconId() == KNullDesC )
+ {
+ DLINFO(("Icon id not set"));
+ User::Leave( KErrNotFound );
+ }
+
+ // Get the session that will contain the handle of the node.
+ MCatalogsSession& requestSession( aMessage.Session() );
+
+ // Add the icon to the session and get the handle.
+ // If the node already existed in the session we will still
+ // get a new handle to the same object.
+ TInt32 handle( requestSession.AddObjectL( iIcon ) );
+
+ DLINFO(("Icon handle: %d", handle ));
+
+ // Send the information to the client side
+ // If this leaves, ReceiveMessage will complete the message.
+ aMessage.CompleteAndReleaseL( handle, KErrNone );
+
+ DLTRACEOUT((""));
+ }
+
+
+void CNcdNodeMetaData::ScreenshotHandleRequestL( MCatalogsBaseMessage& aMessage ) const
+ {
+ DLTRACEIN((""));
+
+ if( iScreenshot == NULL )
+ {
+ DLINFO(("Screenshot NULL"));
+ User::Leave( KErrNotFound );
+ }
+
+ // Get the session that will contain the handle of the node.
+ MCatalogsSession& requestSession( aMessage.Session() );
+
+ // Add the screenshot to the session and get the handle.
+ // If the node already existed in the session we will still
+ // get a new handle to the same object.
+ TInt32 handle( requestSession.AddObjectL( iScreenshot ) );
+
+ DLINFO(("Screenshot handle: %d", handle ));
+
+ // Send the information to the client side
+ // If this leaves, ReceiveMessage will complete the message.
+ aMessage.CompleteAndReleaseL( handle, KErrNone );
+
+ DLTRACEOUT((""));
+ }
+
+
+void CNcdNodeMetaData::SkinHandleRequestL( MCatalogsBaseMessage& aMessage ) const
+ {
+ DLTRACEIN((""));
+
+ if( iSkin == NULL )
+ {
+ DLINFO(("Skin NULL"));
+ User::Leave( KErrNotFound );
+ }
+
+ // Get the session that will contain the handle of the node.
+ MCatalogsSession& requestSession( aMessage.Session() );
+
+ // Add the skin to the session and get the handle.
+ // If the node already existed in the session we will still
+ // get a new handle to the same object.
+ TInt32 handle( requestSession.AddObjectL( iSkin ) );
+
+ DLINFO(("Skin handle: %d", handle ));
+
+ // Send the information to the client side
+ // If this leaves, ReceiveMessage will complete the message.
+ aMessage.CompleteAndReleaseL( handle, KErrNone );
+
+ DLTRACEOUT((""));
+ }
+
+
+void CNcdNodeMetaData::UriContentHandleRequestL(
+ MCatalogsBaseMessage& aMessage ) const
+ {
+ DLTRACEIN((""));
+
+ if( iUriContent == NULL )
+ {
+ DLINFO(("UriContent NULL"));
+ User::Leave( KErrNotFound );
+ }
+
+ // Get the session that will contain the handle of the node.
+ MCatalogsSession& requestSession( aMessage.Session() );
+
+
+ // Add the uri content to the session and get the handle.
+ // If the node already existed in the session we will still
+ // get a new handle to the same object.
+ TInt32 handle( requestSession.AddObjectL( iUriContent ) );
+
+ DLINFO(("Uri content handle: %d", handle ));
+
+ // Send the information to the client side
+ // If this leaves, ReceiveMessage will complete the message.
+ aMessage.CompleteAndReleaseL( handle, KErrNone );
+
+ DLTRACEOUT((""));
+ }
+
+
+void CNcdNodeMetaData::ContentInfoHandleRequestL(
+ MCatalogsBaseMessage& aMessage ) const
+ {
+ DLTRACEIN((""));
+
+ if( iContentInfo == NULL )
+ {
+ DLINFO(("ContentInfo NULL"));
+ User::Leave( KErrNotFound );
+ }
+
+ // Get the session that will contain the handle of the node.
+ MCatalogsSession& requestSession( aMessage.Session() );
+
+
+ // Add the content info to the session and get the handle.
+ // If the node already existed in the session we will still
+ // get a new handle to the same object.
+ TInt32 handle( requestSession.AddObjectL( iContentInfo ) );
+
+ DLINFO(("Content info handle: %d", handle ));
+
+ // Send the information to the client side.
+ // If this leaves, ReceiveMessage will complete the message.
+ aMessage.CompleteAndReleaseL( handle, KErrNone );
+
+ DLTRACEOUT((""));
+ }
+
+
+void CNcdNodeMetaData::PreviewHandleRequestL( MCatalogsBaseMessage& aMessage ) const
+ {
+ DLTRACEIN((""));
+
+ if( iPreview == NULL )
+ {
+ DLINFO(("Preview NULL"));
+ User::Leave( KErrNotFound );
+ }
+
+ // Get the session that will contain the handle of the preview.
+ MCatalogsSession& requestSession( aMessage.Session() );
+
+
+ // Add the preview to the session and get the handle.
+ // If the preview already existed in the session we will still
+ // get a new handle to the same object.
+ TInt32 handle( requestSession.AddObjectL( iPreview ) );
+
+ DLINFO(("Preview handle: %d", handle ));
+
+ // Send the information to the client side
+ // If this leaves, ReceiveMessage will complete the message.
+ aMessage.CompleteAndReleaseL( handle, KErrNone );
+
+ DLTRACEOUT((""));
+ }
+
+
+void CNcdNodeMetaData::UpgradeHandleRequestL( MCatalogsBaseMessage& aMessage )
+ {
+ DLTRACEIN((""));
+ DLNODEID(( Identifier() ));
+ HandleContentUpgradeL();
+ // Upgrade interface should be provided in proxy side only if the upgrade
+ // exists in server side and it has some identifiers or content that can be used to
+ // load node upgrades from web.
+ if( !iUpgrade
+ || ( iUpgrade->AllUpgradesInstalledL() && !iUpgrade->ContentUpgrades() ) )
+ {
+ DLINFO(("Upgrade NULL or no node targets available"));
+ User::Leave( KErrNotFound );
+ }
+
+ // Get the session that will contain the handle of the preview.
+ MCatalogsSession& requestSession( aMessage.Session() );
+
+
+ // Add the preview to the session and get the handle.
+ // If the object already existed in the session we will still
+ // get a new handle to the same object.
+ TInt32 handle( requestSession.AddObjectL( iUpgrade ) );
+
+ DLINFO(("Upgrade handle: %d", handle ));
+
+ // Send the information to the client side
+ // If this leaves, ReceiveMessage will complete the message.
+ aMessage.CompleteAndReleaseL( handle, KErrNone );
+
+ DLTRACEOUT((""));
+ }
+
+
+void CNcdNodeMetaData::DependencyHandleRequestL( MCatalogsBaseMessage& aMessage ) const
+ {
+ DLTRACEIN((""));
+
+ // Dependency interface should be provided in proxy side only if the dependency
+ // exists in server side and it has some identifiers or content that can be used to
+ // load dependencies from web.
+ // NOTE: interface will be visible even if all of the dependencies are installed
+ if( !iDependency )
+ {
+ DLINFO(("Dependency NULL"));
+ User::Leave( KErrNotFound );
+ }
+
+ // Get the session that will contain the handle of the preview.
+ MCatalogsSession& requestSession( aMessage.Session() );
+
+
+ // Add the preview to the session and get the handle.
+ // If the preview already existed in the session we will still
+ // get a new handle to the same object.
+ TInt32 handle( requestSession.AddObjectL( iDependency ) );
+
+ DLINFO(("Dependency handle: %d", handle ));
+
+ // Send the information to the client side
+ // If this leaves, ReceiveMessage will complete the message.
+ aMessage.CompleteAndReleaseL( handle, KErrNone );
+
+ DLTRACEOUT((""));
+ }
+
+
+void CNcdNodeMetaData::DownloadHandleRequestL( MCatalogsBaseMessage& aMessage ) const
+ {
+ DLTRACEIN((""));
+
+ if( iDownload == NULL )
+ {
+ DLINFO(("Node download NULL"));
+ User::Leave( KErrNotFound );
+ }
+
+ // Get the session that will contain the handle of the node
+ MCatalogsSession& requestSession( aMessage.Session() );
+
+ // Add the download to the session and get the handle.
+ // If the node already existed in the session we will still
+ // get a new handle to the same object.
+ TInt32 handle( requestSession.AddObjectL( iDownload ) );
+
+ DLINFO(("Download handle: %d", handle ));
+
+ // Send the information to the client side
+ // If this leaves, ReceiveMessage will complete the message.
+ aMessage.CompleteAndReleaseL( handle, KErrNone );
+
+ DLTRACEOUT((""));
+ }
+
+
+void CNcdNodeMetaData::InstallHandleRequestL( MCatalogsBaseMessage& aMessage ) const
+ {
+ DLTRACEIN((""));
+
+ if( iInstall == NULL )
+ {
+ DLINFO(("Node install NULL"));
+ User::Leave( KErrNotFound );
+ }
+
+ // Get the session that will contain the handle of the node
+ MCatalogsSession& requestSession( aMessage.Session() );
+
+ // Add the install to the session and get the handle.
+ // If the node already existed in the session we will still
+ // get a new handle to the same object.
+ TInt32 handle( requestSession.AddObjectL( iInstall ) );
+
+ DLINFO(("Install handle: %d", handle ));
+
+ // Send the information to the client side
+ // If this leaves, ReceiveMessage will complete the message.
+ aMessage.CompleteAndReleaseL( handle, KErrNone );
+
+ DLTRACEOUT((""));
+ }
+
+void CNcdNodeMetaData::MoreInfoHandleRequestL( MCatalogsBaseMessage& aMessage ) const
+ {
+ DLTRACEIN((""));
+
+ if( iMoreInfo == NULL )
+ {
+ DLINFO(("More info NULL"));
+ User::Leave( KErrNotFound );
+ }
+
+ // Get the session that will contain the handle of the node.
+ MCatalogsSession& requestSession( aMessage.Session() );
+
+ // Add the more info to the session and get the handle.
+ // If the node already existed in the session we will still
+ // get a new handle to the same object.
+ TInt32 handle( requestSession.AddObjectL( iMoreInfo ) );
+
+ DLINFO(("More info handle: %d", handle ));
+
+ // Send the information to the client side
+ // If this leaves, ReceiveMessage will complete the message.
+ aMessage.CompleteAndReleaseL( handle, KErrNone );
+
+ DLTRACEOUT((""));
+ }
+
+void CNcdNodeMetaData::IsPurchaseSupportedRequestL( MCatalogsBaseMessage& aMessage ) const
+ {
+ DLTRACEIN((""));
+ TBool isPurchaseSupported = EFalse;
+ if( iPurchaseOptions.Count() > 0 )
+ {
+ isPurchaseSupported = ETrue;
+ }
+
+ // Send the information to the client side
+ // If this leaves, ReceiveMessage will complete the message.
+ aMessage.CompleteAndReleaseL( isPurchaseSupported, KErrNone );
+ }
+
+void CNcdNodeMetaData::InternalizePurchaseOptionL(
+ const MNcdPreminetProtocolPurchaseOption& aData )
+ {
+ DLTRACEIN((""));
+ CNcdPurchaseOptionImpl& option(
+ CreateOrGetPurchaseOptionL( aData.Id() ) );
+
+ TRAPD( error, option.InternalizeL( aData ) );
+ if ( error != KErrNone )
+ {
+ // If internalization fails, let's remove the option so
+ // no incomplete data is left to be used
+
+ // If an error occurs in the removal we don't want to
+ // pass that forward. Let's pass the original error.
+ TRAP_IGNORE( RemovePurchaseOptionL( aData.Id() ) );
+
+ User::Leave( error );
+ }
+
+ // Set the option recently updated so we can later in
+ // RemoveRecentlyUpdatedPurchaseOptions() differentiate
+ // options that should be removed because they were not
+ // received from the server anymore.
+ option.SetRecentlyUpdated( ETrue );
+
+ // Updates content URI if necessary
+ HandleContentUriUpdateL( option );
+ DLTRACEOUT(("Purchase option internalized successfully"));
+ }
+
+
+CNcdPurchaseOptionImpl& CNcdNodeMetaData::CreateOrGetPurchaseOptionL(
+ const TDesC& aPurchaseOptionId )
+ {
+ DLTRACEIN((""));
+ CNcdPurchaseOptionImpl* option( NULL );
+ TRAPD( error, option = &PurchaseOptionByIdL( aPurchaseOptionId ) );
+ if ( error != KErrNone && error != KErrNotFound )
+ {
+ User::Leave( error );
+ }
+ else if ( error == KErrNotFound )
+ {
+ // Not found, have to create
+ option = CNcdPurchaseOptionImpl::NewL( *this );
+ // Set option id already here so if something goes wrong
+ // after appending the option into array, the option can be
+ // identified and removed.
+ option->SetIdL( aPurchaseOptionId );
+
+ error = KErrNone;
+ error = iPurchaseOptions.Append( option );
+ if ( error != KErrNone )
+ {
+ DLERROR(("Appending purchase option failed with %d", error ));
+ // When CObject base object is created its reference count
+ // is set to one. Therefore close is said once.
+ option->Close();
+ User::Leave( error );
+ }
+ }
+ return *option;
+ }
+
+void CNcdNodeMetaData::RemovePurchaseOptionL(
+ const TDesC& aPurchaseOptionId )
+ {
+ DLTRACEIN((""));
+ const TInt KAmountOfOptions( iPurchaseOptions.Count() );
+ for ( TInt i = 0; i < KAmountOfOptions; i++ )
+ {
+ if ( iPurchaseOptions[i]->Id() == aPurchaseOptionId )
+ {
+ // Meta data has one reference count to all objects
+ // so that for one Close is said to the option.
+ iPurchaseOptions[i]->Close();
+ iPurchaseOptions.Remove( i );
+ return;
+ }
+ }
+ User::Leave( KErrNotFound );
+ }
+
+void CNcdNodeMetaData::RemoveNotUpdatedPurchaseOptions()
+ {
+ DLTRACEIN((""));
+ TInt optionsIndexer( iPurchaseOptions.Count() - 1 );
+ while ( optionsIndexer > -1 )
+ {
+ if ( !iPurchaseOptions[optionsIndexer]->RecentlyUpdated() )
+ {
+ DLINFO(( "Removing purchase option that is removed from server." ));
+ // Meta data has one reference count to all objects
+ // so that for one Close is said to the option.
+ iPurchaseOptions[optionsIndexer]->Close();
+ iPurchaseOptions.Remove( optionsIndexer );
+ }
+ else
+ {
+ DLINFO(( "Resettting recently updated info of po." ));
+ // Resetting the flag for later use
+ iPurchaseOptions[optionsIndexer]->
+ SetRecentlyUpdated( EFalse );
+ }
+ --optionsIndexer;
+ }
+ DLTRACEOUT((""));
+ }
+
+// ---------------------------------------------------------------------------
+// Internalization from a stream is a little harder now than
+// than internalizing from the protocol object. It is done
+// so that the po is first internalized into temp option and then
+// needed info is taken from it for example to identify the option
+// among the already existing options. If the option is already
+// found the temp option is externalized to stream and then
+// internalized into the already existing option. If no option
+// with same id is found then created temp option is appended to
+// array. Usually when internalizing from a stream it means that
+// we are internalizing from the database and we don't have the
+// object created yet. So the latter case is the usual case.
+
+// One drawback with this implementation is that we can use only
+// little of the functions which are used when internalizing from
+// the protocol.
+
+// One other way to implement this could be
+// just to move the purchase option id first in the
+// internalize/externalize so that the option id could be retrieved
+// easily without no temp externalization/internalization.
+// This would need some changes and would bind the order of
+// externalization/internalization of variables so it is not done
+// now. Also if current implementation is kept, the externalization
+// internalization could be replaced with assignment opertators in
+// purchase option and its composite classes.
+// ---------------------------------------------------------------------------
+//
+void CNcdNodeMetaData::InternalizePurchaseOptionL(
+ RReadStream& aStream )
+ {
+ DLTRACEIN((""));
+
+ // Temp option for reading option id
+ CNcdPurchaseOptionImpl* tmpOption =
+ CNcdPurchaseOptionImpl::NewLC( *this );
+ tmpOption->InternalizeL( aStream );
+ const TDesC& poId( tmpOption->Id() );
+
+ // Search for the option requires the purchase option id so it is the
+ // only reason why the temp option is needed always in this function.
+ CNcdPurchaseOptionImpl* option( NULL );
+ TRAPD( error, option = &PurchaseOptionByIdL( poId ) );
+ if ( error != KErrNone && error != KErrNotFound )
+ {
+ User::Leave( error );
+ }
+
+ CleanupStack::Pop( tmpOption );
+
+ if ( option == NULL )
+ {
+ DLTRACE((""));
+ // Purchase option not found, append the temp option into
+ // array of purchase options
+ option = tmpOption;
+
+ error = KErrNone;
+ error = iPurchaseOptions.Append( option );
+ if ( error != KErrNone )
+ {
+ DLERROR(("Appending purchase option failed with %d", error ));
+ // When CObject base object is created its reference count
+ // is set to one. Therefore close is said once.
+ option->Close();
+ User::Leave( error );
+ }
+ }
+ else
+ {
+ DLTRACE((""));
+ CleanupClosePushL( *tmpOption );
+ // We externalize the content of a option into a stream.
+ // This is done to copy the content from the temp option
+ // into the option already found from the array.
+
+ // This could be replaced with an assignment operation
+ // in CNcdPurchaseOptionImpl and in all of its composite
+ // classes. Because at the moment this is a rare situation
+ // (never happens at the moment) we don't use
+ // any effort into it at the moment.
+ //
+ CBufBase* buf = CBufFlat::NewL( KBufExpandSize );
+ CleanupStack::PushL( buf );
+
+ RBufWriteStream writeStream( *buf );
+ CleanupClosePushL( writeStream );
+ DLINFO(( "Externalizing option in copy" ));
+ tmpOption->ExternalizeL( writeStream );
+ // Commits data to the stream when closing.
+ CleanupStack::PopAndDestroy( &writeStream );
+
+ // Now we internalize the option already found in the
+ // array from the stream.
+ RDesReadStream readStream( buf->Ptr( 0 ) );
+ CleanupClosePushL( readStream );
+ DLINFO(( "Internalizing option in copy" ));
+ TRAPD( error, option->InternalizeL( readStream ) );
+ if ( error != KErrNone )
+ {
+ // If internalization fails, let's remove the option so
+ // no incomplete data is left to be used
+
+ // If an error occurs in the removal we don't want to
+ // pass that forward. Let's pass the original error.
+ TRAP_IGNORE( RemovePurchaseOptionL( poId ) );
+
+ User::Leave( error );
+ }
+ // Closes the stream
+ CleanupStack::PopAndDestroy( &readStream );
+
+ CleanupStack::PopAndDestroy( buf );
+ CleanupStack::PopAndDestroy( tmpOption );
+ }
+
+ // Set the option recently updated so we can later in
+ // RemoveRecentlyUpdatedPurchaseOptions() differentiate
+ // options that should be removed because they were not
+ // received from the server anymore.
+ option->SetRecentlyUpdated( ETrue );
+ }
+
+
+// ---------------------------------------------------------------------------
+// Updates URI content interface if necessary
+// ---------------------------------------------------------------------------
+//
+void CNcdNodeMetaData::HandleContentUriUpdateL(
+ const CNcdPurchaseOptionImpl& aOption )
+ {
+ DLTRACEIN((""));
+ if ( !iUriContent ||
+ !aOption.IsFree() ||
+ aOption.DownloadInfoCount() == 0 )
+ {
+ DLTRACEOUT(("No bought URI content or not free content so nothing to do"));
+ return;
+ }
+
+ TInt count = aOption.DownloadInfoCount();
+ TInt index = KErrNotFound;
+
+ DLINFO(("Going through %d download infos", count));
+ for ( TInt i = 0; i < count; ++i )
+ {
+ if ( aOption.DownloadInfo( i ).ContentUsage() ==
+ MNcdPurchaseDownloadInfo::EConsumable )
+ {
+ DLINFO(("Download in index %d is consumable!", i));
+ index = i;
+ // Only one uri is supported so break immediately as we
+ // come across it
+ break;
+ }
+ }
+
+ if ( index == KErrNotFound ||
+ aOption.DownloadInfo( index ).ContentUri() == iUriContent->Uri() )
+ {
+ DLTRACEOUT(("Option doesn't contain URI content or URI has not changed"));
+ return;
+ }
+
+
+ DLTRACE(("New URI differs from the old one. Updating..."));
+ DLINFO(( _L("New URI: %S"),
+ &aOption.DownloadInfo( index ).ContentUri() ));
+
+ CNcdPurchaseDetails* details = PurchaseDetailsLC();
+
+ // Ensure that ids match, otherwise
+ // we would be updating wrong purchase option
+ if ( details->PurchaseOptionId() == aOption.Id() )
+ {
+ // Find the correct download info for updating
+ TArray<MNcdPurchaseDownloadInfo*> dlInfo ( details->DownloadInfoL() );
+
+ TInt oldIndex = KErrNotFound;
+ for ( TInt i = 0; i < dlInfo.Count(); ++i )
+ {
+ if ( dlInfo[i]->ContentUsage() ==
+ MNcdPurchaseDownloadInfo::EConsumable )
+ {
+ DLINFO(("Download in index %d is consumable!", i));
+ oldIndex = i;
+ // Only one uri is supported so break immediately as we
+ // come across it
+ break;
+ }
+ }
+
+ NCD_ASSERT_ALWAYS( oldIndex != KErrNotFound, ENcdPanicNoData );
+
+ CNcdPurchaseDownloadInfo* modDownload =
+ static_cast<CNcdPurchaseDownloadInfo*>( dlInfo[oldIndex] );
+
+ DLTRACE(("Updating the URI to download info"));
+ modDownload->SetContentUriL(
+ aOption.DownloadInfo( index ).ContentUri() );
+
+ DLTRACE(("Saving purchase"));
+ iNodeManager.PurchaseHistory().SavePurchaseL( *details );
+ DLTRACE(("Purchase updated"));
+
+ iUriContent->InternalizeL( *details );
+ DLTRACE(("URI content internalized"));
+ }
+
+ CleanupStack::PopAndDestroy( details );
+
+ DLTRACEOUT(("All is well"));
+ }
+