--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/ncdengine/provider/client/src/ncdnodepurchaseproxy.cpp Thu Dec 17 08:51:10 2009 +0200
@@ -0,0 +1,792 @@
+/*
+* Copyright (c) 2006 Nokia Corporation and/or its subsidiary(-ies).
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of "Eclipse Public License v1.0"
+* which accompanies this distribution, and is available
+* at the URL "http://www.eclipse.org/legal/epl-v10.html".
+*
+* Initial Contributors:
+* Nokia Corporation - initial contribution.
+*
+* Contributors:
+*
+* Description:
+*
+*/
+
+
+#include <e32base.h>
+
+#include "ncdnodepurchaseproxy.h"
+
+#include "ncdpurchaseoptionproxy.h"
+#include "ncdpurchaseoperationproxy.h"
+#include "ncdsubscriptionmanagerproxy.h"
+#include "ncdclientpartofsubscription.h"
+#include "ncdclientsubscribablecontent.h"
+#include "ncdnodemanagerproxy.h"
+
+#include "ncdnodeproxy.h"
+#include "ncdnodemetadataproxy.h"
+#include "ncdoperationmanagerproxy.h"
+#include "ncdoperationimpl.h"
+#include "catalogsclientserver.h"
+#include "ncdnodeidentifier.h"
+#include "ncdnodefunctionids.h"
+#include "ncdnodeclassids.h"
+#include "catalogsinterfaceidentifier.h"
+#include "catalogsutils.h"
+#include "catalogsdebug.h"
+#include "catalogsconstants.h"
+#include "ncderrors.h"
+
+
+// ======== MEMBER FUNCTIONS ========
+
+
+CNcdNodePurchaseProxy::CNcdNodePurchaseProxy(
+ MCatalogsClientServer& aSession,
+ TInt aHandle,
+ CNcdNodeMetadataProxy& aMetadata )
+ : CNcdInterfaceBaseProxy( aSession, aHandle, &aMetadata ),
+ iMetadata( aMetadata )
+ {
+ // This would be faster in the construct list but because
+ // resetting is needed also elsewhere it is better to keep
+ // the reset values only in one place.
+ ResetHistoryData();
+ }
+
+void CNcdNodePurchaseProxy::ConstructL()
+ {
+ DLTRACEIN((""));
+
+ // Register the interface
+ MNcdNodePurchase* purchase( this );
+ AddInterfaceL( CCatalogsInterfaceIdentifier::NewL(
+ purchase,
+ this,
+ MNcdNodePurchase::KInterfaceUid ) );
+ // Try to internalize already here. And if it fails,
+ // then let it leave.
+ InternalizeL();
+
+ DLTRACEOUT(("Success. Options: %d", iPurchaseOptions.Count()));
+ }
+
+
+CNcdNodePurchaseProxy* CNcdNodePurchaseProxy::NewL(
+ MCatalogsClientServer& aSession,
+ TInt aHandle,
+ CNcdNodeMetadataProxy& aMetadata )
+ {
+ CNcdNodePurchaseProxy* self =
+ CNcdNodePurchaseProxy::NewLC( aSession,
+ aHandle,
+ aMetadata );
+ CleanupStack::Pop( self );
+ return self;
+ }
+
+
+CNcdNodePurchaseProxy* CNcdNodePurchaseProxy::NewLC(
+ MCatalogsClientServer& aSession,
+ TInt aHandle,
+ CNcdNodeMetadataProxy& aMetadata )
+ {
+ CNcdNodePurchaseProxy* self =
+ new( ELeave ) CNcdNodePurchaseProxy( aSession,
+ aHandle,
+ aMetadata );
+ // Using PushL because the object does not have any references yet
+ CleanupStack::PushL( self );
+ self->ConstructL();
+ return self;
+ }
+
+
+CNcdNodePurchaseProxy::~CNcdNodePurchaseProxy()
+ {
+ DLTRACEIN((""));
+ // Remove interfaces implemented by this class from the interface list.
+ // So, the interface list is up to date when this class object is deleted.
+ RemoveInterface( MNcdNodePurchase::KInterfaceUid );
+
+ delete iSubscribableContent;
+ iSubscribableContent = NULL;
+
+ // When purchase is destroyed, also purchaseoptions go
+ // with it if no references are left to them.
+ DeletePurchaseOptions();
+
+ ResetHistoryData();
+
+ DLTRACEOUT((""));
+ }
+
+void CNcdNodePurchaseProxy::InternalizeL()
+ {
+ DLTRACEIN((""));
+
+ TRAPD( error,
+ {
+ InternalizeMeansL();
+ InternalizeHistoryL();
+ } );
+ if ( error != KErrNone )
+ {
+ DLERROR(("Purchase internalize error"));
+ // Because we can't fully construct the purchase info,
+ // we don't give even parts of info to the user because it could
+ // be misleading.
+ DeletePurchaseOptions();
+ ResetHistoryData();
+ User::Leave( error );
+ }
+ DLTRACEOUT((""));
+ }
+
+
+void CNcdNodePurchaseProxy::InternalizeMeansL()
+ {
+ DLTRACEIN((""));
+
+ // Request the purchase option ids from server side
+ CDesCArray* poIds = RequestPurchaseOptionIdsL();
+ CleanupStack::PushL( poIds );
+
+ // Delete purchase options that don't exist in server side.
+ ReleaseMissingPurchaseOptions( *poIds );
+
+ // Reinternalize purchase options that existed already.
+ InternalizeExistingPurchaseOptionsL();
+
+ // Create purchase options that exists in the server side but not
+ // in proxy side.
+ CDesCArray* newPurchaseOptions = new( ELeave ) CDesCArrayFlat( 5 );
+ CleanupStack::PushL( newPurchaseOptions );
+
+ // Find the purchase options that don't exist in the proxy side.
+ for ( TInt i = 0; i < poIds->Count(); i++ )
+ {
+ TPtrC id = (*poIds)[i];
+ if ( !HasPurchaseOption( id ) )
+ {
+ newPurchaseOptions->AppendL( id );
+ }
+ }
+
+ InternalizeMeansL( *newPurchaseOptions );
+ CleanupStack::PopAndDestroy( newPurchaseOptions );
+ newPurchaseOptions = NULL;
+ CleanupStack::PopAndDestroy( poIds );
+ poIds = NULL;
+
+ DLTRACEOUT((""));
+ }
+
+
+void CNcdNodePurchaseProxy::InternalizeHistoryL()
+ {
+ DLTRACEIN((""));
+
+ HBufC8* data( NULL );
+
+ // Because we do not know the exact size of the data id, use
+ // the alloc method, which creates the buffer of the right size
+ // and sets the pointer to point to the created buffer.
+ User::LeaveIfError(
+ ClientServerSession().
+ SendSyncAlloc( NcdNodeFunctionIds::ENcdInternalizePurchaseHistory,
+ KNullDesC8,
+ data,
+ Metadata().Handle(),
+ 0 ) );
+
+ if ( data == NULL )
+ {
+ User::Leave( KErrNotFound );
+ }
+
+ CleanupStack::PushL( data );
+
+
+ // Read the data from the stream
+ RDesReadStream stream( *data );
+ CleanupClosePushL( stream );
+
+ TRAPD( error, InternalizeHistoryDataL( stream ) );
+ if ( error != KErrNone )
+ {
+ User::Leave( error );
+ }
+
+ // Closes the stream
+ CleanupStack::PopAndDestroy( &stream );
+ CleanupStack::PopAndDestroy( data );
+
+ DLTRACEOUT((""));
+ }
+
+CNcdNodeMetadataProxy& CNcdNodePurchaseProxy::Metadata() const
+ {
+ return iMetadata;
+ }
+
+const CNcdClientSubscribableContent*
+ CNcdNodePurchaseProxy::SubscribableContent() const
+ {
+ DLTRACEIN((""));
+ DLTRACEOUT((""));
+ return iSubscribableContent;
+ }
+
+
+
+// ---------------------------------------------------------------------------
+// From class MNcdNodePurchase.
+// In this function we return purchaseoptions to ui that are available for
+// the client at the moment.
+// ---------------------------------------------------------------------------
+//
+RCatalogsArray<MNcdPurchaseOption>
+ CNcdNodePurchaseProxy::PurchaseOptionsL() const
+ {
+ DLTRACEIN(( "" ));
+
+ RCatalogsArray<MNcdPurchaseOption> options;
+
+ // in case of leave, destroy its contents (release)
+ CleanupResetAndDestroyPushL( options );
+
+
+ TInt optionsCount( iPurchaseOptions.Count() );
+ TInt optionsIndexer( 0 );
+ while ( optionsIndexer < optionsCount )
+ {
+ DASSERT( iPurchaseOptions[optionsIndexer] );
+
+ // Purchaseoption that we handle at the moment
+ CNcdPurchaseOptionProxy* purchaseOption =
+ iPurchaseOptions[optionsIndexer];
+
+ // Type of the purchaseoption
+ MNcdPurchaseOption::TType purchaseoptionType =
+ purchaseOption->PurchaseOptionType();
+
+ // dataentity to whome the purchaseoption belongs to
+ CNcdNodeMetadataProxy& meta =
+ purchaseOption->ParentNodePurchase()->Metadata();
+
+
+
+ // NOTICE: At the moment this function does not take into count
+ // situations where purchaseoption could be of several
+ // types like ESubscription and ESubscriptionPurchase
+
+
+ // Can purchase of the item be done if it is already
+ // purchased?
+
+
+ if ( purchaseoptionType == MNcdPurchaseOption::EPurchase )
+ {
+
+ // Should check if parentfolder has separately purchaseable
+ // false and if it has then do not show normal purchase
+ // purchaseoptions to ui
+
+ options.AppendL( purchaseOption );
+ TInt ref = purchaseOption->AddRef();
+ DLTRACE(("Purchase option ref count after addref: %d", ref));
+ }
+ else if ( purchaseoptionType ==
+ MNcdPurchaseOption::ESubscriptionPurchase )
+ {
+ // Part of subscription -type purchaseoptions are
+ // always shown to ui
+ options.AppendL( purchaseOption );
+ purchaseOption->AddRef();
+ }
+ else if ( purchaseoptionType ==
+ MNcdPurchaseOption::ESubscription )
+ {
+ // If this subscription is already bought, we can't show
+ // it to ui.
+
+ TBool isBought =
+ Metadata().Node().NodeManager().
+ SubscriptionManager().
+ ActiveSubscriptionExists( meta.Id(),
+ meta.Namespace(),
+ purchaseOption->Id() );
+
+ if ( !isBought )
+ {
+ options.AppendL( purchaseOption );
+ purchaseOption->AddRef();
+ }
+ }
+ else if ( purchaseoptionType ==
+ MNcdPurchaseOption::ESubscriptionUpgrade )
+ {
+ // If target of the purchaseoption is not bought, upgrade
+ // cannot be used
+ if ( purchaseOption->IsUsableL() )
+ {
+ options.AppendL( purchaseOption );
+ purchaseOption->AddRef();
+ }
+ }
+ else
+ {
+ // Not supported
+ DASSERT( false );
+ }
+
+ ++optionsIndexer;
+ }
+
+
+ CleanupStack::Pop( &options );
+
+ DLTRACEOUT(( "" ));
+ return options;
+ }
+
+// ---------------------------------------------------------------------------
+// From class MNcdNodePurchase.
+// ?implementation_description
+// ---------------------------------------------------------------------------
+//
+MNcdPurchaseOption* CNcdNodePurchaseProxy::PurchaseOptionL(
+ const TDesC& aPurchaseOptionId ) const
+ {
+ DLTRACEIN((""));
+ TInt optionsCount( iPurchaseOptions.Count() );
+ TInt optionsIndexer( 0 );
+ while ( optionsIndexer < optionsCount )
+ {
+ DASSERT( iPurchaseOptions[optionsIndexer] );
+
+ if ( iPurchaseOptions[optionsIndexer]->Id() == aPurchaseOptionId )
+ {
+ iPurchaseOptions[optionsIndexer]->AddRef();
+
+ DLTRACEOUT(( "" ));
+ return iPurchaseOptions[optionsIndexer];
+ }
+
+ ++optionsIndexer;
+ }
+
+ DLTRACEOUT(( "" ));
+ return NULL;
+ }
+
+
+// ---------------------------------------------------------------------------
+// From class MNcdNodePurchase.
+// Notice that this function accepts purchase options also from other nodes
+// than into which this interface belongs to. Could be changed to accept
+// only purchase options from this interface, but at the moment UI
+// does not permit this in case of subscription.
+// ---------------------------------------------------------------------------
+//
+MNcdPurchaseOperation* CNcdNodePurchaseProxy::PurchaseL(
+ MNcdPurchaseOption& aPurchaseOption,
+ MNcdPurchaseOperationObserver& aObserver )
+ {
+ DLTRACEIN((""));
+
+
+ CNcdPurchaseOperationProxy* operation( NULL );
+
+ CNcdPurchaseOptionProxy& option =
+ *static_cast<CNcdPurchaseOptionProxy*>( &aPurchaseOption );
+
+
+ // Given purchaseoption is old and should not be used anymore
+ if ( option.IsObsolete() )
+ {
+ User::Leave( KNcdErrorObsolete );
+ }
+
+
+ // Now if validuntil for subscription has passed, we should not allow it
+ // to be bought anymore
+ if ( option.PurchaseOptionType() == MNcdPurchaseOption::ESubscription )
+ {
+ TTime now;
+ now.HomeTime();
+
+ // The time until the node is subscribable is stored in the
+ // subscribable content of the NodePurchase interface where to
+ // the GIVEN PURCHASEOPTION belongs to.
+ const CNcdClientSubscribableContent* subscribableContent =
+ option.ParentNodePurchase()->SubscribableContent();
+
+ DASSERT( subscribableContent );
+ if ( subscribableContent &&
+ subscribableContent->ValidUntilSet() &&
+ now > subscribableContent->ValidUntil() )
+ {
+ User::Leave( KNcdErrorSubscriptionNotSubscribableAnymore );
+ }
+
+ }
+
+
+ DLTRACE(( _L("Purchase started with option whose name is: %S"),
+ &option.Name() ));
+
+
+ // NOTICE: In the case of subscription or upgrade the purchaseoption
+ // can be from another node. That is why we give
+ // node-reference from the purchaseoption.
+ operation =
+ Metadata().Node().OperationManager().
+ CreatePurchaseOperationL( option.ParentNodePurchase()->Metadata().Node(),
+ option,
+ &aObserver );
+
+ // It is enough that the observer is informed
+ // when the file operation is ready. So, no need to add
+ // node or this class object to be observers.
+
+ // No need to increase the operation ref count here because
+ // it should be initially one.
+
+ DLTRACEOUT((""));
+
+ return operation;
+ }
+
+// ---------------------------------------------------------------------------
+// From class MNcdNodePurchase.
+// ?implementation_description
+// ---------------------------------------------------------------------------
+//
+TBool CNcdNodePurchaseProxy::IsPurchased() const
+ {
+ return iIsPurchased;
+ }
+
+
+// ---------------------------------------------------------------------------
+// From class MNcdNodePurchase.
+// ?implementation_description
+// ---------------------------------------------------------------------------
+//
+MNcdPurchaseOption* CNcdNodePurchaseProxy::PurchasedOptionL() const
+ {
+ if ( !IsPurchased() )
+ {
+ return NULL;
+ }
+
+ return PurchaseOptionL( *iPurchasedOptionId );
+ }
+
+// ---------------------------------------------------------------------------
+// From class MNcdNodePurchase.
+// ?implementation_description
+// ---------------------------------------------------------------------------
+//
+TTime CNcdNodePurchaseProxy::TimeOfPurchaseL() const
+ {
+ if ( !IsPurchased() )
+ {
+ User::Leave( KErrNotFound );
+ }
+
+ return iTimeOfPurchase;
+ }
+
+// ---------------------------------------------------------------------------
+// From class MNcdNodePurchase.
+// ?implementation_description
+// ---------------------------------------------------------------------------
+//
+const TDesC& CNcdNodePurchaseProxy::PurchasedPriceL() const
+ {
+ if ( !IsPurchased() )
+ {
+ User::Leave( KErrNotFound );
+ }
+
+ return *iPurchasedPrice;
+ }
+
+
+void CNcdNodePurchaseProxy::InternalizeMeansDataL( RReadStream& aStream )
+ {
+ DLTRACEIN((""));
+
+ // Subscribable content is read into its own class
+ TBool subscribableContentFound( aStream.ReadInt32L() );
+ if ( subscribableContentFound )
+ {
+ if ( iSubscribableContent == NULL )
+ {
+ iSubscribableContent = CNcdClientSubscribableContent::NewL();
+ }
+ iSubscribableContent->InternalizeL( aStream );
+ }
+
+
+ TInt handleCount = aStream.ReadInt32L();
+ DLINFO((( "handle count: %d" ), handleCount ));
+
+ for ( TInt i = 0; i < handleCount; i++ )
+ {
+ TInt tmpProxyHandle = aStream.ReadInt32L();
+ CNcdPurchaseOptionProxy* tmpPurchaseOption =
+ CNcdPurchaseOptionProxy::NewLC(
+ ClientServerSession(),
+ tmpProxyHandle,
+ *this );
+
+ TRAPD( addError, iPurchaseOptions.AppendL( tmpPurchaseOption ) );
+ if ( addError != KErrNone )
+ {
+ CleanupStack::PopAndDestroy( tmpPurchaseOption );
+ User::Leave( addError );
+ }
+
+ CleanupStack::Pop( tmpPurchaseOption );
+ tmpPurchaseOption->InternalizeL();
+ }
+
+ DLTRACEOUT((""));
+ }
+
+
+void CNcdNodePurchaseProxy::InternalizeHistoryDataL( RReadStream& aStream )
+ {
+ DLTRACEIN((""));
+
+ // Reset values so that if we receive message that for some reason
+ // does not contain purchase history info, we don't keep the old
+ // purchase history info in memory.
+ ResetHistoryData();
+
+ // Node class id. Not actually needed.
+ aStream.ReadInt32L();
+
+
+ iIsPurchased = aStream.ReadInt32L();
+ if ( iIsPurchased == EFalse )
+ {
+ return;
+ }
+
+ InternalizeDesL( iPurchasedOptionId, aStream );
+
+ TInt64 integerTimeOfPurchase( 0 );
+ // Store framework provides the necessary implementation for
+ // the operator>> to internalise the 64-bit integer
+ aStream >> integerTimeOfPurchase;
+ iTimeOfPurchase = TTime( integerTimeOfPurchase );
+
+ InternalizeDesL( iPurchasedPrice, aStream );
+
+
+ DLTRACEOUT((""));
+ }
+
+
+void CNcdNodePurchaseProxy::DeletePurchaseOptions()
+ {
+ DLTRACEIN(("Handling %d purchase options", iPurchaseOptions.Count() ));
+ for ( TInt i = iPurchaseOptions.Count() - 1; i >= 0; --i )
+ {
+ CNcdPurchaseOptionProxy* tmpOption = iPurchaseOptions[i];
+
+ if ( tmpOption->MyTotalRefCount() > 0 )
+ {
+ // to prevent loops remove purchaseoption first
+ // so it won't become deleted
+ iPurchaseOptions.Remove( i );
+
+ tmpOption->SetObsolete();
+ // Remove the purchase option from the interface parent.
+ // This will update the parent reference count.
+ // Because purchase option does not provide any interfaces for
+ // the parent, it is safe to use this function.
+ tmpOption->RemoveFromParent();
+ if ( tmpOption->TotalRefCount() == 0 )
+ {
+ DLINFO(("Purchase option can be deleted here."));
+ delete tmpOption;
+ }
+ }
+ }
+ DLTRACE(("Deleting %d purchase options", iPurchaseOptions.Count() ));
+ iPurchaseOptions.ResetAndDestroy();
+ }
+
+void CNcdNodePurchaseProxy::ResetHistoryData()
+ {
+ iIsPurchased = EFalse;
+ delete iPurchasedOptionId;
+ iPurchasedOptionId = NULL;
+ iTimeOfPurchase = TTime( 0 );
+ delete iPurchasedPrice;
+ iPurchasedPrice = NULL;
+ }
+
+CDesCArray* CNcdNodePurchaseProxy::RequestPurchaseOptionIdsL()
+ {
+ DLTRACEIN((""));
+
+ HBufC8* data( NULL );
+
+ // Because we do not know the exact size of the data, use
+ // the alloc method, which creates the buffer of the right size
+ // and sets the pointer to point to the created buffer.
+ User::LeaveIfError(
+ ClientServerSession().
+ SendSyncAlloc( NcdNodeFunctionIds::ENcdPurchaseOptionIds,
+ KNullDesC8,
+ data,
+ Handle(),
+ 0 ) );
+
+ if ( data == NULL )
+ {
+ User::Leave( KErrNotFound );
+ }
+
+ CleanupStack::PushL( data );
+
+ // Read the data from the stream
+ RDesReadStream stream( *data );
+ CleanupClosePushL( stream );
+
+ TInt purchaseOptionCount = stream.ReadInt32L();
+ CDesCArray* array = new( ELeave ) CDesCArrayFlat( 5 );
+ CleanupStack::PushL( array );
+ for ( TInt i = 0; i < purchaseOptionCount; i++ )
+ {
+ HBufC* des( NULL );
+ InternalizeDesL( des, stream );
+ CleanupStack::PushL( des );
+ array->AppendL( *des );
+ CleanupStack::PopAndDestroy( des );
+ }
+
+ CleanupStack::Pop( array );
+ CleanupStack::PopAndDestroy( &stream );
+ CleanupStack::PopAndDestroy( data );
+
+ return array;
+ }
+
+void CNcdNodePurchaseProxy::ReleaseMissingPurchaseOptions(
+ const CDesCArray& aPurchaseOptionIds )
+ {
+ DLTRACEIN((""));
+
+ for ( TInt i = iPurchaseOptions.Count() - 1; i >= 0; i-- )
+ {
+ TInt index;
+ if ( aPurchaseOptionIds.Find( iPurchaseOptions[i]->Id(), index ) != 0 )
+ {
+ iPurchaseOptions[i]->SetObsolete();
+ // Remove the purchase option from the interface parent.
+ // This will update the parent reference count.
+ // Because purchase option does not provide any interfaces for
+ // the parent, it is safe to use this function.
+ iPurchaseOptions[i]->RemoveFromParent();
+ if ( iPurchaseOptions[ i ]->TotalRefCount() == 0 )
+ {
+ DLINFO(("Purchase option can be deleted."));
+ delete iPurchaseOptions[ i ];
+ }
+ iPurchaseOptions.Remove( i );
+ }
+ }
+ }
+
+void CNcdNodePurchaseProxy::InternalizeExistingPurchaseOptionsL()
+ {
+ DLTRACEIN((""));
+
+ for ( TInt i = 0; i < iPurchaseOptions.Count(); i++ )
+ {
+ iPurchaseOptions[i]->InternalizeL();
+ }
+ }
+
+void CNcdNodePurchaseProxy::InternalizeMeansL(
+ const CDesCArray& aPurchaseOptionIds )
+ {
+ DLTRACEIN((""));
+
+ CBufBase* buf = CBufFlat::NewL( KBufExpandSize );
+ CleanupStack::PushL( buf );
+
+ RBufWriteStream writeStream( *buf );
+ CleanupClosePushL( writeStream );
+ writeStream.WriteInt32L( aPurchaseOptionIds.Count() );
+ for ( TInt i = 0; i < aPurchaseOptionIds.Count(); i++ )
+ {
+ ExternalizeDesL( aPurchaseOptionIds[i], writeStream );
+ }
+
+ CleanupStack::PopAndDestroy( &writeStream );
+ HBufC8* messageToSend = HBufC8::NewL( buf->Size() );
+ messageToSend->Des().Copy( buf->Ptr( 0 ) );
+
+ CleanupStack::PopAndDestroy( buf );
+ CleanupStack::PushL( messageToSend );
+
+ // Request handles to the new purchase options.
+ HBufC8* data( NULL );
+
+ // Because we do not know the exact size of the data, use
+ // the alloc method, which creates the buffer of the right size
+ // and sets the pointer to point to the created buffer.
+ User::LeaveIfError(
+ ClientServerSession().
+ SendSyncAlloc( NcdNodeFunctionIds::ENcdInternalizePurchaseMeans,
+ *messageToSend,
+ data,
+ Handle(),
+ 0 ) );
+
+ CleanupStack::PopAndDestroy( messageToSend );
+ messageToSend = NULL;
+
+ if ( data == NULL )
+ {
+ User::Leave( KErrNotFound );
+ }
+
+ CleanupStack::PushL( data );
+
+ // Read the data from the stream
+ RDesReadStream stream( *data );
+ CleanupClosePushL( stream );
+
+ InternalizeMeansDataL( stream );
+
+ CleanupStack::PopAndDestroy( &stream );
+ CleanupStack::PopAndDestroy( data );
+ }
+
+TBool CNcdNodePurchaseProxy::HasPurchaseOption( const TDesC& aId ) const
+ {
+ DLTRACEIN((""));
+ for ( TInt i = 0; i < iPurchaseOptions.Count(); i++ )
+ {
+ if ( iPurchaseOptions[i]->Id() == aId )
+ {
+ return ETrue;
+ }
+ }
+
+ return EFalse;
+ }