phonebookui/Phonebook2/CommonUI/src/CPbk2ContactRelocator.cpp
changeset 0 e686773b3f54
child 14 81f8547efd4f
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/phonebookui/Phonebook2/CommonUI/src/CPbk2ContactRelocator.cpp	Tue Feb 02 10:12:17 2010 +0200
@@ -0,0 +1,1015 @@
+/*
+* Copyright (c) 2002-2007 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:  Contacts relocator.
+*
+*/
+
+
+
+// INCLUDE FILES
+#include <CPbk2ContactRelocator.h>
+
+// Phonebook 2
+#include <CPbk2StoreConfiguration.h>
+#include <MPbk2ApplicationServices.h>
+#include <Phonebook2PrivateCRKeys.h>
+#include <MPbk2ContactRelocatorObserver.h>
+#include <Pbk2CommonUi.rsg>
+#include <CPbk2StoreProperty.h>
+#include <CPbk2StorePropertyArray.h>
+#include <MPbk2ContactNameFormatter.h>
+#include <TPbk2DestructionIndicator.h>
+
+// Virtual Phonebook
+#include <MVPbkStoreContact.h>
+#include <MVPbkContactStore.h>
+#include <MVPbkContactStoreList.h>
+#include <MVPbkContactStoreProperties.h>
+#include <VPbkContactStoreUris.h>
+#include <CVPbkContactStoreUriArray.h>
+#include <CVPbkContactManager.h>
+#include <MVPbkContactOperationBase.h>
+#include <MVPbkContactLink.h>
+#include <TVPbkContactStoreUriPtr.h>
+#include <CVPbkContactLinkArray.h>
+#include <CPbk2ApplicationServices.h>
+#include <MVPbkContactCopyPolicy.h>
+#include <CVPbkContactCopyPolicyManager.h>
+
+// System includes
+#include <centralrepository.h>
+#include <StringLoader.h>
+#include <AknQueryDialog.h>
+
+/// Unnamed namespace for local definitions
+namespace {
+
+// LOCAL CONSTANTS AND MACROS
+
+const TInt KFirstElement = 0;
+const TInt KOneContact = 1;
+const TInt KDefaultTitleFormat = MPbk2ContactNameFormatter::EUseSeparator;
+
+#ifdef _DEBUG
+
+// Definition for many contacts relocation
+const TInt KLinkArrayRelocationMinCount = 2;
+
+enum TPanicCode
+    {
+    EPanicPreCond_ContactsSaved,
+    EPanicLogic_AskConfirmationL,
+    EPanicPreCond_RelocateContactL,
+    EPanicPreCond_RelocateContactsL,
+    EPanicPreCond_RelocateAndLockContactL,
+    EPanicPreCond_PrepareToRelocateContactL,
+    EPanicPreCond_DeleteSourceContact,
+    EPanicPreCond_VerifyRelocationQueryType
+    };
+
+void Panic( TInt aReason )
+    {
+    _LIT( KPanicText, "CPbk2ContactRelocator" );
+    User::Panic( KPanicText, aReason );
+    }
+
+#endif // _DEBUG
+
+/**
+ * Fetches contact's store name, which can be use in relocation queries.
+ * If store name cannot be fetched from global store properties, then
+ * contact's store property is returned.
+ *
+ * @param aContact Reference to contact.
+ * @param aStoreProperties Reference to store properties.
+ * @return Pointer to store name. Ownership is not transferred
+ */
+const TDesC* StoreName(
+        const MVPbkStoreContact* aContact,
+        CPbk2StorePropertyArray& aStoreProperties )
+    {
+    const TDesC* storeName = NULL;
+    if ( aContact )
+        {
+        // Fetch store name
+        TVPbkContactStoreUriPtr uri =
+            aContact->ParentStore().StoreProperties().Uri();
+        const CPbk2StoreProperty* storeProperty =
+            aStoreProperties.FindProperty( uri );
+
+        if (storeProperty)
+            {
+            storeName = &storeProperty->StoreName();
+            }
+        else
+            {
+            storeName = &uri.UriDes();
+            }        
+        }
+    return storeName;
+    }
+
+} // namespace
+
+
+// --------------------------------------------------------------------------
+// CPbk2ContactRelocator::CPbk2ContactRelocator
+// --------------------------------------------------------------------------
+//
+CPbk2ContactRelocator::CPbk2ContactRelocator() :
+        CActive( CActive::EPriorityStandard )
+    {
+    CActiveScheduler::Add( this );
+    }
+
+// --------------------------------------------------------------------------
+// CPbk2ContactRelocator::~CPbk2ContactRelocator
+// --------------------------------------------------------------------------
+//
+CPbk2ContactRelocator::~CPbk2ContactRelocator()
+    {
+    Cancel();
+    delete iSourceContact;
+    delete iSourceContacts;
+    delete iRelocatedContact;
+    delete iContactRetriever;
+    delete iSavedContactsRetriever;
+    delete iContactCopier;
+    delete iCopyPolicyManager;
+    delete iQueryDialog;
+
+    if ( iTargetStore )
+        {
+        iTargetStore->Close( *this );
+        }
+
+    if ( iDestroyedPtr )
+        {
+        *iDestroyedPtr = ETrue;
+        }
+    Release( iAppServices ); 
+    }
+
+// --------------------------------------------------------------------------
+// CPbk2ContactRelocator::NewL
+// --------------------------------------------------------------------------
+//
+EXPORT_C CPbk2ContactRelocator* CPbk2ContactRelocator::NewL()
+    {
+    CPbk2ContactRelocator* self =
+        new ( ELeave ) CPbk2ContactRelocator();
+    CleanupStack::PushL( self );
+    self->ConstructL();
+    CleanupStack::Pop( self );
+    return self;
+    }
+
+// --------------------------------------------------------------------------
+// CPbk2ContactRelocator::ConstructL
+// --------------------------------------------------------------------------
+//
+inline void CPbk2ContactRelocator::ConstructL()
+    {
+    iAppServices = CPbk2ApplicationServices::InstanceL();
+    iRelocationPolicy = ReadRelocationPolicyL();
+    }
+
+// --------------------------------------------------------------------------
+// CPbk2ContactRelocator::RelocateContactL
+// --------------------------------------------------------------------------
+//
+EXPORT_C TBool CPbk2ContactRelocator::RelocateContactL(
+        MVPbkStoreContact* aContact,
+        MPbk2ContactRelocatorObserver& aObserver,
+        Pbk2ContactRelocator::TPbk2ContactRelocationQueryPolicy aQueryPolicy,
+        TUint32 aFlags )
+    {
+    __ASSERT_DEBUG( aContact, Panic( EPanicPreCond_RelocateContactL ) );
+
+    // Adjust policy
+    if ( iRelocationPolicy == Pbk2ContactRelocator::EPbk2CopyContactToPhoneMemoryAndLock )
+        {
+        iRelocationPolicy = Pbk2ContactRelocator::EPbk2CopyContactToPhoneMemory;
+        }
+    else if ( iRelocationPolicy == Pbk2ContactRelocator::EPbk2MoveContactToPhoneMemoryAndLock )
+        {
+        iRelocationPolicy = Pbk2ContactRelocator::EPbk2MoveContactToPhoneMemory;
+        }
+
+    return PrepareToRelocateContactL( aContact, NULL, aObserver,
+        aQueryPolicy, aFlags );
+    }
+
+// --------------------------------------------------------------------------
+// CPbk2ContactRelocator::RelocateAndLockContactL
+// --------------------------------------------------------------------------
+//
+EXPORT_C TBool CPbk2ContactRelocator::RelocateAndLockContactL(
+        MVPbkStoreContact* aContact,
+        MPbk2ContactRelocatorObserver& aObserver,
+        Pbk2ContactRelocator::TPbk2ContactRelocationQueryPolicy aQueryPolicy,
+        TUint32 aFlags )
+    {
+    __ASSERT_DEBUG( aContact, Panic( EPanicPreCond_RelocateAndLockContactL ) );
+
+    // Adjust policy
+    if ( iRelocationPolicy == Pbk2ContactRelocator::EPbk2CopyContactToPhoneMemory )
+        {
+        iRelocationPolicy = Pbk2ContactRelocator::EPbk2CopyContactToPhoneMemoryAndLock;
+        }
+    else if ( iRelocationPolicy == Pbk2ContactRelocator::EPbk2MoveContactToPhoneMemory )
+        {
+        iRelocationPolicy = Pbk2ContactRelocator::EPbk2MoveContactToPhoneMemoryAndLock;
+        }
+
+    return PrepareToRelocateContactL( aContact, NULL, aObserver,
+        aQueryPolicy, aFlags );
+    }
+
+// --------------------------------------------------------------------------
+// CPbk2ContactRelocator::RelocateContactsL
+// --------------------------------------------------------------------------
+//
+EXPORT_C TBool CPbk2ContactRelocator::RelocateContactsL(
+        CVPbkContactLinkArray* aContacts,
+        MPbk2ContactRelocatorObserver& aObserver,
+        Pbk2ContactRelocator::TPbk2ContactRelocationQueryPolicy aQueryPolicy )
+    {
+    __ASSERT_DEBUG( aContacts, Panic(EPanicPreCond_RelocateContactsL ) );
+
+    return PrepareToRelocateContactL( NULL, aContacts, aObserver,
+        aQueryPolicy, EPbk2RelocatorExistingContact );
+    }
+
+// --------------------------------------------------------------------------
+// CPbk2ContactRelocator::IsPhoneMemoryContact
+// --------------------------------------------------------------------------
+//
+EXPORT_C TBool CPbk2ContactRelocator::IsPhoneMemoryContact(
+        const MVPbkStoreContact& aContact) const
+    {
+    TBool ret = EFalse;
+
+    TVPbkContactStoreUriPtr uri =
+        aContact.ParentStore().StoreProperties().Uri();
+
+    TVPbkContactStoreUriPtr phoneMemoryUri
+        ( VPbkContactStoreUris::DefaultCntDbUri() );
+
+    if (uri.Compare( phoneMemoryUri,
+        TVPbkContactStoreUriPtr::EContactStoreUriStoreType ) == 0)
+        {
+        ret = ETrue;
+        }
+
+    return ret;
+    }
+
+// --------------------------------------------------------------------------
+// CPbk2ContactRelocator::IsPhoneMemoryInConfigurationL
+// --------------------------------------------------------------------------
+//
+EXPORT_C TBool CPbk2ContactRelocator::IsPhoneMemoryInConfigurationL() const
+    {
+    TBool ret = EFalse;
+
+    // Get current configuration
+    CPbk2StoreConfiguration& storeConfig = iAppServices->StoreConfiguration();
+
+    CVPbkContactStoreUriArray* uriArray = storeConfig.CurrentConfigurationL();
+
+    // Check is phone memory included
+    ret = uriArray->IsIncluded( VPbkContactStoreUris::DefaultCntDbUri() );
+    delete uriArray;
+
+    return ret;
+    }
+
+// --------------------------------------------------------------------------
+// CPbk2ContactRelocator::RunL
+// --------------------------------------------------------------------------
+//
+void CPbk2ContactRelocator::RunL()
+    {
+    // This methods gets called only when the relocation was cancelled or
+    // otherwise stopped at the very beginning. The observer is needed to
+    // be called back asynchronously, so the active object is set running.
+    if ( iSourceContact )
+        {
+        MVPbkStoreContact* sourceContact = iSourceContact;
+        iSourceContact = NULL;
+        iObserver->ContactRelocationFailed( iErrorCode, sourceContact );
+        }
+    else if ( iSourceContacts )
+        {
+        CVPbkContactLinkArray* sourceContacts = iSourceContacts;
+        iSourceContacts = NULL;
+        iObserver->ContactsRelocationFailed( iErrorCode, sourceContacts );
+        }
+    }
+
+// --------------------------------------------------------------------------
+// CPbk2ContactRelocator::DoCancel
+// --------------------------------------------------------------------------
+//
+void CPbk2ContactRelocator::DoCancel()
+    {
+    // Do nothing
+    }
+
+// --------------------------------------------------------------------------
+// CPbk2ContactRelocator::RunError
+// --------------------------------------------------------------------------
+//
+TInt CPbk2ContactRelocator::RunError( TInt /*aError*/ )
+    {
+    // No leaving code in RunL
+    return KErrNone;
+    }
+
+// --------------------------------------------------------------------------
+// CPbk2ContactRelocator::StoreReady
+// Phone memory store was succesfully opened.
+// --------------------------------------------------------------------------
+//
+void CPbk2ContactRelocator::StoreReady
+        ( MVPbkContactStore& /*aContactStore*/ )
+    {
+    iTargetStoreOpen = ETrue;
+    // Safe to ignore error
+    TRAP_IGNORE( DoRelocateContactL() );
+    }
+
+// --------------------------------------------------------------------------
+// CPbk2ContactRelocator::StoreUnavailable
+// --------------------------------------------------------------------------
+//
+void CPbk2ContactRelocator::StoreUnavailable
+        ( MVPbkContactStore& /*aContactStore*/, TInt aReason )
+    {
+    // Problem in opening phone memory store
+    iObserver->ContactRelocationFailed( aReason, iSourceContact );
+    iSourceContact = NULL; // ownership was given away
+    }
+
+// --------------------------------------------------------------------------
+// CPbk2ContactRelocator::HandleStoreEventL
+// --------------------------------------------------------------------------
+//
+void CPbk2ContactRelocator::HandleStoreEventL
+        ( MVPbkContactStore& /*aContactStore*/,
+        TVPbkContactStoreEvent /*aStoreEvent*/ )
+    {
+    // Do nothing
+    }
+
+// --------------------------------------------------------------------------
+// CPbk2ContactRelocator::FieldAddedToContact
+// --------------------------------------------------------------------------
+//
+void CPbk2ContactRelocator::FieldAddedToContact
+        ( MVPbkContactOperationBase& /*aOperation*/ )
+    {
+    // Do nothing
+    }
+
+// --------------------------------------------------------------------------
+// CPbk2ContactRelocator::FieldAddingFailed
+// --------------------------------------------------------------------------
+//
+void CPbk2ContactRelocator::FieldAddingFailed
+        ( MVPbkContactOperationBase& /*aOperation*/, TInt /*aError*/ )
+    {
+    // Do nothing
+    }
+
+// --------------------------------------------------------------------------
+// CPbk2ContactRelocator::ContactsSaved
+// Contact was succesfully saved to phone memory
+// --------------------------------------------------------------------------
+//
+void CPbk2ContactRelocator::ContactsSaved
+        ( MVPbkContactOperationBase& /*aOperation*/,
+        MVPbkContactLinkArray* aResults )
+    {
+    // There should be only one link in the results array
+    __ASSERT_DEBUG( aResults && aResults->Count() == KOneContact,
+        Panic( EPanicPreCond_ContactsSaved ) );
+
+    TRAPD( err,
+        {
+        CleanupDeletePushL( aResults );
+
+        // Next, retrieve the saved contact
+        RetrieveSavedContactL( aResults->At( KFirstElement ) );
+        CleanupStack::PopAndDestroy(); // aResults
+        });
+
+    if ( err != KErrNone )
+        {
+        iObserver->ContactRelocationFailed( err, iSourceContact );
+        iSourceContact = NULL; // ownership was given away
+        }
+
+    }
+
+// --------------------------------------------------------------------------
+// CPbk2ContactRelocator::ContactsSavingFailed
+// --------------------------------------------------------------------------
+//
+void CPbk2ContactRelocator::ContactsSavingFailed
+        ( MVPbkContactOperationBase& /*aOperation*/, TInt aError )
+    {
+    // Contact was not succesfully saved to phone memory
+    iObserver->ContactRelocationFailed( aError, iSourceContact );
+    iSourceContact = NULL; // ownership was given away
+
+    // Move to next request, if any. Safe to ignore error.
+    TRAP_IGNORE( DoRelocateContactL() );
+    }
+
+// --------------------------------------------------------------------------
+// CPbk2ContactRelocator::VPbkSingleContactOperationComplete
+// Contact was succesfully retrieved from a link.
+// --------------------------------------------------------------------------
+//
+void CPbk2ContactRelocator::VPbkSingleContactOperationComplete
+        ( MVPbkContactOperationBase& aOperation,
+        MVPbkStoreContact* aContact )
+    {
+    if ( &aOperation == iSavedContactsRetriever )
+        {
+        // Destroy the last relocated contact
+        delete iRelocatedContact;
+        iRelocatedContact = NULL;
+        // Assign a new relocated contact
+        iRelocatedContact = aContact;
+        if ( ( iActivePolicy == Pbk2ContactRelocator::EPbk2CopyContactToPhoneMemoryAndLock ) ||
+            ( iActivePolicy == Pbk2ContactRelocator::EPbk2MoveContactToPhoneMemoryAndLock ) )
+            {
+            // Lock the contact
+            TRAPD( err, iRelocatedContact->LockL( *this ) );
+            if ( err != KErrNone )
+                {
+                iObserver->ContactRelocationFailed( err, iSourceContact );
+                iSourceContact = NULL; // ownership was given away
+
+                // Move to next request, if any. Safe to ignore error.
+                TRAP_IGNORE( DoRelocateContactL() );
+                }
+            }
+        else if ( iActivePolicy == Pbk2ContactRelocator::EPbk2MoveContactToPhoneMemory )
+            {
+            DeleteSourceContact();
+            }
+        else // EPbk2CopyContactToPhoneMemory
+            {
+            DoHandleContactRelocated();
+            TRAP_IGNORE( DoRelocateContactL() );
+            FinalizeIfReady();
+            }
+        }
+    else if ( &aOperation == iContactRetriever )
+        {
+        // One contact from given link array was retrieved, now it has
+        // to be stored and then relocated
+        iSourceContact = aContact;
+        TRAP_IGNORE( DoRelocateContactL() );
+        }
+    }
+
+// --------------------------------------------------------------------------
+// CPbk2ContactRelocator::VPbkSingleContactOperationFailed
+// Contact was not succesfully retrieved from a link.
+// --------------------------------------------------------------------------
+//
+void CPbk2ContactRelocator::VPbkSingleContactOperationFailed
+        ( MVPbkContactOperationBase& /*aOperation*/, TInt aError )
+    {
+    iObserver->ContactRelocationFailed( aError, iSourceContact );
+    iSourceContact = NULL; // ownership was given away
+
+    // Move to next request, if any
+    TRAP_IGNORE( DoRelocateContactL() );
+    }
+
+// --------------------------------------------------------------------------
+// CPbk2ContactRelocator::ContactOperationCompleted
+// --------------------------------------------------------------------------
+//
+void CPbk2ContactRelocator::ContactOperationCompleted
+        ( TContactOpResult aResult )
+    {
+    if ( aResult.iOpCode == MVPbkContactObserver::EContactLock )
+        {
+        if ( iActivePolicy == Pbk2ContactRelocator::EPbk2MoveContactToPhoneMemoryAndLock )
+            {
+            // One step to -> delete the original contact
+            DeleteSourceContact();
+            }
+        else
+            {
+            // Relocation is done with current contact
+            DoHandleContactRelocated();
+            // Continue if there are still contacts to relocate
+            TRAP_IGNORE( DoRelocateContactL() );
+            FinalizeIfReady();
+            }
+        }
+    else if ( aResult.iOpCode == MVPbkContactObserver::EContactDelete )
+        {
+        // The original contact was succesfully deleted.
+        // Notify has already been called, so move to next request, if any.
+        // In practise:
+        DoHandleContactRelocated();
+        TRAP_IGNORE( DoRelocateContactL() );
+        FinalizeIfReady();
+        }
+    }
+
+// --------------------------------------------------------------------------
+// CPbk2ContactRelocator::ContactOperationFailed
+// --------------------------------------------------------------------------
+//
+void CPbk2ContactRelocator::ContactOperationFailed
+        ( TContactOp /*aOpCode*/, TInt aErrorCode,
+        TBool /*aErrorNotified*/ )
+    {
+    // Request of the deletion of the original contact
+    // was not succesfully completed
+    // Give ownership of the failed contact to the observer
+    iObserver->ContactRelocationFailed( aErrorCode, iSourceContact );
+    iSourceContact = NULL;
+
+    // Move to next request, if any
+    TRAP_IGNORE( DoRelocateContactL() );
+    }
+
+// --------------------------------------------------------------------------
+// CPbk2ContactRelocator::ReadRelocationPolicyL
+// --------------------------------------------------------------------------
+//
+Pbk2ContactRelocator::TPbk2ContactRelocationPolicy
+        CPbk2ContactRelocator::ReadRelocationPolicyL()
+    {
+    // Default to copy option
+    Pbk2ContactRelocator::TPbk2ContactRelocationPolicy ret = Pbk2ContactRelocator::EPbk2CopyContactToPhoneMemory;
+    TInt result = 0;
+
+    // Get real setting from central repository
+    CRepository* repository = CRepository::NewL
+        ( TUid::Uid( KCRUidPhonebookInternalConfig ) );
+    CleanupStack::PushL( repository );
+    TInt err = repository->Get( KPhonebookContactRelocationPolicy, result );
+    if ( err == KErrNone )
+        {
+        ret  = Pbk2ContactRelocator::TPbk2ContactRelocationPolicy( result );
+        }
+
+    CleanupStack::PopAndDestroy( repository );
+    return ret;
+    }
+
+// --------------------------------------------------------------------------
+// CPbk2ContactRelocator::OpenTargetStoreL
+// --------------------------------------------------------------------------
+//
+void CPbk2ContactRelocator::OpenTargetStoreL()
+    {
+    if ( !iTargetStore )
+        {
+        const TVPbkContactStoreUriPtr phoneMemoryUri =
+            VPbkContactStoreUris::DefaultCntDbUri();
+        CVPbkContactManager& contactManager =
+            iAppServices->ContactManager();
+        contactManager.LoadContactStoreL( phoneMemoryUri );
+
+        MVPbkContactStoreList& storeList = contactManager.ContactStoresL();
+
+        iTargetStore = storeList.Find( phoneMemoryUri );
+        User::LeaveIfNull( iTargetStore );
+        iTargetStore->OpenL( *this );
+        }
+    }
+
+// --------------------------------------------------------------------------
+// CPbk2ContactRelocator::DoRelocateContactL
+// --------------------------------------------------------------------------
+//
+void CPbk2ContactRelocator::DoRelocateContactL()
+    {
+    // No previous multirelocate request exists,
+    // cleanup the previous request
+    if ( iSourceContacts && iSourceContacts->Count() < KOneContact )
+        {
+        // All contacts were sent to relocation, its important
+        // to clean the array and set it NULL
+        delete iSourceContacts;
+        iSourceContacts = NULL;
+        }
+
+    if ( iSourceContact )
+        {
+        // Start the copy operation
+        CopyContactL( *iSourceContact );
+        }
+    else if ( iSourceContacts )
+        {
+        // Since we can not use batch copy operation (it does not give
+        // copied contact links back) we have to retrieve all the contacts
+        // and relocate them one by one
+        if ( iSourceContacts->Count() >= KOneContact )
+            {
+            // Take the first contact link of the array
+            MVPbkContactLink* contactLink =
+                iSourceContacts->At( KFirstElement ).CloneLC();
+            // Then remove it from the array
+            iSourceContacts->Delete( KFirstElement );
+
+            // Then retrieve it
+            delete iContactRetriever;
+            iContactRetriever = NULL;
+            iContactRetriever =
+                iAppServices->ContactManager().
+                    RetrieveContactL( *contactLink, *this );
+            CleanupStack::PopAndDestroy(); // contactLink
+            }
+        }
+    }
+
+// --------------------------------------------------------------------------
+// CPbk2ContactRelocator::InitCopyPolicyL
+// --------------------------------------------------------------------------
+//
+inline void CPbk2ContactRelocator::InitCopyPolicyL()
+    {
+    if (!iCopyPolicy)
+        {
+        // There is no copy policy manager if we are in this method
+        // so creating a new one is always ok
+        delete iCopyPolicyManager;
+        iCopyPolicyManager = NULL;
+        iCopyPolicyManager = CVPbkContactCopyPolicyManager::NewL();
+        iCopyPolicy = iCopyPolicyManager->GetPolicyL
+            ( iAppServices->ContactManager(),
+            VPbkContactStoreUris::DefaultCntDbUri());
+        }
+    }
+
+// --------------------------------------------------------------------------
+// CPbk2ContactRelocator::DoHandleContactRelocated
+// --------------------------------------------------------------------------
+//
+void CPbk2ContactRelocator::DoHandleContactRelocated()
+    {
+    if ( iRelocatedContact )
+        {
+        MVPbkStoreContact* relocatedContact = iRelocatedContact;
+        iRelocatedContact = NULL;
+        // Give ownership of the relocated contact to client.
+        TRAPD( res, iObserver->ContactRelocatedL( relocatedContact ) );
+        if ( res != KErrNone )
+            {
+            MVPbkStoreContact* sourceContact = iSourceContact;
+            iSourceContact = NULL;
+            // Give source contact as documented in observer. Client
+            // takes the ownership
+            iObserver->ContactRelocationFailed( res, sourceContact );
+            }
+
+        delete iSourceContact;
+        iSourceContact = NULL;
+        }
+    }
+
+// --------------------------------------------------------------------------
+// CPbk2ContactRelocator::DeleteSourceContact
+// --------------------------------------------------------------------------
+//
+void CPbk2ContactRelocator::DeleteSourceContact()
+    {
+    // Source contact is deleted only if policy is MOVE
+    __ASSERT_DEBUG( iActivePolicy == Pbk2ContactRelocator::EPbk2MoveContactToPhoneMemory ||
+        iActivePolicy == Pbk2ContactRelocator::EPbk2MoveContactToPhoneMemoryAndLock,
+        Panic( EPanicPreCond_DeleteSourceContact ) );
+
+    // Delete original contact
+    if ( iSourceContact )
+        {
+        TRAPD( err, iSourceContact->DeleteL( *this ) );
+        if ( err != KErrNone )
+            {
+            MVPbkStoreContact* sourceContact = iSourceContact;
+            iSourceContact = NULL;
+            // Give source contact as documented in observer. Client
+            // takes the ownership
+            iObserver->ContactRelocationFailed( err, sourceContact );
+            if ( !iSourceContacts )
+                {
+                // If no more contacts to relocate then complete the relocation
+                iObserver->RelocationProcessComplete();
+                }
+            }
+        }
+    }
+
+// --------------------------------------------------------------------------
+// CPbk2ContactRelocator::AskConfirmationL
+// --------------------------------------------------------------------------
+//
+TBool CPbk2ContactRelocator::AskConfirmationL(
+        MVPbkStoreContact* aContact,
+        CVPbkContactLinkArray* aContacts,
+        TPbk2RelocationQueryType aRelocationQueryType )
+    {
+    TBool ret = ETrue;
+
+    HBufC* prompt = NULL;
+    HBufC* nameBuffer = NULL;
+    const TDesC* storeName = 
+        StoreName( aContact,
+            iAppServices->StoreProperties() );
+
+    if ( aContact )
+        {
+        nameBuffer = 
+                iAppServices->NameFormatter().
+                    GetContactTitleL( aContact->Fields(), KDefaultTitleFormat );
+
+        CleanupStack::PushL( nameBuffer );    
+        }   
+                    
+    switch( aRelocationQueryType )
+        {
+        case EPbk2NoRelocationQuery:
+        //don't show the following queries anymore
+        case EPbk2CopyOneToStoreQuery:
+        case EPbk2MoveOneToStoreQuery:
+        case EPbk2CopyOneToPhoneQuery:
+        case EPbk2MoveOneToPhoneQuery:
+        case EPbk2CopyManyToStoreQuery:
+        case EPbk2MoveManyToStoreQuery:
+            {
+            // Do nothing
+            }
+            break;
+        default:
+            {
+            __ASSERT_DEBUG( EFalse,
+                Panic( EPanicLogic_AskConfirmationL ) );
+            break;
+            }            
+        }
+    
+    if ( prompt )
+        {
+        CleanupStack::PushL( prompt );
+        delete iQueryDialog;
+        iQueryDialog = NULL;
+        iQueryDialog = CAknQueryDialog::NewL();
+        iQueryDialog->SetPromptL( *prompt );
+
+        CleanupStack::PopAndDestroy( prompt );
+
+        ret = iQueryDialog->ExecuteLD( R_PBK2_COMMONUI_CONFIRMATION_QUERY );
+        iQueryDialog = NULL;
+        }
+
+    if ( aContact )
+        {
+        CleanupStack::PopAndDestroy(); // nameBuffer    
+        }
+    return ret;    
+    }
+
+// --------------------------------------------------------------------------
+// CPbk2ContactRelocator::RetrieveSavedContactL
+// --------------------------------------------------------------------------
+//
+void CPbk2ContactRelocator::RetrieveSavedContactL
+        ( const MVPbkContactLink& aLink )
+    {
+    delete iSavedContactsRetriever;
+    iSavedContactsRetriever = NULL;
+    iSavedContactsRetriever =
+        iAppServices->ContactManager().
+            RetrieveContactL( aLink, *this );
+    }
+
+// --------------------------------------------------------------------------
+// CPbk2ContactRelocator::VerifyPolicy
+// --------------------------------------------------------------------------
+//
+inline void CPbk2ContactRelocator::VerifyPolicy(
+        MVPbkStoreContact* aContact, TUint32 aFlags )
+    {
+    // Reset policy
+    iActivePolicy = iRelocationPolicy;
+
+    // Read-only contacts can not be moved so
+    // adjust active policy if necessary. New contacts are also not moved.
+    if ( iRelocationPolicy == Pbk2ContactRelocator::EPbk2MoveContactToPhoneMemory ||
+         iRelocationPolicy == Pbk2ContactRelocator::EPbk2MoveContactToPhoneMemoryAndLock )
+        {
+        if ( aContact )
+            {
+            if (aContact->ParentStore().StoreProperties().ReadOnly() ||
+                aFlags & EPbk2RelocatorNewContact )
+                {
+                iActivePolicy = Pbk2ContactRelocator::EPbk2CopyContactToPhoneMemory;
+                if ( iRelocationPolicy == Pbk2ContactRelocator::EPbk2MoveContactToPhoneMemoryAndLock )
+                    {
+                    iActivePolicy = Pbk2ContactRelocator::EPbk2CopyContactToPhoneMemoryAndLock;
+                    }
+                }            
+            }
+        }
+    }
+
+// --------------------------------------------------------------------------
+// CPbk2ContactRelocator::PrepareToRelocateContactL
+// --------------------------------------------------------------------------
+//
+TBool CPbk2ContactRelocator::PrepareToRelocateContactL(
+        MVPbkStoreContact* aContact,
+        CVPbkContactLinkArray* aContacts,
+        MPbk2ContactRelocatorObserver& aObserver,
+        Pbk2ContactRelocator::TPbk2ContactRelocationQueryPolicy aQueryPolicy,
+        TUint32 aFlags )
+    {
+    __ASSERT_DEBUG( !iSourceContact && !iSourceContacts,
+        Panic( EPanicPreCond_PrepareToRelocateContactL ) );
+
+    iObserver = &aObserver;
+
+    TBool result = EFalse;
+
+    // If this is deleted when confirmation note returns do not access
+    // any member data.
+    TBool thisDestroyed = EFalse;
+    iDestroyedPtr = &thisDestroyed;
+    TPbk2DestructionIndicator indicator
+        ( &thisDestroyed, iDestroyedPtr );
+
+    
+    if ( aContact || aContacts )
+        {
+        VerifyPolicy( aContact, aFlags );
+        TPbk2RelocationQueryType relocationQueryType =
+            SelectRelocationQueryType( aContact, aContacts, aQueryPolicy );        
+            
+        // Take ownership
+        iSourceContact = aContact;
+        iSourceContacts = aContacts;
+        
+        result = AskConfirmationL( aContact, aContacts, relocationQueryType );
+        }
+    else
+        {
+        iErrorCode  = KErrArgument;
+        }
+            
+    if ( !thisDestroyed )
+        {
+        if ( !result )
+            {
+            iErrorCode = KErrCancel;
+            }
+
+        if ( iErrorCode != KErrNone )
+            {
+            // Inform failure asynchronously
+            TRequestStatus* status = &iStatus;
+            User::RequestComplete( status, KErrNone );
+            SetActive();
+            }
+        else
+            {
+            if ( !iTargetStoreOpen )
+                {
+                OpenTargetStoreL();
+                }
+            else
+                {
+                DoRelocateContactL();
+                }
+            }
+        }
+
+    return result;
+    }
+
+// --------------------------------------------------------------------------
+// CPbk2ContactRelocator::CopyContactL
+// --------------------------------------------------------------------------
+//
+void CPbk2ContactRelocator::CopyContactL( MVPbkStoreContact& aContact )
+    {
+    // Init copy policy
+    InitCopyPolicyL();
+
+    delete iContactCopier;
+    iContactCopier = NULL;
+    iContactCopier = iCopyPolicy->CopyContactL
+        ( aContact, *iTargetStore, *this );
+    }
+
+// --------------------------------------------------------------------------
+// CPbk2ContactRelocator::FinalizeIfReady
+// --------------------------------------------------------------------------
+//
+void CPbk2ContactRelocator::FinalizeIfReady()
+    {
+    // If there are no more contacts waiting to be relocated in this
+    // request, signal process complete
+    if ( !iSourceContacts )
+        {
+        iObserver->RelocationProcessComplete();
+        }
+    }
+
+// --------------------------------------------------------------------------
+// CPbk2ContactRelocator::SelectRelocationQueryType
+// --------------------------------------------------------------------------
+//
+CPbk2ContactRelocator::TPbk2RelocationQueryType 
+    CPbk2ContactRelocator::SelectRelocationQueryType(
+        MVPbkStoreContact* aContact,
+        CVPbkContactLinkArray* aContacts,
+        Pbk2ContactRelocator::TPbk2ContactRelocationQueryPolicy
+        aQueryPolicy )
+    {    
+    TPbk2RelocationQueryType relocationQueryType(EPbk2NoRelocationQuery);
+    TBool moveRelocation(EFalse);
+    
+    if ( Pbk2ContactRelocator::EPbk2MoveContactToPhoneMemory == iActivePolicy || 
+         Pbk2ContactRelocator::EPbk2MoveContactToPhoneMemoryAndLock == iActivePolicy )
+        {
+        moveRelocation = ETrue;
+        }
+
+    switch (aQueryPolicy)
+        {
+        case Pbk2ContactRelocator::EPbk2DisplayNoQueries:
+            {
+            relocationQueryType = EPbk2NoRelocationQuery;
+            }
+            break;
+        
+        case Pbk2ContactRelocator::EPbk2DisplayBasicQuery:
+            {
+            relocationQueryType = EPbk2CopyOneToStoreQuery;
+            if ( moveRelocation )
+                {
+                relocationQueryType = EPbk2MoveOneToStoreQuery;
+                }
+            }
+            break;
+    
+        case Pbk2ContactRelocator::EPbk2DisplayStoreDoesNotSupportQuery:
+            {
+            relocationQueryType = EPbk2CopyOneToPhoneQuery;
+            if ( moveRelocation )
+                {
+                relocationQueryType = EPbk2MoveOneToPhoneQuery;
+                }
+            }
+            break;
+
+        default:
+            {
+            __ASSERT_DEBUG( EFalse,
+                Panic( EPanicPreCond_VerifyRelocationQueryType ) );
+            break;
+            }
+        }
+        
+    if ( !aContact && aContacts && 
+         aQueryPolicy != Pbk2ContactRelocator::EPbk2DisplayNoQueries )
+        {
+        // Relocation is going to be done for many contacts
+        // and query policy is defined.
+        __ASSERT_DEBUG( aContacts->Count() >= KLinkArrayRelocationMinCount, 
+                        Panic( EPanicPreCond_VerifyRelocationQueryType ) );
+        
+        relocationQueryType = EPbk2CopyManyToStoreQuery;
+        if ( moveRelocation )
+            {
+            relocationQueryType = EPbk2MoveManyToStoreQuery;
+            }        
+        }
+    return relocationQueryType;        
+    }
+
+// End of File