ncdengine/provider/server/src/ncdnodemetadataimpl.cpp
changeset 0 ba25891c3a9e
child 18 3ba40be8e484
--- /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"));
+    }
+