ncdengine/provider/client/src/ncdnodepurchaseproxy.cpp
changeset 0 ba25891c3a9e
--- /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;
+    }