iaupdate/IAD/engine/controller/src/iaupdatecontrollerimpl.cpp
changeset 0 ba25891c3a9e
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/iaupdate/IAD/engine/controller/src/iaupdatecontrollerimpl.cpp	Thu Dec 17 08:51:10 2009 +0200
@@ -0,0 +1,1724 @@
+/*
+* Copyright (c) 2007-2009 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:   This module contains the implementation of 
+*                CIAUpdateController class member functions.
+*
+*/
+
+
+
+// For the NCD Engine ECOM session closing.
+#include <ecom/ecom.h>
+
+#include <catalogsuids.h>
+#include <catalogsutils.h>
+#include <catalogsengine.h>
+#include <ncdprovider.h>
+#include <ncdutils.h>
+#include <ncdconfigurationkeys.h>
+#include <ncdcapabilities.h>
+#include <ncdprogress.h>
+#include <ncdnode.h>
+#include <ncdnodecontainer.h>
+#include <ncdconnectionmethod.h>
+#include <ncdserverreportoperation.h>
+#include <ncdserverreportmanager.h>
+#include <ncdquery.h>
+#include <ncdpurchasehistory.h>
+#include <ncdutils.h>
+#include <ncdprovideroptions.h>
+#include <ncdoperation.h>
+#include <ncddownloadoperation.h>
+#include <ncderrors.h>
+
+// Required for NCD debug logging.
+#include <catalogsdebug.h>
+
+#include "iaupdatecontrollerimpl.h"
+#include "iaupdateloader.h"
+#include "iaupdatenodecontainer.h"
+#include "iaupdatenodefactory.h"
+#include "iaupdatenodeimpl.h"
+#include "iaupdatefwnodeimpl.h"
+#include "iaupdateutils.h"
+#include "iaupdatehistoryimpl.h"
+#include "iaupdateenginexmlparser.h"
+#include "iaupdateengineconfigdata.h"
+#include "iaupdatectrlconsts.h"
+#include "iaupdateprotocolconsts.h"
+#include "iaupdatectrlfileconsts.h"
+#include "iaupdateselfupdaterctrl.h"
+#include "iaupdatecontentoperationmanager.h"
+#include "iaupdatecachecleaner.h"
+#include "iaupdatecontrollerfile.h"
+#include "iaupdateridentifier.h"
+#include "iaupdateerrorcodes.h"
+#include "iaupdatetimer.h"
+#include "iaupdatedebug.h"
+
+
+// -----------------------------------------------------------------------------
+// CIAUpdateController::NewLC
+// Two-phased constructor.
+// -----------------------------------------------------------------------------
+// 
+CIAUpdateController* CIAUpdateController::NewLC( 
+    const TUid& aFamilyUid, 
+    MIAUpdateControllerObserver& aObserver )
+    {
+    IAUPDATE_TRACE("[IAUPDATE] CIAUpdateController::NewLC() begin");
+    CIAUpdateController* self = 
+        new( ELeave ) CIAUpdateController( aFamilyUid, aObserver );
+    CleanupStack::PushL(self);
+    self->ConstructL();
+    IAUPDATE_TRACE("[IAUPDATE] CIAUpdateController::NewLC end");
+    return self;
+    }
+
+
+// -----------------------------------------------------------------------------
+// CIAUpdateController::NewL
+// Two-phased constructor.
+// -----------------------------------------------------------------------------
+//    
+CIAUpdateController* CIAUpdateController::NewL( 
+    const TUid& aFamilyUid, 
+    MIAUpdateControllerObserver& aObserver )
+    {
+    IAUPDATE_TRACE("[IAUPDATE] CIAUpdateController::NewL() begin");
+    CIAUpdateController* self = 
+        CIAUpdateController::NewLC( aFamilyUid, aObserver );
+    CleanupStack::Pop( self );
+    IAUPDATE_TRACE("[IAUPDATE] CIAUpdateController::NewL end");
+    return self;
+    }
+
+
+// -----------------------------------------------------------------------------
+// CIAUpdateController::CIAUpdateController
+// C++ default constructor can NOT contain any code, that
+// might leave.
+// -----------------------------------------------------------------------------
+//
+CIAUpdateController::CIAUpdateController( 
+    const TUid& aFamilyUid,
+    MIAUpdateControllerObserver& aObserver ) 
+: CActive( CActive::EPriorityStandard ),
+  iFamilyUid( aFamilyUid ),
+  iObserver( aObserver ),
+  iControllerState( ENotRunning )
+    {
+    IAUPDATE_TRACE("[IAUPDATE] CIAUpdateController::CIAUpdateController() begin");
+
+    // Required for NCD debug logging.
+    DLINIT;
+
+    CActiveScheduler::Add( this );
+
+    IAUPDATE_TRACE("[IAUPDATE] CIAUpdateController::CIAUpdateController() end");
+    }
+
+
+// -----------------------------------------------------------------------------
+// CIAUpdateController::ConstructL
+// Symbian 2nd phase constructor can leave.
+// -----------------------------------------------------------------------------
+//
+void CIAUpdateController::ConstructL()
+    {
+    IAUPDATE_TRACE("[IAUPDATE] CIAUpdateController::ConstructL() begin");
+    
+    iEngine = CCatalogsEngine::NewL( *this );
+
+    if ( !iEngine )
+        {
+        IAUPDATE_TRACE("[IAUPDATE] !iEngine");
+        User::Leave( KErrNotFound );
+        }
+    
+    iNodeContainer = CIAUpdateNodeContainer::NewL( *this );
+    
+    iSelfUpdaterCtrl = CIAUpdateSelfUpdaterCtrl::NewL( *this );
+    iContentOperationManager = CIAUpdateContentOperationManager::NewL();
+
+    // Notice, that this will read the data from the file 
+    // and adjust variables from the file if the file exists.
+    iCacheClearFile =
+        CIAUpdateControllerFile::NewL( 
+            IAUpdateCtrlFileConsts::KCacheClearFile );
+    
+    IAUPDATE_TRACE("[IAUPDATE] CIAUpdateController::ConstructL() end");
+    }    
+   
+    
+// -----------------------------------------------------------------------------
+// CIAUpdateController::~CIAUpdateController
+// Destructor
+// -----------------------------------------------------------------------------
+//    
+CIAUpdateController::~CIAUpdateController()
+    {
+    IAUPDATE_TRACE("[IAUPDATE] CIAUpdateController::~CIAUpdateController() begin");
+
+    // This is always a good thing to do with active objects.
+    Cancel();
+    
+    // Also cancel possible report operation.
+    CancelReporting();
+
+    delete iReportTimer;
+    delete iContentOperationManager;
+    delete iLoader;    
+    delete iNodeContainer;
+    delete iCacheCleaner;
+    delete iCacheClearFile;
+        
+    // Before releasing engine, be sure to release or
+    // delete all other objects that may contain connetions
+    // to the engine.
+    
+    // History uses the services that are provided throught the provider.
+    // So, delete history here before releasing the provider and closing
+    // the engine.
+    delete iHistory;
+    
+    // Do not delete the contents here.
+    // This array does not own the content.
+    iNodes.Reset();
+
+    delete iSelfUpdaterCtrl;
+
+    if ( iServerReportManager )
+        {
+        iServerReportManager->Release();
+        }
+
+    if ( iProvider )
+        {
+        iProvider->Release();
+        }
+
+    if ( iBaseProvider )
+        {
+        iBaseProvider->Release();
+        }
+         
+    if ( iEngine )
+        {
+        iEngine->Close();
+        delete iEngine;
+        }    
+
+    // Make sure that the NCD Engine ECOM session is closed. 
+    // SKD help describes this:
+    // Direct users of ECOM plugins must call this method when all 
+    // implementations they have created have been destroyed and they 
+    // are finished using ECOM e.g. library shutdown. It will garbage 
+    // collect the last previously destroyed implementation and close 
+    // the REComSession if no longer in use.
+    REComSession::FinalClose();
+
+    // Required for NCD debug logging.
+    DLUNINIT;
+
+    IAUPDATE_TRACE("[IAUPDATE] CIAUpdateController::~CIAUpdateController() end");
+    }
+
+
+// -----------------------------------------------------------------------------
+// CIAUpdateController::FamilyUid
+//
+// -----------------------------------------------------------------------------
+//    
+const TUid& CIAUpdateController::FamilyUid() const
+    {
+    IAUPDATE_TRACE("[IAUPDATE] CIAUpdateController::FamilyUid()");
+    IAUPDATE_TRACE_1("[IAUPDATE] family uid: %x", iFamilyUid.iUid );
+    return iFamilyUid;
+    }
+
+
+// -----------------------------------------------------------------------------
+// CIAUpdateController::ProviderL
+// 
+// -----------------------------------------------------------------------------
+//
+MNcdProvider& CIAUpdateController::ProviderL()
+    {
+    IAUPDATE_TRACE("[IAUPDATE] CIAUpdateController::ProviderL() begin");
+
+    if ( !iProvider )
+        {
+        User::Leave( KErrNotFound );
+        }
+
+    IAUPDATE_TRACE("[IAUPDATE] CIAUpdateController::ProviderL() end");
+
+    return *iProvider;
+    }
+
+
+// -----------------------------------------------------------------------------
+// CIAUpdateController::SelfUpdaterCtrl
+// 
+// -----------------------------------------------------------------------------
+//
+CIAUpdateSelfUpdaterCtrl& CIAUpdateController::SelfUpdaterCtrl()
+    {
+    return *iSelfUpdaterCtrl;
+    }
+
+
+// -----------------------------------------------------------------------------
+// CIAUpdateController::ContentOperationManager
+// 
+// -----------------------------------------------------------------------------
+//
+CIAUpdateContentOperationManager& CIAUpdateController::ContentOperationManager()
+    {
+    return *iContentOperationManager;
+    }
+
+
+// -----------------------------------------------------------------------------
+// CIAUpdateController::Startup
+// 
+// -----------------------------------------------------------------------------
+//
+TInt CIAUpdateController::Startup()
+    {
+    IAUPDATE_TRACE("[IAUPDATE] CIAUpdateController::Startup() begin");
+
+    if ( iControllerState == EStarting )
+        {
+        IAUPDATE_TRACE("[IAUPDATE] Error code: KErrInUse");        
+        return KErrInUse;
+        }
+    else if ( iControllerState != ENotRunning )
+        {
+        IAUPDATE_TRACE("[IAUPDATE] Error code: KErrAlreadyExists");
+        return KErrAlreadyExists;
+        }
+    
+    // Turn off the cache cleaner because we do not want it to remove any items
+    // even if allowed db size is exceeded.
+    // Make sure that IMEI is send in server requests.
+    // Disable HEAD requests for optimization. With SISX content this is 
+    // safe to do.
+    TUint32 providerOptions( ENcdProviderDisableNodeCacheCleaner
+                             | ENcdProviderSendImei
+                             | ENcdProviderDisableHttpHeadRequest );
+    
+    TInt connectErr = iEngine->Connect( FamilyUid() );
+    if ( connectErr != KErrNone )
+        {
+        return connectErr;
+        }
+    
+    TRAPD ( err, 
+            iEngine->CreateProviderL( KNcdProviderUid, 
+                                      iBaseProvider, 
+                                      iStatus, 
+                                      providerOptions ) );
+    IAUPDATE_TRACE_1("[IAUPDATE] error code: %d", err );        
+    if ( err != KErrNone )
+        {
+        return err;
+        }
+    
+    SetActive();
+
+    iControllerState = EStarting;
+
+    IAUPDATE_TRACE("[IAUPDATE] CIAUpdateController::Startup() end");
+
+    return KErrNone;
+    }
+ 
+    
+// -----------------------------------------------------------------------------
+// CIAUpdateController::StartRefreshL
+//
+// -----------------------------------------------------------------------------
+//
+void CIAUpdateController::StartRefreshL( TBool aAllowNetConnection )
+    {
+    IAUPDATE_TRACE("[IAUPDATE] CIAUpdateController::StartRefreshL() begin");
+    IAUPDATE_TRACE_2("[IAUPDATE] iControllerState %d allow net connection %d", iControllerState, aAllowNetConnection );
+
+    if ( iControllerState == ENotRunning )
+        {
+        User::Leave( KErrNotReady );
+        }
+    else if ( iControllerState != EIdle )
+        {
+        User::Leave( KErrInUse );
+        }
+
+    if ( !iLoader )
+        {
+        IAUPDATE_TRACE("[IAUPDATE] Create loader");
+        iLoader = CIAUpdateLoader::NewL( *iProvider, *this );
+        // For optimization reasons, skip child count refreshes.
+        iLoader->SetSkipChildCountRefresh( ETrue );       
+        }
+
+    // Reset the node list. New one will be created when this completes. 
+    // Notice, that the array content is not owned by this array.
+    iNodeContainer->Clear();
+    iNodes.Reset();
+        
+    if ( aAllowNetConnection )
+        {
+        IAUPDATE_TRACE("[IAUPDATE] Net connection allowed");
+
+        if ( iLoader->RootExpiredL() )
+            {
+            IAUPDATE_TRACE("[IAUPDATE] Root has expired");
+
+            // Notice, that we will clean the cache only if the
+            // root load is required. Otherwise, if cache was cleaned,
+            // the root would be reloaded also. Then, unwanted
+            // CDB connections would occur.
+            
+            // Update the data from the file just in case.
+            // Actually the data was already read when the object
+            // was created if the file exists. But, this way we
+            // can be sure that the data matches the file even if
+            // in some situation the write operation has failed
+            // and the object data could not be synchronized into
+            // the file.
+            iCacheClearFile->ReadControllerDataL();
+
+            TLanguage currentLanguage = User::Language();
+            TLanguage lastTimeLanguage = iCacheClearFile->Language();
+            TTime lastClearTime( iCacheClearFile->RefreshTime() );
+            const TTimeIntervalDays KCacheClearInterval( 
+                IAUpdateCtrlConsts::KCacheClearIntervalDays );
+            TTime expireTime( lastClearTime + KCacheClearInterval );
+            TTime universalTime;
+            universalTime.UniversalTime();
+
+            if ( currentLanguage != lastTimeLanguage
+                 || expireTime < universalTime
+                 || lastClearTime > universalTime  )
+                {
+                IAUPDATE_TRACE("[IAUPDATE] Clear cache");
+                // Database is expired because languages do not match
+                // or current time has passed the expiration time. 
+                // Also, sanity check is made. If last refresh time is larger 
+                // than current time, then the last refresh value has been set wrong, 
+                // and the database can be thought as expired. This might be the case 
+                // if the user has changed the time in the phone.
+
+                // Before starting to load data from the net,
+                // clear an old cache. This way files related to unfinished
+                // updates will be deleted and there is no danger of them becoming
+                // hanging data that can not be handled when old nodes are removed.
+                if ( !iCacheCleaner )
+                    {
+                    iCacheCleaner = CIAUpdateCacheCleaner::NewL( *iProvider );
+                    }
+                iCacheCleaner->ClearL( iStatus );
+                SetActive();
+                iControllerState = EInClearCache;
+                }
+            }
+
+        if ( iControllerState == EIdle )
+            {
+            IAUPDATE_TRACE("[IAUPDATE] Refresh directly from net");
+            // Because controller state is still idle, we did not start
+            // cache cleaning above.
+            // There is no need to clean the cache here. 
+            // So, skip that step and start loading directly.     
+            // This starts an asynchronous operation which will end
+            // when callback is called.
+            iLoader->LoadNodesL();
+            iControllerState = EInLoadOperation;
+            }
+        }
+    else
+        {
+        IAUPDATE_TRACE("[IAUPDATE] Start local refresh");
+        // Load should be done locally.
+        // So, just delegate the thing to the RunL which will handle
+        // the local getting of the data in a next asynchronous step.
+        iStatus = KRequestPending;
+        SetActive();
+        TRequestStatus* ptrStatus = &iStatus;
+        User::RequestComplete( ptrStatus, KErrNone );
+        iControllerState = EInLocalLoadOperation;
+        }
+
+    IAUPDATE_TRACE("[IAUPDATE] CIAUpdateController::StartRefreshL() end");    
+    }
+
+        
+// -----------------------------------------------------------------------------
+// CIAUpdateController::CancelRefresh
+//
+// -----------------------------------------------------------------------------
+//
+void CIAUpdateController::CancelRefresh()
+    {
+    IAUPDATE_TRACE_1("[IAUPDATE] CIAUpdateController::CancelRefresh() begin: %d",
+                     iControllerState);
+
+    switch ( iControllerState )
+        {
+        case EInClearCache:
+            // Cache cleaner is responsible of this operation.
+            iCacheCleaner->Cancel();
+            break;
+
+        case EInLoadOperation:
+            // Loader is responsible of this operation.
+            iLoader->Cancel();
+            break;
+
+        case EInLocalLoadOperation:
+            // Use the normal cancellation of this active class because 
+            // these operations are handled by this active object itself.
+            Cancel();
+            break;
+
+        default:
+            break;
+        }
+
+    // New state should be idle.
+    iControllerState = EIdle;
+
+    IAUPDATE_TRACE("[IAUPDATE] CIAUpdateController::CancelRefresh() end");
+    }
+
+
+// -----------------------------------------------------------------------------
+// CIAUpdateController::CancelReporting
+//
+// -----------------------------------------------------------------------------
+//
+void CIAUpdateController::CancelReporting()
+    {
+    IAUPDATE_TRACE("[IAUPDATE] CIAUpdateController::CancelReport() begin");
+
+    // Because report operation is cancelled, no need for the timer
+    // anymore. So, delete timer if it exists. Deletion will automatically
+    // cancel the timer operation. The timer may be started for some special
+    // cases even if report operation was not created. So, try to delete it
+    // here just in case.
+    delete iReportTimer;
+    iReportTimer = NULL;
+
+    if ( iReportOperation )
+        {
+        // Set this for the callback because operation call operation complete
+        // when the operation is cancelled. We do not want to call ui callback there.
+        iCancellingReportOperation = ETrue;
+
+        iReportOperation->CancelOperation();
+
+        // Notice, that the operation complete will release the operation and set the
+        // operation pointer to NULL. Do not do it here.
+
+        // Set the cancelling flag to EFalse because cancell operation is finished.
+        iCancellingReportOperation = EFalse;
+        }
+
+    IAUPDATE_TRACE("[IAUPDATE] CIAUpdateController::CancelReport() end");
+    }
+    
+    
+// -----------------------------------------------------------------------------
+// CIAUpdateController::HistoryL
+//
+// -----------------------------------------------------------------------------
+//    
+MIAUpdateHistory& CIAUpdateController::HistoryL()
+    {
+    IAUPDATE_TRACE("[IAUPDATE] CIAUpdateController::HistoryL() begin");
+
+    if ( !iHistory )
+        {
+        iHistory = 
+            CIAUpdateHistory::NewL( FamilyUid(), ProviderL() );
+        }
+
+    IAUPDATE_TRACE("[IAUPDATE] CIAUpdateController::HistoryL() end");
+
+    return *iHistory;
+    }
+
+
+// -----------------------------------------------------------------------------
+// CIAUpdateController::SetDefaultConnectionMethodL
+//
+// -----------------------------------------------------------------------------
+//
+void CIAUpdateController::SetDefaultConnectionMethodL( 
+    const TIAUpdateConnectionMethod& aMethod )
+    {
+    IAUPDATE_TRACE("[IAUPDATE] CIAUpdateController::SetDefaultAccessPointL begin");
+    IAUPDATE_TRACE_1("[IAUPDATE] access point: %d", aMethod.iId );
+
+    if ( !iProvider )
+        {
+        User::Leave( KErrNotFound );
+        }
+
+    TNcdConnectionMethodType type( ENcdConnectionMethodTypeAlwaysAsk );
+    switch ( aMethod.iType )
+        {
+        case TIAUpdateConnectionMethod::EConnectionMethodTypeAlwaysAsk:
+            type = ENcdConnectionMethodTypeAlwaysAsk;
+            break;
+
+        case TIAUpdateConnectionMethod::EConnectionMethodTypeDestination:
+            type = ENcdConnectionMethodTypeDestination;
+            break;
+
+        case TIAUpdateConnectionMethod::EConnectionMethodTypeAccessPoint:
+            type = ENcdConnectionMethodTypeAccessPoint;
+            break;
+
+        case TIAUpdateConnectionMethod::EConnectionMethodTypeDefault:
+            type = ENcdConnectionMethodTypeDefault;
+            break;
+
+        default:
+            User::Leave( KErrNotSupported );
+            break;
+        }
+        
+    TNcdConnectionMethod method( aMethod.iId, type );
+    iProvider->SetDefaultConnectionMethodL( method );
+
+    IAUPDATE_TRACE("[IAUPDATE] CIAUpdateController::SetDefaultAccessPointL end");
+    }
+
+
+// -----------------------------------------------------------------------------
+// CIAUpdateController::SelfUpdateDataExists
+//
+// -----------------------------------------------------------------------------
+//
+TBool CIAUpdateController::SelfUpdateDataExists() const
+    {
+    return iSelfUpdaterCtrl->DataExists();
+    }
+
+
+// -----------------------------------------------------------------------------
+// CIAUpdateController::StartPossibleSelfUpdateL
+//
+// -----------------------------------------------------------------------------
+//
+TBool CIAUpdateController::StartPossibleSelfUpdateL( 
+    TInt aIndex, 
+    TInt aTotalCount,
+    const RPointerArray< MIAUpdateNode >& aPendingNodes,
+    TBool aSilent )
+    {
+    IAUPDATE_TRACE("[IAUPDATE] CIAUpdateController::StartPossibleSelfUpdateL");
+    return SelfUpdaterCtrl().StartL( aIndex, aTotalCount, aPendingNodes, aSilent );
+    }
+
+
+// -----------------------------------------------------------------------------
+// CIAUpdateController::ResetSelfUpdate
+//
+// -----------------------------------------------------------------------------
+//
+void CIAUpdateController::ResetSelfUpdate()
+    {
+    IAUPDATE_TRACE("[IAUPDATE] CIAUpdateController::ResetSelfUpdate() begin");
+
+    SelfUpdaterCtrl().Reset();
+
+    IAUPDATE_TRACE("[IAUPDATE] CIAUpdateController::ResetSelfUpdate() end");
+    }
+
+
+// -----------------------------------------------------------------------------
+// CIAUpdateController::SelfUpdateRestartInfo
+//
+// -----------------------------------------------------------------------------
+//
+CIAUpdateRestartInfo* CIAUpdateController::SelfUpdateRestartInfo()
+    {
+    IAUPDATE_TRACE("[IAUPDATE] CIAUpdateController::SelfUpdateRestartInfo");
+    return SelfUpdaterCtrl().SelfUpdateRestartInfo();    
+    }
+
+
+// -----------------------------------------------------------------------------
+// CIAUpdateController::NodeL
+//
+// -----------------------------------------------------------------------------
+//
+MIAUpdateNode& CIAUpdateController::NodeL( 
+    const CIAUpdaterIdentifier& aIdentifier )
+    {
+    IAUPDATE_TRACE("[IAUPDATE] CIAUpdateController::NodeL begin");
+
+    CIAUpdateNode* node( NULL );
+
+    for ( TInt i = 0; i < iNodeContainer->AllNodes().Count(); ++i )
+        {
+        CIAUpdateNode* tmpNode( iNodeContainer->AllNodes()[ i ] );
+        if ( tmpNode->MetaNamespace() == aIdentifier.Namespace()
+             && tmpNode->MetaId() == aIdentifier.Id() ) 
+            {
+            node = tmpNode;
+            break;
+            }
+        }
+
+    if ( !node )
+        {
+        IAUPDATE_TRACE("[IAUPDATE] CIAUpdateController::NodeL node was not in the list");
+        for ( TInt i = 0; i < iNodeContainer->ExcessNodes().Count(); ++i )
+            {
+            CIAUpdateNode* tmpNode( iNodeContainer->ExcessNodes()[ i ] );
+            if ( tmpNode->MetaNamespace() == aIdentifier.Namespace()
+                 && tmpNode->MetaId() == aIdentifier.Id() ) 
+                {
+                IAUPDATE_TRACE("[IAUPDATE] CIAUpdateController::NodeL excess node found");
+                node = tmpNode;
+                break;
+                }
+            }        
+        }
+
+    if ( node == NULL )
+        {
+        IAUPDATE_TRACE("[IAUPDATE] CIAUpdateController::NodeL create excess node");
+        MNcdNode* ncdNode( NodeFromPurchaseHistoryL( aIdentifier ) );
+        node = IAUpdateNodeFactory::CreateNodeLC( ncdNode, *this );
+        iNodeContainer->AddExcessNodeL( node );
+        CleanupStack::Pop( node );
+        }
+
+    IAUPDATE_TRACE("[IAUPDATE] CIAUpdateController::NodeL end");
+
+    return *node;        
+    }
+
+
+// -----------------------------------------------------------------------------
+// CIAUpdateController::StartingUpdatesL
+//
+// -----------------------------------------------------------------------------
+//
+void CIAUpdateController::StartingUpdatesL()
+    {
+    IAUPDATE_TRACE("[IAUPDATE] CIAUpdateController::StartingUpdatesL begin");
+
+    if ( !iServerReportManager )
+        {
+        IAUPDATE_TRACE("[IAUPDATE] CIAUpdateController::StartingUpdatesL not found");
+        User::Leave( KErrNotFound );
+        }    
+
+    // Start collecting server reports because updates are going to be downloaded
+    // and installed.
+    // Set the reporting method to the manager method instead of letting NCD Engine
+    // do sending automatically. 
+    // After we have manually sent the reports, we may change the method back to 
+    // automatic and let the NCD Engine to do its thing as it seems best.
+    // The reason why to set the reporting method here when the updates start is that
+    // if for some reason the application was not able to send all the reports last time,
+    // in background mode they will be sent automatically when there is process time
+    // for that, for example before starting to do new updates.
+    iServerReportManager->SetReportingMethodL( MNcdServerReportManager::EReportingManaged );
+
+    IAUPDATE_TRACE("[IAUPDATE] CIAUpdateController::StartingUpdatesL end");
+    }
+
+
+// -----------------------------------------------------------------------------
+// CIAUpdateController::FinishedUpdatesL
+//
+// -----------------------------------------------------------------------------
+//
+void CIAUpdateController::FinishedUpdatesL( 
+    TBool aOperationsAllowed, TInt aMaxWaitTime )
+    {
+    IAUPDATE_TRACE("[IAUPDATE] CIAUpdateController::FinishedUpdatesL begin");
+
+    if ( !iProvider )
+        {
+        IAUPDATE_TRACE("[IAUPDATE] ERROR: Provider not found");
+        User::Leave( KErrNotFound );
+        }
+
+    // Reset the timer related flag. 
+    iReportTimerCompleted = EFalse;
+        
+    if ( aOperationsAllowed ) 
+        {
+        IAUPDATE_TRACE("[IAUPDATE] Operations allowed");
+        if ( !iReportOperation )
+            {
+            IAUPDATE_TRACE("[IAUPDATE] Create operation");
+            // Send the reports that have been collected.
+            // Notice, that the created operation needs to be released
+            // at some point.
+            MNcdServerReportOperation* tmpOperation(
+                iServerReportManager->SendL( *this ) );
+            if ( tmpOperation )
+                {
+                IAUPDATE_TRACE("[IAUPDATE] Start operation");
+
+                // Make sure that if the starting of the operation
+                // leaves, then the operation will be released correctly.
+                CleanupReleasePushL( *tmpOperation );
+
+                // Start the operation
+                tmpOperation->StartOperationL();
+
+                CleanupStack::Pop( tmpOperation );
+
+                // Because operation was successfully started,
+                // it can now be inserted to memeber variable.
+                iReportOperation = tmpOperation;
+
+                // Notice, that we do not Release the operation here. 
+                // We release it when the operation has finished and
+                // the callback is called.
+                }
+            }
+        }
+
+    if ( !iReportOperation )
+        {
+        IAUPDATE_TRACE("[IAUPDATE] Operation was not created");
+        // Set aMaxWaitTime as one. Then, we will get the timer
+        // to do only one quick asynchronous loop and callback
+        // is called after that. This way we make sure that
+        // callback is always called even if operation is not
+        // created here.
+        aMaxWaitTime = 0;
+        }
+
+    // Create timer if needed.
+    if ( aMaxWaitTime >= 0 )
+        {
+        IAUPDATE_TRACE_1("[IAUPDATE] Max wait time: %d", aMaxWaitTime);
+        if ( !iReportTimer )
+            {
+            IAUPDATE_TRACE("[IAUPDATE] Create timer");
+            // Timer does not exist yet. So, create new one.
+            iReportTimer = CIAUpdateTimer::NewL( *this );
+            }
+        else
+            {
+            IAUPDATE_TRACE("[IAUPDATE] Cancel timer");
+            // Timer already exists.
+            // Cancel possible already ongoing operation
+            // before starting the new one.
+            iReportTimer->Cancel();
+            }
+        IAUPDATE_TRACE("[IAUPDATE] Start timer");
+        iReportTimer->After( aMaxWaitTime );
+        }
+
+    // Because operation has now been started there is nothing to manage anymore.
+    // So, set the NCD Engine to automatic mode. Then, if there is something to do later
+    // in the background, the engine can do it when it suits it best.
+    iServerReportManager->SetReportingMethodL( MNcdServerReportManager::EReportingBackground );
+       
+    IAUPDATE_TRACE("[IAUPDATE] CIAUpdateController::FinishedUpdatesL end");
+    }
+
+
+// -----------------------------------------------------------------------------
+// CIAUpdateController::LoadComplete
+//
+// -----------------------------------------------------------------------------
+//
+void CIAUpdateController::LoadComplete( TInt aError )
+    {
+    IAUPDATE_TRACE("[IAUPDATE] CIAUpdateController::LoadComplete begin");
+    IAUPDATE_TRACE_1("[IAUPDATE] error code: %d", aError );
+
+    // Because node hierarchy is now concidered up-to-date,
+    // get all the required nodes from the local cache to the
+    // head node list that will be given to the observer.
+
+    TRAPD ( trapError, LocalLoadL() );
+    if ( trapError != KErrNone )
+        {
+        aError = trapError;        
+        }
+
+    // Update the state, now that everything has been done.
+    iControllerState = EIdle;
+
+    // Inform, the observer.            
+    iObserver.RefreshComplete( iNodes, aError );
+
+    IAUPDATE_TRACE("[IAUPDATE] CIAUpdateController::LoadComplete end");
+    }
+
+
+// -----------------------------------------------------------------------------
+// CIAUpdateController::SelfUpdaterComplete
+//
+// -----------------------------------------------------------------------------
+//
+void CIAUpdateController::SelfUpdaterComplete( TInt aErrorCode )
+    {
+    IAUPDATE_TRACE_1("[IAUPDATE] CIAUpdateController::SelfUpdaterComplete() error code: %d", aErrorCode );
+    iObserver.SelfUpdaterComplete( aErrorCode );
+    }
+
+
+// -----------------------------------------------------------------------------
+// CIAUpdateController::
+//
+// -----------------------------------------------------------------------------
+//
+void CIAUpdateController::CatalogsEngineShutdown()
+    {
+    // IAD handles self updates in its own updater.
+    // Therefore, self updates are not started by NCD Engine itself.
+    // So, this callback function should be never called.  
+    }
+
+
+// -----------------------------------------------------------------------------
+// CIAUpdateController::CatalogsUpdateNotification
+//
+// -----------------------------------------------------------------------------
+//
+void CIAUpdateController::CatalogsUpdateNotification( 
+    const TDesC& /*aTarget*/, 
+    const TDesC& /*aId*/,
+    const TDesC& /*aVersion*/,
+    const TDesC& /*aUri*/,
+    TBool /*aForce*/ )
+    {
+    // Called when a Catalogs OTA update is available.
+    // IAD handles self updates in its own updater.    
+    // This callback function should be never called.
+    }
+
+
+// -----------------------------------------------------------------------------
+// CIAUpdateController::CatalogsConnectionEvent
+//
+// -----------------------------------------------------------------------------
+//
+void CIAUpdateController::CatalogsConnectionEvent( 
+    TBool /*aConnectionActive*/ )
+    {
+    // This callback function is called when data is transferred in the
+    // network connections. IAD does not use this information for now.
+    }    
+
+
+// -----------------------------------------------------------------------------
+// CIAUpdateController::ForceExpirationInformationReceived
+//
+// -----------------------------------------------------------------------------
+//
+void CIAUpdateController::ForceExpirationInformationReceived( 
+    RCatalogsArray< MNcdNode >& /*aExpiredNodes*/ )
+    {
+    // IAD UI is not forced to be updated by the server side.
+    // It is up to the UI to decide when to update its content.
+    }
+
+
+// -----------------------------------------------------------------------------
+// CIAUpdateController::LocalizeString
+//
+// -----------------------------------------------------------------------------
+//
+HBufC* CIAUpdateController::LocalizeString( 
+    const TDesC& /*aLocalizationKey*/ )
+    {
+    return NULL;
+    }
+
+
+// ---------------------------------------------------------------------------
+// CIAUpdateController::ReportProgress
+// 
+// ---------------------------------------------------------------------------
+//
+void CIAUpdateController::ReportProgress( 
+    MNcdServerReportOperation& /*aOperation*/, 
+    TNcdProgress /*aProgress*/ )
+    {
+    IAUPDATE_TRACE("[IAUPDATE] CIAUpdateController::ReportProgress()");
+    }
+
+
+// ---------------------------------------------------------------------------
+// CIAUpdateController::QueryReceived
+// 
+// ---------------------------------------------------------------------------
+//
+void CIAUpdateController::QueryReceived( 
+    MNcdServerReportOperation& aOperation, 
+    MNcdQuery* aQuery )
+    {
+    IAUPDATE_TRACE("[IAUPDATE] CIAUpdateController::QueryReceived() begin");
+
+    // Install query received.
+    // Always accept queries.
+    // Queries should not be requested from this client.
+    TInt trapError( KErrNone );
+    if ( aQuery )
+        {
+        TRAP ( trapError, 
+               aQuery->SetResponseL( MNcdQuery::EAccepted );
+               aOperation.CompleteQueryL( *aQuery ); );
+        // Release needs to be called to the query after it is not used.
+        aQuery->Release();        
+        }
+
+    if ( ( trapError != KErrNone ) || ( !aQuery ) )
+        {
+        // Error occurred when query was handled.
+        // So, operation can not continue.
+        // Cancel operation. Notice, that OperationComplete will be called
+        // by the operation when cancel is called.
+        aOperation.CancelOperation();
+        }
+
+    IAUPDATE_TRACE("[IAUPDATE] CIAUpdateController::QueryReceived() end");
+    }
+
+
+// ---------------------------------------------------------------------------
+// CIAUpdateController::OperationComplete
+// 
+// ---------------------------------------------------------------------------
+//
+void CIAUpdateController::OperationComplete( 
+    MNcdServerReportOperation& aOperation, 
+    TInt aError )
+    {
+    IAUPDATE_TRACE("[IAUPDATE] CIAUpdateController::OperationComplete() begin");
+
+    // Report operation has completed.
+    
+    if ( &aOperation == iReportOperation )
+        {
+        IAUPDATE_TRACE("[IAUPDATE] Acceptable server report operation");
+
+        // We should always come here
+        // because only one operation at a time is going on.
+
+        // Release the operation because we do not need it anymore
+        // and because operation reference count was increased when
+        // it was created for this class object.        
+        iReportOperation->Release();
+        iReportOperation = NULL;
+
+        // By checking if the timer has completed its job, we know if
+        // the observer should be informed about the completion of the
+        // operation. This way we will avoid duplicate callbacks, for example,
+        // after timer completion has called callback and the report operation
+        // completes after that.
+        if ( !iReportTimerCompleted )
+            {
+            IAUPDATE_TRACE("[IAUPDATE] Timer has not informed observer yet");
+
+            // Because operation is completed, no need for the timer anymore.
+            // So, delete timer if it exists. Deletion will automatically
+            // cancel the timer operation.
+            delete iReportTimer;
+            iReportTimer = NULL;
+
+            // Do not call callback function if cancel was started by user. 
+            if ( !iCancellingReportOperation )
+                {
+                IAUPDATE_TRACE("[IAUPDATE] Inform observer.");
+                iObserver.ServerReportSent( aError );        
+                }
+            }
+        }
+
+    IAUPDATE_TRACE("[IAUPDATE] CIAUpdateController::OperationComplete() end");
+    }
+
+
+// ---------------------------------------------------------------------------
+// CIAUpdateController::TimerComplete
+// 
+// ---------------------------------------------------------------------------
+//
+void CIAUpdateController::TimerComplete( TInt aError )
+    {
+    IAUPDATE_TRACE_1("[IAUPDATE] CIAUpdateController::TimerComplete() begin: %d",
+                     aError);
+
+    // If we come here it means that timer has completed before
+    // the reports were actually sent and before the operation is released. 
+
+    // Timer has done its job. So delete it.
+    delete iReportTimer;
+    iReportTimer = NULL;
+
+    // Set the flag. Then, observer will not be informed twice when the
+    // report operation is actually completed.
+    iReportTimerCompleted = ETrue;
+
+    // Inform the observer that it should continue even if reports are still
+    // being sent in the background. Notice, that the report operation most likely
+    // will complete later and then OperationComplete will be called.
+    iObserver.ServerReportSent( aError );
+
+    IAUPDATE_TRACE("[IAUPDATE] CIAUpdateController::TimerComplete() end");
+    }
+
+
+// -----------------------------------------------------------------------------
+// CIAUpdateController::DoCancel
+//
+// -----------------------------------------------------------------------------
+//
+void CIAUpdateController::DoCancel()
+    {
+    IAUPDATE_TRACE("[IAUPDATE] CIAUpdateController::DoCancel() begin");
+    IAUPDATE_TRACE_1("[IAUPDATE] ControllerState: %d", iControllerState );
+
+    switch ( iControllerState )
+        {
+        case EStarting:
+            {
+            // This controller is trying to create the 
+            // provider. Cancel that.
+            iEngine->CancelProviderCreation();
+            iControllerState = ENotRunning;            
+            }
+            break;
+
+        case EInLocalLoadOperation:
+            {
+            // Local loading was cancelled. 
+            // Nothing to cancel, because complete of the request already issued
+            iControllerState = EIdle;
+            }
+            break;
+
+        default:
+            // We should never come here.
+            break;
+        }
+
+    IAUPDATE_TRACE("[IAUPDATE] CIAUpdateController::DoCancel() end");
+    }
+
+
+// -----------------------------------------------------------------------------
+// CIAUpdateController::RunL
+//
+// -----------------------------------------------------------------------------
+//
+void CIAUpdateController::RunL()
+    {
+    IAUPDATE_TRACE("[IAUPDATE] CIAUpdateController::RunL() begin");
+    IAUPDATE_TRACE_1("[IAUPDATE] ControllerState: %d", iControllerState);
+    IAUPDATE_TRACE_1("[IAUPDATE] Error code: %d", iStatus.Int());        
+
+    // If we were trying to start the provider we may get different
+    // error codes that are still acceptable. For example, the DB may have
+    // been cleaned because of some error situation. But, then we just have
+    // to continue after that normally. 
+    // In other cases, KErrNone will inform about success.
+    // Possible feedback from the provider contains the following error
+    // codes that are interpreted as success: 
+    // KErrNone, KNcdDatabasesClearedAfterCrash, KNcdPurchaseHistoryVersionMismatch,
+    // KNcdGeneralDatabaseVersionMismatch. 
+    // Notice, that the actual error code can be a combination of these numbers.
+
+    // Get the error code.
+    TInt errorCode( iStatus.Int() );
+ 
+    // This will leave if error code is negative. 
+    // KErrNone and positive error codes are interpreted as success.
+    // If leave occurs, let RunError handle it.
+    User::LeaveIfError( errorCode );
+
+    switch ( iControllerState )
+        {
+        case EStarting:
+            {
+            if ( !iBaseProvider )
+                {
+                User::Leave( KErrGeneral );
+                }
+
+            // Change the error code to iaupdate specific if necessary.
+            if ( errorCode > 0 )
+                {
+                IAUPDATE_TRACE("[IAUPDATE] NCD cache cleared. Change error code to iaupdate specific.");
+                errorCode = IAUpdateErrorCodes::KErrCacheCleared;        
+                }
+                
+            iProvider = iBaseProvider->QueryInterfaceL<MNcdProvider>();
+            iProvider->SetObserver( this );
+            iProvider->SetStringLocalizer( *this );
+            
+            SetupConfigurationL();
+
+            iServerReportManager = 
+                iProvider->QueryInterfaceL<MNcdServerReportManager>();
+            // Because we want to send S60 error codes instead of general
+            // codes into the server, set the style here.
+            iServerReportManager->
+                SetReportingStyleL( 
+                    MNcdServerReportManager::EReportingStyleS60 );
+
+            // Cancel possible paused operations.
+            // So, they do not prevent others to start their operations.
+            CancelPausedOperationsL();
+            
+            // Everything was handled correctly. So, set the state and
+            // inform observer.
+            iControllerState = EIdle;            
+            iObserver.StartupComplete( errorCode );
+            }
+            break;
+
+        case EInClearCache:
+            {
+            IAUPDATE_TRACE("[IAUPDATE] Load nodes from net.");
+            // Cache has been cleaned.
+
+            // Save the current information to clear file.
+            iCacheClearFile->SetCurrentData();
+            iCacheClearFile->WriteControllerDataL();
+
+            // Next, load necessary nodes from the net.
+            // This starts an asynchronous operation which will end
+            // when callback is called.
+            iLoader->LoadNodesL();
+
+            iControllerState = EInLoadOperation;
+            }
+            break;
+
+        case EInLocalLoadOperation:
+            {
+            // Nodes should be gotten from the local database instead of 
+            // from the internet.
+            LocalLoadL();
+                
+            // New state should be idle because after this function
+            // everything is done and observer is informed.
+            // Notice, that the state is inserted here after all the other
+            // functionality has been handeled because if the code above leaves,
+            // then RunError will be able to check the state and handle things 
+            // correctly.
+            iControllerState = EIdle;
+
+            // Inform, the observer.            
+            iObserver.RefreshComplete( iNodes, KErrNone );            
+            }
+            break;
+        
+        default:
+            break;
+        }
+
+    IAUPDATE_TRACE("[IAUPDATE] CIAUpdateController::RunL() end");
+    }
+  
+    
+// -----------------------------------------------------------------------------
+// CIAUpdateController::RunError
+//
+// -----------------------------------------------------------------------------
+//    
+TInt CIAUpdateController::RunError( TInt aError )
+    {
+    IAUPDATE_TRACE("[IAUPDATE] CIAUpdateController::RunError() begin");
+    IAUPDATE_TRACE_1("[IAUPDATE] ControllerState: %d", iControllerState );
+
+    switch ( iControllerState )
+        {
+        case EStarting:
+            iControllerState = ENotRunning;
+            iObserver.StartupComplete( aError );
+            break;
+
+        case EInLocalLoadOperation:
+        case EInClearCache:
+            // Local load left in RunL.
+            iControllerState = EIdle;
+            iObserver.RefreshComplete( iNodes, aError );
+            break;
+
+        default:
+            // We should not come here.
+            break;
+        }
+
+    IAUPDATE_TRACE("[IAUPDATE] CIAUpdateController::RunError() end");    
+
+    return KErrNone;
+    }
+ 
+
+// -----------------------------------------------------------------------------
+// CIAUpdateController::LocalLoadL()
+//
+// -----------------------------------------------------------------------------
+// 
+void CIAUpdateController::LocalLoadL()
+    {
+    IAUPDATE_TRACE("[IAUPDATE] CIAUpdateController::LocalLoadL() begin");
+
+    MNcdNode* rootNode( iProvider->RootNodeL() );
+    if ( !rootNode )
+        {
+        IAUPDATE_TRACE("[IAUPDATE] ERROR: NULL root was given.");
+        User::Leave( KErrNotFound );
+        }
+
+    if ( rootNode->State() == MNcdNode::EStateNotInitialized )
+        {
+        IAUPDATE_TRACE("[IAUPDATE] Root node uninitialized. Do not continue local load.");
+        rootNode->Release();
+        return;
+        }
+
+    CleanupReleasePushL( *rootNode );
+
+    MNcdNodeContainer* rootContainer = 
+        rootNode->QueryInterfaceLC< MNcdNodeContainer >();
+    if ( !rootContainer )
+        {
+        IAUPDATE_TRACE("[IAUPDATE] ERROR: NULL container for root.");
+        // Root should always have container interface.
+        User::Leave( KErrNotFound );
+        }
+
+    // The given node was root node.
+
+    LocalContainerLoadL( *rootContainer );
+
+    CleanupStack::PopAndDestroy( rootContainer );
+    rootContainer = NULL;
+            
+    CleanupStack::PopAndDestroy( rootNode );
+    rootNode = NULL;
+
+    // The iNodeContainer now contains all the necessary nodes.
+    // Get the nodes from the iNodeContainer.
+    // Make sure that the array is clean before adding new items.
+    iNodes.Reset();
+
+    // Get references to the node arrays.
+    const RPointerArray< CIAUpdateFwNode >& fwNodes = 
+        iNodeContainer->FwNodes();
+    const RPointerArray< CIAUpdateNode >& headNodes = 
+        iNodeContainer->HeadNodesL();
+
+    // Make sure we have enough memory for the array.
+    TInt fwNodeCount( fwNodes.Count() );
+    TInt headNodeCount( headNodes.Count() );
+    iNodes.ReserveL( fwNodeCount + headNodeCount );
+
+    // Insert the firmware nodes into the beginning of the array.
+    for ( TInt i = 0; i < fwNodeCount; ++i )
+        {
+        // Notice, that the ownership is not transferred here.
+        MIAUpdateAnyNode* anyNode( fwNodes[ i ] );
+        iNodes.AppendL( anyNode );
+        }
+
+    // Insert the head nodes into the array.
+    for ( TInt i = 0; i < headNodeCount; ++i )
+        {
+        // Notice, that the ownership is not transferred here.
+        MIAUpdateAnyNode* anyNode( headNodes[ i ] );
+        iNodes.AppendL( anyNode );
+        }
+
+    IAUPDATE_TRACE("[IAUPDATE] CIAUpdateController::LocalLoadL() end");
+    }
+
+    
+// -----------------------------------------------------------------------------
+// CIAUpdateController::LocalContainerLoadL
+//
+// -----------------------------------------------------------------------------
+//   
+void CIAUpdateController::LocalContainerLoadL( 
+    MNcdNodeContainer& aContainer )
+    {
+    IAUPDATE_TRACE("[IAUPDATE] CIAUpdateController::LocalContainerLoadL() begin");
+
+    // Insert all the item children (that are not uninitilized) 
+    // from the container node into the iNodeContainer. 
+    // So, iNodeContainer will have all the item children in its list.
+    
+    TInt childCount( aContainer.ChildCount() );	        
+    IAUPDATE_TRACE_1("[IAUPDATE] childcount: %d", childCount);	        
+
+    for ( TInt i = 0; i < childCount; ++i )
+        {
+        IAUPDATE_TRACE_1("[IAUPDATE] child index: %d", i );
+        
+        // This call increases the reference count of the child.
+        MNcdNode* child( aContainer.ChildL( i ) );
+
+        if ( child )
+            {
+            // Notice, that we need to check if the child really exists.
+            // If a container has been loaded from the net, it has 
+            // its child count. But, children may have not been loaded.
+            IAUPDATE_TRACE("[IAUPDATE] Child was loaded.");
+            if ( child->State() == MNcdNode::EStateNotInitialized )
+                {
+                IAUPDATE_TRACE("[IAUPDATE] Skip uninitialized child.");
+                // Skip uninitialized child.
+                // Remember to release it here.
+                child->Release();
+                child = NULL;
+                }
+            else
+                {
+                // Insert child into the cleanup stack. 
+                // So, if functions leave, it will be released.
+                CleanupReleasePushL( *child );
+
+                // Notice, that this has to be released.
+                MNcdNodeContainer* childContainer( 
+                    child->QueryInterfaceL< MNcdNodeContainer >() );
+
+                if ( !childContainer )
+                    {
+                    IAUPDATE_TRACE("[IAUPDATE] Item node");            
+
+                    TBool isFwNode( 
+                        IAUpdateNodeFactory::IsFwUpdateL( *child ) ); 
+
+                    // Because the factory takes care of the deletion of the child object,
+                    // just pop it from the cleanup stack here. So, no release is called here.
+                    CleanupStack::Pop( child );
+
+                    if ( isFwNode  && !IAUpdateUtils::IsFirmwareChangedL() ) 
+                        {
+                        // if phone's firmware changed after previous successfull network refresh,
+                        // firmware nodes are skipped. That's a workaround to hide them from UI just after 
+                        // firmware update. 
+                                      
+                        // Notice, that the IAUpdateNodeFactory and CIAUpdateNodeContainer 
+                        // take the ownership and release the node if the creation leaves.
+                        CIAUpdateFwNode* node( NULL );
+                        // Trap error here. 
+                        // If one node fails, others may still be created.
+                        TRAP_IGNORE( 
+                            node = IAUpdateNodeFactory::CreateFwNodeL( child, *this ) );
+                        if ( node )
+                            {
+                            IAUPDATE_TRACE("[IAUPDATE] Fw node created successfully");
+                            // If leave occurs, then AddNodeL will itself delete the created node.
+                            // So, do not insert the node into the cleanup stack here.
+                            iNodeContainer->AddFwNodeL( node );
+                            }
+                        }
+                    else
+                        {
+                        // Notice, that the IAUpdateNodeFactory and CIAUpdateNodeContainer 
+                        // take the ownership and release the node if the creation leaves.
+                        CIAUpdateNode* node( NULL );
+                        // Trap error here. 
+                        // If one node fails, others may still be created.
+                        TRAP_IGNORE( 
+                            node = IAUpdateNodeFactory::CreateNodeL( child, *this ) );
+                        if ( node )
+                            {
+                            IAUPDATE_TRACE("[IAUPDATE] Node created successfully");
+                            // If leave occurs, then AddNodeL will itself delete the created node.
+                            // So, do not insert the node into the cleanup stack here.
+                            iNodeContainer->AddNodeL( node );
+                            }
+                        }
+                    }
+                else
+                    {
+                    IAUPDATE_TRACE("[IAUPDATE] Container node");
+
+                    // The ownership of the child was not transferred to
+                    // anybody, the node has to be released here.
+                    CleanupStack::PopAndDestroy( child );
+
+                    CleanupReleasePushL( *childContainer );
+
+                    // Because this is a container, use recursion to insert its
+                    // child items into the node container.
+                    LocalContainerLoadL( *childContainer );
+
+                    CleanupStack::PopAndDestroy( childContainer );
+                    }
+                }
+            }
+        }
+    
+    IAUPDATE_TRACE("[IAUPDATE] CIAUpdateController::LocalContainerLoadL() begin");
+    }
+
+
+// -----------------------------------------------------------------------------
+// CIAUpdateController::SetupConfigurationL
+//
+// -----------------------------------------------------------------------------
+// 
+void CIAUpdateController::SetupConfigurationL()
+    {
+    IAUPDATE_TRACE("[IAUPDATE] CIAUpdateController::SetupConfigurationL() begin");
+
+    CIAUpdateEngineXmlParser* parser( CIAUpdateEngineXmlParser::NewLC() );
+    parser->ParseL();
+    const CIAUpdateEngineConfigData& data( parser->ConfigData() );
+
+    CNcdKeyValuePair* pair( NULL );
+    
+
+    // Master server (CDB) uri
+    IAUPDATE_TRACE_1("[IAUPDATE] master server: %S", &data.MasterServerUri() );
+    pair = CNcdKeyValuePair::NewLC( NcdConfigurationKeys::KMasterServer(), 
+                                    data.MasterServerUri() );
+    iProvider->AddConfigurationL( *pair );
+    CleanupStack::PopAndDestroy( pair );
+        
+    // Max storage size
+    // Notice, this value does not have any effect if the cache cleaner is
+    // turned off when provider is created.
+    const TDesC& storageMaxSize( data.StorageMaxSize() );
+    if ( storageMaxSize == KNullDesC )
+        {
+        IAUPDATE_TRACE("[IAUPDATE] Use default storage max size");
+        pair = CNcdKeyValuePair::NewLC( NcdConfigurationKeys::KMaxStorageSize(), 
+                                        IAUpdateCtrlConsts::KDefaultStorageMaxSize() );
+        }
+    else
+        {
+        IAUPDATE_TRACE("[IAUPDATE] Use config file storage max size");
+        pair = CNcdKeyValuePair::NewLC( NcdConfigurationKeys::KMaxStorageSize(), 
+                                        storageMaxSize );        
+        }
+    iProvider->AddConfigurationL( *pair );
+    CleanupStack::PopAndDestroy( pair );
+
+    // Software version
+    // Notice, that here we use the hardcoded value instead of parsing the data
+    // from the configuration XML file. This should be hardcoded value because the
+    // version number is strictly related to the version of the engine. So, the version
+    // should not be altered by different configuration files.
+    pair = CNcdKeyValuePair::NewLC( NcdConfigurationKeys::KSoftwareVersion(), 
+                                    IAUpdateCtrlConsts::KSoftwareVersion() );
+    iProvider->AddConfigurationL( *pair );
+    CleanupStack::PopAndDestroy( pair );
+    
+    // Software type
+    // Notice, that here we use the hardcoded value instead of parsing the data
+    // from the configuration XML file. This should be hardcoded value because the
+    // software type is always same for the engine. It should not be allowed to
+    // change by defining new value in config file.
+    pair = CNcdKeyValuePair::NewLC( NcdConfigurationKeys::KSoftwareType(), 
+                                    IAUpdateCtrlConsts::KSoftwareType() );
+    iProvider->AddConfigurationL( *pair );
+    CleanupStack::PopAndDestroy( pair );
+
+    // Provisioning
+    pair = CNcdKeyValuePair::NewLC( NcdConfigurationKeys::KProvisioning(), 
+                                    data.Provisioning() );
+    iProvider->AddConfigurationL( *pair );
+    CleanupStack::PopAndDestroy( pair );
+
+    // Client role
+    // This value is used in the server requests.
+    pair = CNcdKeyValuePair::NewLC( IAUpdateProtocolConsts::KIAClientRole(), 
+                                    data.ClientRole() );
+    iProvider->AddConfigurationL( *pair );
+    CleanupStack::PopAndDestroy( pair );
+    iObserver.ClientRole( data.ClientRole() );
+
+
+    // No need for the parser anymore.
+    CleanupStack::PopAndDestroy( parser );
+    parser = NULL;
+
+    
+    // Language
+    TLanguage language( User::Language() );
+    HBufC* languageDes( HBufC::NewLC( 32 ) );
+    TPtr languagePtr( languageDes->Des() );
+    languagePtr.AppendNum( language );
+    pair = CNcdKeyValuePair::NewLC( NcdConfigurationKeys::KSoftwareLanguage(), 
+                                    languagePtr );
+    iProvider->AddConfigurationL( *pair );
+    CleanupStack::PopAndDestroy( pair );
+    CleanupStack::PopAndDestroy( languageDes );
+
+
+    // Capabilities accepted by the client.
+    // These capabilities define actions between the client and the server.
+    
+    // Download report
+    pair = CNcdKeyValuePair::NewLC( NcdConfigurationKeys::KCapability(),
+                                    NcdCapabilities::KDownloadReport() );
+    iProvider->AddConfigurationL( *pair );
+    CleanupStack::PopAndDestroy( pair );
+    
+    // Install report
+    pair = CNcdKeyValuePair::NewLC( NcdConfigurationKeys::KCapability(),
+                                    NcdCapabilities::KInstallationReport() );
+    iProvider->AddConfigurationL( *pair );
+    CleanupStack::PopAndDestroy( pair );
+
+    IAUPDATE_TRACE("[IAUPDATE] CIAUpdateController::SetupConfigurationL() end");
+    }
+
+
+// -----------------------------------------------------------------------------
+// CIAUpdateController::NodeFromPurchaseHistoryL
+//
+// -----------------------------------------------------------------------------
+//
+MNcdNode* CIAUpdateController::NodeFromPurchaseHistoryL( 
+    const CIAUpdaterIdentifier& aIdentifier )
+    {
+    IAUPDATE_TRACE("[IAUPDATE] CIAUpdateController::NodeFromPurchaseHistoryL() begin");
+
+    // This will contain the correct details object.
+    CNcdPurchaseDetails* details( NULL );
+
+    // Create filter. So, we will get
+    // all the purchase history items.
+    CNcdPurchaseHistoryFilter* filter =
+        CNcdPurchaseHistoryFilter::NewLC();
+    filter->SetNamespaceL( aIdentifier.Namespace() );
+    filter->SetEntityIdL( aIdentifier.Id() );
+    
+    // Add family uid to the filter
+    RArray< TUid > uids;
+    CleanupClosePushL( uids );
+    uids.AppendL( FamilyUid() );
+    filter->SetClientUids( uids.Array() );
+    CleanupStack::PopAndDestroy( &uids );
+
+    MNcdPurchaseHistory* history( ProviderL().PurchaseHistoryL() );
+    CleanupReleasePushL( *history );
+    
+    // Get the ids. So, we can next get all the corresponding
+    // details.
+    RArray< TUint > ids = history->PurchaseIdsL( *filter );
+    // Temporarily remove history from cleanup stack
+    CleanupStack::Pop( history );
+    CleanupStack::PopAndDestroy( filter );
+    CleanupReleasePushL( *history );
+    CleanupClosePushL( ids );
+    
+    if ( ids.Count() > 0 )
+        {
+        // If purchase details exist, then use the most up-to-date one.
+        details = 
+            history->PurchaseDetailsL( ids[ 0 ], EFalse );
+        }
+    
+    CleanupStack::PopAndDestroy( &ids );
+    CleanupStack::PopAndDestroy( history );
+    
+    if ( details == NULL )
+        {
+        User::Leave( KErrNotFound );
+        }
+    else
+        {
+        // The details was created but not inserted into
+        // the cleanup stack there. Insert it into the cleanupstack now.
+        CleanupStack::PushL( details );
+        }
+
+    MNcdNode* node( ProviderL().NodeL( *details ) );
+    if ( node == NULL )
+        {
+        User::Leave( KErrNotFound );
+        }
+
+    CleanupStack::PopAndDestroy( details );
+
+    IAUPDATE_TRACE("[IAUPDATE] CIAUpdateController::NodeFromPurchaseHistoryL() end");
+
+    return node;
+    }
+
+
+// -----------------------------------------------------------------------------
+// CIAUpdateController::NodeFromPurchaseHistoryL
+//
+// -----------------------------------------------------------------------------
+//
+void CIAUpdateController::CancelPausedOperationsL()
+    {
+    IAUPDATE_TRACE("[IAUPDATE] CIAUpdateController::CancelPausedOperationsL() begin");
+    
+    // Cancel possible paused operations here.
+    // IAD Engine does not itself pause operations. 
+    // But, in some error cases download operation may have become paused.
+    // By cancelling a paused operation, we can avoid locking if multiple IAD UIs 
+    // are opened. Else, the paused operations that belong to first opened UI 
+    // will block the starting of the operations from another IAD UIs.
+    // Because these operations are created for the one IAD, 
+    // they will be blocking other UI operations because multiple 
+    // simultaneous operations are not allowed for same metadata content.
+    // When the IAD is started, the operations that are paused will be
+    // created in the NCD Provider and they are part of that IAD UI via NCD
+    // Provider Proxy.
+    
+    // Notice, Release needs to be called for array elements.
+    RCatalogsArray< MNcdOperation > operations = 
+        iProvider->OperationsL();
+
+    // Push the array into the cleanupstack. So, PopAndDestroy will
+    // call Release to the array items and finally reset the array.
+    CleanupResetAndDestroyPushL( operations );
+        
+    TInt count( operations.Count() );
+    IAUPDATE_TRACE_1("[IAUPDATE] Pending operation count: %d", count);
+    for ( TInt i = 0; i < count; ++i )
+        {
+        MNcdOperation* operation( operations[ i ] );
+        MNcdDownloadOperation* download( 
+            operation->QueryInterfaceLC< MNcdDownloadOperation >() );
+        if ( download && download->IsPaused() )
+            {
+            // A download operation has been left hanging as paused.
+            // Just, cancel it. So, it will not prevent possible other
+            // download attempts from other IAD UIs. We cancel this operations
+            // already now, because we may not actually start it later in this
+            // UI.
+            IAUPDATE_TRACE_1("[IAUPDATE] Cancel paused operation: %d", i);
+            operation->CancelOperation();
+            CleanupStack::PopAndDestroy( download );
+            }
+        }
+    
+    // This will Release array elements and reset the array.
+    CleanupStack::PopAndDestroy( &operations );
+
+    IAUPDATE_TRACE("[IAUPDATE] CIAUpdateController::CancelPausedOperationsL() begin");
+    }