messagingfw/msgcommonutils/src/contactmatcher.cpp
changeset 0 8e480a14352b
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/messagingfw/msgcommonutils/src/contactmatcher.cpp	Mon Jan 18 20:36:02 2010 +0200
@@ -0,0 +1,1239 @@
+/*
+* Copyright (c) 2005-2006 Nokia Corporation and/or its subsidiary(-ies).
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of "Eclipse Public License v1.0"
+* which accompanies this distribution, and is available
+* at the URL "http://www.eclipse.org/legal/epl-v10.html".
+*
+* Initial Contributors:
+* Nokia Corporation - initial contribution.
+*
+* Contributors:
+*
+* Description:   CContactMatcher class implementation
+*
+*/
+
+
+
+// System includes
+#include <e32base.h>
+#include <bamdesca.h>
+#include <cntitem.h>
+#include <eikenv.h>
+#include <bautils.h>
+#include <data_caging_path_literals.hrh>
+
+#include <contactmatcher.h>
+
+#include <CVPbkContactManager.h>
+#include <MVPbkContactStoreList.h>
+#include <MVPbkContactStore.h>
+#include <CVPbkContactStoreUriArray.h>
+#include <MVPbkContactLinkArray.h>
+#include <MVPbkContactLink.h>
+#include <MVPbkFieldType.h>
+#include <MVPbkStoreContact.h>
+#include <MVPbkStoreContactField.h>
+#include <MVPbkStoreContactFieldCollection.h>
+#include <MVPbkContactFieldData.h>
+#include <MVPbkContactFieldTextData.h>
+#include <MVPbkContactFieldDateTimeData.h>
+#include <MVPbkContactFieldBinaryData.h>
+#include <MVPbkContactOperationBase.h>
+#include <MVPbkContactStoreProperties.h>
+#include <TVPbkContactStoreUriPtr.h>
+#include <VPbkContactStoreUris.h>
+#include <MPbk2ContactNameFormatter.h>
+#include <CVPbkFieldTypeSelector.h>
+#include <TVPbkFieldVersitProperty.h>
+#include <CVPbkFieldTypeRefsList.h>
+
+#include <coemain.h>
+#include <CPbk2SortOrderManager.h>
+#include <Pbk2ContactNameFormatterFactory.h>
+
+#include <msgcommonutils.rsg>
+
+
+// ================= Static Constant Data ===================
+
+typedef const TDesC& (*UriFuncPtr)();
+
+// Number match store URIs in priority order.
+// When doing number matching, order of the stores in the uri array will
+// determine which stores are searched first (sequential match). We stop
+// the search when first match is found.
+static const UriFuncPtr NumberMatchStoreUris[] =
+    {
+    VPbkContactStoreUris::DefaultCntDbUri,
+    // If we don't manage to open some store, we remove it from our array
+    VPbkContactStoreUris::SimGlobalAdnUri,
+    VPbkContactStoreUris::SimGlobalSdnUri,
+    NULL,   // end marker
+    };
+
+// All store URIs except own number store
+static const UriFuncPtr AllStoreUris[] =
+    {
+    VPbkContactStoreUris::DefaultCntDbUri,
+    // If we don't manage to open some store, we remove it from our array
+    VPbkContactStoreUris::SimGlobalAdnUri,
+    VPbkContactStoreUris::SimGlobalSdnUri,
+    VPbkContactStoreUris::SimGlobalFdnUri,
+    NULL,   // end marker
+    };
+
+// Own number store URIs
+static const UriFuncPtr OwnNumberStoreUris[] =
+    {
+    VPbkContactStoreUris::SimGlobalOwnNumberUri,
+    NULL,   // end marker
+    };
+
+_LIT(KMsgCommonUtilsResourceFileName, "msgcommonutils.rsc");
+
+// ================= MEMBER FUNCTIONS =======================
+
+// ----------------------------------------------------------------------------
+// Two-phase constructor for CContactMatcher class.
+// ----------------------------------------------------------------------------
+EXPORT_C CContactMatcher* CContactMatcher::NewL(
+    RFs* aFsSession )
+    {
+    CContactMatcher* self = CContactMatcher::NewLC( aFsSession );
+    CleanupStack::Pop(self);
+    return self;
+    }
+
+// ----------------------------------------------------------------------------
+// Two-phase constructor for CContactMatcher class.
+// ----------------------------------------------------------------------------
+EXPORT_C CContactMatcher* CContactMatcher::NewLC(
+    RFs* aFsSession )
+    {
+    CContactMatcher* self = new ( ELeave ) CContactMatcher( aFsSession );
+    CleanupStack::PushL(self);
+    self->ConstructL();
+    return self;
+    }
+
+// ----------------------------------------------------------------------------
+// C++ destructor.
+// ----------------------------------------------------------------------------
+EXPORT_C CContactMatcher::~CContactMatcher()
+    {
+    FreeOldOperation();
+    CleanupNumberMatch();
+    delete iStoreUris;
+    delete iContactManager;
+    delete iSortOrderManager;
+    delete iNameFormatter;
+    iResourceFile.Close();
+
+    if ( iClientStatus )
+        {
+        User::RequestComplete( iClientStatus, KErrCancel );
+        }
+    if ( iASchedulerWait.IsStarted() )
+        {
+        iASchedulerWait.AsyncStop();
+        }
+    }
+
+// ----------------------------------------------------------------------------
+// C++ Constructor.
+// ----------------------------------------------------------------------------
+CContactMatcher::CContactMatcher( RFs* aFsSession) : iFsSession( aFsSession )
+    {
+    }
+
+// ----------------------------------------------------------------------------
+// Second phase constructor
+// ----------------------------------------------------------------------------
+void CContactMatcher::ConstructL()
+    {
+    iContactManager = CVPbkContactManager::NewL(
+        *CVPbkContactStoreUriArray::NewLC(), iFsSession );
+    CleanupStack::PopAndDestroy(); // CVPbkContactStoreUriArray
+
+    // No stores open yet
+    iStoreUris = CVPbkContactStoreUriArray::NewL();
+    }
+
+//******************* API-methods *********************************************
+
+// ----------------------------------------------------------------------------
+// Synchronous version
+// ----------------------------------------------------------------------------
+EXPORT_C void CContactMatcher::OpenStoreL(
+    const CVPbkContactStoreUriArray& aUriArray )
+    {
+    InitOperationL( EOpenStore );
+    OpenStoreCommonL( aUriArray );
+    if ( iApiMethodStatus != EFinished )
+        {
+        iApiMethodStatus = EExecuting;
+        // Wait until stores are open
+        iASchedulerWait.Start();
+        }
+    User::LeaveIfError( iError );
+    }
+
+// ----------------------------------------------------------------------------
+// Asynchronous version
+// ----------------------------------------------------------------------------
+EXPORT_C void CContactMatcher::OpenStoreL(
+    const CVPbkContactStoreUriArray& aUriArray, TRequestStatus&  aStatus )
+    {
+    InitOperationL( EOpenStore );
+    OpenStoreCommonL( aUriArray );
+    InitOperation( &aStatus );
+
+    if ( iApiMethodStatus != EFinished )
+        {
+        iApiMethodStatus = EExecuting;
+        }
+    }
+
+
+// ----------------------------------------------------------------------------
+// Common code to sync/async versions.
+// ----------------------------------------------------------------------------
+void CContactMatcher::OpenStoreCommonL(
+    const CVPbkContactStoreUriArray& aUriArray )
+    {
+    if (iStoreUris->Count())
+        {
+        // Opening more stores when some stores are already open is not
+        // supported. Support would require managing iStoreUris properly
+        // so that it contains all open stores.
+        User::Leave(KErrGeneral);
+        }
+
+    const TInt count = aUriArray.Count();
+    
+    for (TInt i = 0; i < count; ++i)
+        {
+        // Appended Uri:s to the array. If store fails to open it is removed
+        // from the array. This keeps Uri's in priority order in the array.
+        TVPbkContactStoreUriPtr uriPtr = aUriArray[i];
+        iStoreUris->AppendL( uriPtr );
+
+        iContactManager->LoadContactStoreL( uriPtr );
+        }
+    MVPbkContactStoreList& storeList = iContactManager->ContactStoresL();
+    storeList.OpenAllL( *this );
+    }
+
+// ----------------------------------------------------------------------------
+// Synchronous version
+// ----------------------------------------------------------------------------
+EXPORT_C void CContactMatcher::OpenAllStoresL()
+    {
+    OpenStoreL(AllStoreUris);
+    }
+
+// ----------------------------------------------------------------------------
+// Asynchronous version
+// ----------------------------------------------------------------------------
+EXPORT_C void CContactMatcher::OpenAllStoresL( TRequestStatus& aStatus )
+    {
+    OpenStoreL(AllStoreUris, aStatus);
+    }
+
+// ----------------------------------------------------------------------------
+// Synchronous version
+// ----------------------------------------------------------------------------
+EXPORT_C void CContactMatcher::OpenDefaultMatchStoresL()
+    {
+    OpenStoreL(NumberMatchStoreUris);
+    }
+
+// ----------------------------------------------------------------------------
+// Asynchronous version
+// ----------------------------------------------------------------------------
+EXPORT_C void CContactMatcher::OpenDefaultMatchStoresL( TRequestStatus& aStatus )
+    {
+    OpenStoreL(NumberMatchStoreUris, aStatus);
+    }
+
+// ----------------------------------------------------------------------------
+// Open OwnNumber stores.
+// Synchronous version
+// ----------------------------------------------------------------------------
+EXPORT_C void CContactMatcher::OpenOwnNumberStoresL()
+    {
+    OpenStoreL(OwnNumberStoreUris);
+    }
+
+// ----------------------------------------------------------------------------
+// Open OwnNumber stores.
+// Asynchronous version
+// ----------------------------------------------------------------------------
+EXPORT_C void CContactMatcher::OpenOwnNumberStoresL( TRequestStatus& aStatus )
+    {
+    OpenStoreL(OwnNumberStoreUris, aStatus);
+    }
+
+// ----------------------------------------------------------------------------
+// Close all open stores.
+// ----------------------------------------------------------------------------
+EXPORT_C void CContactMatcher::CloseStoresL()
+    {
+    // Closing stores does not work. MatchDataL() finds contacts from
+    // closed stores.
+
+    InitOperationL( ECloseStores );
+
+    iApiMethodStatus = EExecuting;
+    TRAPD( err, iContactManager->ContactStoresL().CloseAll( *this ) );
+    iApiMethodStatus = EFinished;
+    if ( err == KErrNone)
+        {
+        delete iStoreUris; iStoreUris = NULL;
+        iStoreUris = CVPbkContactStoreUriArray::NewL();        
+        }
+    else
+        {
+        User::Leave(err);
+        }
+    }
+
+// ----------------------------------------------------------------------------
+// Synchronous version
+// ----------------------------------------------------------------------------
+EXPORT_C void CContactMatcher::MatchPhoneNumberL(
+    const TDesC& aData, TInt aDigits,
+    CVPbkPhoneNumberMatchStrategy::TVPbkPhoneNumberMatchFlags aFlags,
+    CVPbkContactLinkArray& aLinkArray )
+    {
+    InitOperationL( EMatchPhoneNumber );
+    iResultContactLinkArray = &aLinkArray;
+
+    // Start asynchronous matching and wait until results are ready
+    MatchPhoneNumberCommonL( aData, aDigits, aFlags );
+    if ( iApiMethodStatus != EFinished )
+        {
+        iApiMethodStatus = EExecuting;
+        iASchedulerWait.Start();
+        }
+    User::LeaveIfError( iError );
+    }
+
+
+// ----------------------------------------------------------------------------
+// Asynchronous version
+// ----------------------------------------------------------------------------
+EXPORT_C void CContactMatcher::MatchPhoneNumberL(
+    const TDesC& aData, TInt aDigits,
+    CVPbkPhoneNumberMatchStrategy::TVPbkPhoneNumberMatchFlags aFlags,
+    CVPbkContactLinkArray& aLinkArray, TRequestStatus& aStatus )
+    {
+    InitOperationL( EMatchPhoneNumber );
+    iResultContactLinkArray = &aLinkArray;
+    // Start asynchronous matching
+    MatchPhoneNumberCommonL( aData, aDigits, aFlags );
+    InitOperation( &aStatus );
+    if ( iApiMethodStatus != EFinished )
+        {
+        iApiMethodStatus = EExecuting;
+        }
+    }
+
+// ----------------------------------------------------------------------------
+// Common code for sync and async versions
+// ----------------------------------------------------------------------------
+void CContactMatcher::MatchPhoneNumberCommonL(
+    const TDesC& aData, TInt aDigits,
+    CVPbkPhoneNumberMatchStrategy::TVPbkPhoneNumberMatchFlags aFlags )
+    {
+    // Delete resources allocated for previous match
+    CleanupNumberMatch();
+
+    // iStoreUris is filled when stores are opened
+
+    iStratConfig = new (ELeave) CVPbkPhoneNumberMatchStrategy::TConfig(
+        aDigits,
+        *iStoreUris,
+        CVPbkPhoneNumberMatchStrategy::EVPbkSequentialMatch,
+        aFlags);
+    iMatchStrategy = CVPbkPhoneNumberMatchStrategy::NewL(
+                *iStratConfig,
+                *iContactManager,
+                *this);
+    // Start asynchronous matching
+    iMatchStrategy->MatchL( aData );
+    }
+
+
+// ----------------------------------------------------------------------------
+// Find from a store succeeded
+// ----------------------------------------------------------------------------
+void CContactMatcher::FindFromStoreSucceededL( MVPbkContactStore& /*aStore*/,
+        MVPbkContactLinkArray* aResultsFromStore )
+    {
+    __ASSERT_DEBUG( aResultsFromStore, ContactMatcherPanics::Panic(
+        ContactMatcherPanics::EPanNullPointer ));
+
+    // Take the ownership of the result immediately
+    CleanupDeletePushL( aResultsFromStore );
+
+    CopyFindResultsL( aResultsFromStore );
+
+    CleanupStack::PopAndDestroy(); // aResultsFromStore
+    }
+
+// ----------------------------------------------------------------------------
+// Copy the found results for a store into array
+// ----------------------------------------------------------------------------
+void CContactMatcher::CopyFindResultsL( MVPbkContactLinkArray*
+    aResults )
+    {
+    const TInt count = aResults->Count();
+    if ( iResultContactLinkArray )
+        {
+        // Copy links to the member array
+        for ( TInt i = 0; i < count; ++i )
+            {
+            iResultContactLinkArray->AppendL( aResults->At( i ).CloneLC() );
+            CleanupStack::Pop(); // cloned link
+            }
+        }
+    else
+        {
+        iResultContactLinkCnt += count;
+        }
+    }
+
+
+// ----------------------------------------------------------------------------
+// Find failed
+// ----------------------------------------------------------------------------
+void CContactMatcher::FindFromStoreFailed( MVPbkContactStore& /*aStore*/, TInt /*aError*/ )
+    {
+    //no operation, search to continue from the other stores
+    }
+
+
+// ----------------------------------------------------------------------------
+// Find complete
+// ----------------------------------------------------------------------------
+void CContactMatcher::FindFromStoresOperationComplete()
+    {
+    if (!iResultContactLinkArray)
+        {
+        // Links were not copied. Result is whether any links found or not.
+        OperationComplete( iResultContactLinkCnt ? KErrNone:KErrNotFound );
+        }
+    else
+        {
+        OperationComplete();
+        iResultContactLinkArray = NULL;
+        }
+    }
+
+// ----------------------------------------------------------------------------
+// Return global list of field types.
+// ----------------------------------------------------------------------------
+EXPORT_C const MVPbkFieldTypeList& CContactMatcher::FieldTypes() const
+    {
+    return iContactManager->FieldTypes();
+    }
+
+// ----------------------------------------------------------------------------
+// Synchronous version
+// ----------------------------------------------------------------------------
+EXPORT_C void CContactMatcher::GetStoreContactL(
+    const MVPbkContactLink& aLink, MVPbkStoreContact** aStoreContact )
+    {
+    InitOperationL( EGetStoreContact );
+    iResultStoreContact = aStoreContact;
+
+    // Start asynchronous operation and wait until results are ready
+    FreeOldOperation();
+    iOperation = iContactManager->RetrieveContactL( aLink, *this );
+    if ( iApiMethodStatus != EFinished )
+        {
+        iApiMethodStatus = EExecuting;
+        iASchedulerWait.Start();
+        }
+    User::LeaveIfError( iError );
+    }
+
+// ----------------------------------------------------------------------------
+// Asynchronous version
+// ----------------------------------------------------------------------------
+EXPORT_C void CContactMatcher::GetStoreContactL(
+    const MVPbkContactLink& aLink, MVPbkStoreContact** aStoreContact,
+    TRequestStatus& aStatus )
+    {
+    InitOperationL( EGetStoreContact );
+    iResultStoreContact = aStoreContact;
+    // Start asynchronous operation
+    FreeOldOperation();
+    iOperation = iContactManager->RetrieveContactL( aLink, *this );
+    InitOperation( &aStatus );
+    if ( iApiMethodStatus != EFinished )
+        {
+        iApiMethodStatus = EExecuting;
+        }
+    }
+
+// ----------------------------------------------------------------------------
+// Synchronous version
+// ----------------------------------------------------------------------------
+EXPORT_C void CContactMatcher::IsOwnNumberL( const TDesC& aNumber, TBool& aResult )
+    {
+    InitOperationL( EMatchPhoneNumber );
+
+     // Not interested in links, only whether found or not
+    iResultContactLinkArray = NULL;
+    iResultContactLinkCnt = 0;
+
+    // Start asynchronous matching and wait until results are ready
+    MatchPhoneNumberCommonL( aNumber, aNumber.Length(),
+        CVPbkPhoneNumberMatchStrategy::EVPbkStopOnFirstMatchFlag );
+    if ( iApiMethodStatus != EFinished )
+        {
+        iApiMethodStatus = EExecuting;
+        iASchedulerWait.Start();
+        }
+    User::LeaveIfError( iError );
+
+    aResult = iResultContactLinkCnt > 0;
+    }
+
+// ----------------------------------------------------------------------------
+// Asynchronous version
+// ----------------------------------------------------------------------------
+EXPORT_C void CContactMatcher::IsOwnNumberL( const TDesC& aNumber,
+    TRequestStatus& aStatus )
+    {
+    InitOperationL( EMatchPhoneNumber );
+
+     // Not interested in links, only whether found or not
+    iResultContactLinkArray = NULL;
+    iResultContactLinkCnt = 0;
+
+    // Start asynchronous matching
+    MatchPhoneNumberCommonL( aNumber, aNumber.Length(),
+        CVPbkPhoneNumberMatchStrategy::EVPbkStopOnFirstMatchFlag );
+    InitOperation( &aStatus );
+    if ( iApiMethodStatus != EFinished )
+        {
+        iApiMethodStatus = EExecuting;
+        }
+    }
+
+// ----------------------------------------------------------------------------
+// Cancel asynchronous operation
+// ----------------------------------------------------------------------------
+EXPORT_C void CContactMatcher::CancelOperation()
+    {
+    if (iApiMethodStatus != EExecuting)
+        {
+        return;
+        }
+
+    __ASSERT_DEBUG(!iSync, ContactMatcherPanics::Panic(
+        ContactMatcherPanics::EPanInvalidOp));
+
+    switch(iApiMethod)
+        {
+        case EMatchData:
+        case EGetStoreContact:
+            FreeOldOperation(); // deleting the operation cancels it
+            break;
+        case EMatchPhoneNumber:
+            CleanupNumberMatch();
+            break;
+        default:
+            ;
+        }
+
+    User::RequestComplete( iClientStatus, KErrCancel );
+
+    iApiMethod = ENoMethod;
+    iApiMethodStatus = EFinished;
+    }
+
+// ----------------------------------------------------------------------------
+// GetFieldData, for EVPbkFieldStorageTypeText
+// ----------------------------------------------------------------------------
+EXPORT_C TPtrC CContactMatcher::GetFieldDataTextL(
+    const MVPbkStoreContact& aContact,
+    const MVPbkFieldType& aFType ) const
+    {
+    TPtrC ret(KNullDesC);
+    const MVPbkStoreContactField* field = FindField( aContact, aFType);
+    if (field)
+        {
+        const MVPbkContactFieldData& fdata = field->FieldData();
+        if (fdata.DataType() == EVPbkFieldStorageTypeText)
+            {
+            const MVPbkContactFieldTextData& fdata2 =
+                MVPbkContactFieldTextData::Cast(fdata);
+            ret.Set( fdata2.Text() );
+            }
+        else
+            {
+            User::Leave( KErrArgument );
+            }
+        }
+    return ret;
+    }
+
+// ----------------------------------------------------------------------------
+// GetFieldData, for EVPbkFieldStorageTypeDateTime
+// ----------------------------------------------------------------------------
+EXPORT_C TTime CContactMatcher::GetFieldDataDateTimeL(
+    const MVPbkStoreContact& aContact,
+    const MVPbkFieldType& aFType ) const
+    {
+    //               YYYYMMDD:HHMMSS.MMMMMM
+    _LIT(KNullTime, "11110000:010101.00000");
+    TTime ret(KNullTime);
+    const MVPbkStoreContactField* field = FindField( aContact, aFType);
+    if (field)
+        {
+        const MVPbkContactFieldData& fdata = field->FieldData();
+        if (fdata.DataType() == EVPbkFieldStorageTypeDateTime)
+            {
+            const MVPbkContactFieldDateTimeData& fdata2 =
+                MVPbkContactFieldDateTimeData::Cast( fdata );
+            ret = fdata2.DateTime();
+            }
+        else
+            {
+            User::Leave( KErrArgument );
+            }
+        }
+    return ret;
+    }
+
+// ----------------------------------------------------------------------------
+// GetFieldData, for EVPbkFieldStorageTypeBinary
+// ----------------------------------------------------------------------------
+EXPORT_C TPtrC8 CContactMatcher::GetFieldDataBinaryL(
+    const MVPbkStoreContact& aContact,
+    const MVPbkFieldType& aFType ) const
+    {
+    TPtrC8 ret(KNullDesC8);
+    const MVPbkStoreContactField* field = FindField( aContact, aFType);
+    if (field)
+        {
+        const MVPbkContactFieldData& fdata = field->FieldData();
+        if (fdata.DataType() == EVPbkFieldStorageTypeBinary)
+            {
+            const MVPbkContactFieldBinaryData& fdata2 =
+                MVPbkContactFieldBinaryData::Cast( fdata );
+            ret.Set( fdata2.BinaryData() );
+            }
+        else
+            {
+            User::Leave( KErrArgument );
+            }
+        }
+    return ret;
+    }
+
+
+//******************************** Private Methods ***************************
+
+// ----------------------------------------------------------------------------
+// Finds a field of given type from contact.
+// Returns pointer to field or NULL if not found.
+// ----------------------------------------------------------------------------
+ const MVPbkStoreContactField* CContactMatcher::FindField(
+    const MVPbkStoreContact& aContact,
+    const MVPbkFieldType& aFType ) const
+    {
+    const MVPbkStoreContactFieldCollection& coll = aContact.Fields();
+    TInt n = coll.FieldCount();
+
+    const MVPbkStoreContactField* field = NULL;
+    TBool bFound = EFalse;
+    for(TInt i=0; i < n && !bFound; ++i)
+        {
+        field = &coll.FieldAt( i );
+        const MVPbkFieldType* ftype = field->MatchFieldType( 0 );
+        if ( ftype )
+            {
+            if ( ftype->IsSame( aFType ))
+                {
+                bFound = ETrue;
+                }
+            }
+        }
+    if ( !bFound )
+        {
+        field = NULL;
+        }
+    return field;
+    }
+
+// ----------------------------------------------------------------------------
+// Get URI array with stores
+// ----------------------------------------------------------------------------
+CVPbkContactStoreUriArray* CContactMatcher::GetStoreArrayLC(
+    const TDesC& (* const aFuncPtrs[])() )
+    {
+    CVPbkContactStoreUriArray* uriArray = CVPbkContactStoreUriArray::NewLC();
+
+    // Add stores
+    for(TInt i = 0; aFuncPtrs[i]; i++)
+        {
+        TVPbkContactStoreUriPtr uriPtr(aFuncPtrs[i]());
+        uriArray->AppendL(uriPtr);
+        }
+    return uriArray;
+    }
+
+// ----------------------------------------------------------------------------
+// Open stores. Synchronous version
+// ----------------------------------------------------------------------------
+void CContactMatcher::OpenStoreL(const TDesC& (* const aFuncPtrs[])())
+    {
+    CVPbkContactStoreUriArray* uriArray = GetStoreArrayLC(aFuncPtrs);
+
+    CContactMatcher::OpenStoreL(*uriArray);
+    CleanupStack::PopAndDestroy(uriArray);
+    }
+
+// ----------------------------------------------------------------------------
+// Open stores. Asynchronous version
+// ----------------------------------------------------------------------------
+void CContactMatcher::OpenStoreL(const TDesC& (* const aFuncPtrs[])(),
+    TRequestStatus&  aStatus)
+    {
+    CVPbkContactStoreUriArray* uriArray = GetStoreArrayLC(aFuncPtrs);
+
+    CContactMatcher::OpenStoreL(*uriArray, aStatus);
+    CleanupStack::PopAndDestroy(uriArray);
+    }
+
+// ----------------------------------------------------------------------------
+// Called when the opening process is complete,
+// ie. all stores have been reported either failed or successfully opened.
+// ----------------------------------------------------------------------------
+//
+void CContactMatcher::OpenComplete()
+    {
+    TInt error = KErrNone;
+    if ( iStoreUris->Count() == 0 )
+        {
+        // unable to open any of the specified stores
+        error = KErrNotSupported;
+        }
+    OperationComplete( error );
+    }
+
+// ----------------------------------------------------------------------------
+// Called when a contact store is ready to use.
+// ----------------------------------------------------------------------------
+void CContactMatcher::StoreReady( MVPbkContactStore& /*aContactStore*/ )
+    {
+    }
+
+// ----------------------------------------------------------------------------
+// Called when a contact store becomes unavailable.
+// Client may inspect the reason of the unavailability and decide whether or not
+// it will keep the store opened (ie. listen to the store events).
+// @param aContactStore The store that became unavailable.
+// @param aReason The reason why the store is unavailable.
+//                This is one of the system wide error codes.
+// ----------------------------------------------------------------------------
+void CContactMatcher::StoreUnavailable( MVPbkContactStore& aContactStore,
+    TInt /*aReason*/ )
+    {
+    // Remove contact store from uri list
+    iStoreUris->Remove( aContactStore.StoreProperties().Uri() );
+    }
+
+// ----------------------------------------------------------------------------
+// Called when changes occur in the contact store.
+// @see TVPbkContactStoreEvent
+//
+// @param aStoreEvent Event that has occured.
+// ----------------------------------------------------------------------------
+void CContactMatcher::HandleStoreEventL(
+        MVPbkContactStore& /*aContactStore*/,
+        TVPbkContactStoreEvent aStoreEvent)
+    {
+    // Contact and group events can be ignored, but we pass backup events for the observer.
+    switch ( aStoreEvent.iEventType )
+        {
+        case TVPbkContactStoreEvent::EStoreBackupBeginning:
+        case TVPbkContactStoreEvent::EStoreRestoreBeginning:
+            {
+            iBackup = ETrue;
+            break;
+            }
+        case TVPbkContactStoreEvent::EStoreBackupRestoreCompleted:
+            {
+            iBackup = EFalse;
+            break;
+            }
+        default:
+            break;
+        }
+    }
+
+
+// ----------------------------------------------------------------------------
+// Called when find is complete. Callee takes ownership of the results.
+// In case of an error during find, the aResults may contain only
+// partial results of the find.
+//
+// @param aResults Array of contact links that matched the find.
+// ----------------------------------------------------------------------------
+void CContactMatcher::FindCompleteL( MVPbkContactLinkArray* aResults )
+    {
+    __ASSERT_DEBUG( aResults, ContactMatcherPanics::Panic(
+        ContactMatcherPanics::EPanNullPointer ));
+
+    // Take the ownership of the result immediately
+    CleanupDeletePushL( aResults );
+
+    CopyFindResultsL( aResults );
+
+    CleanupStack::PopAndDestroy(); // aResults
+
+    if (!iResultContactLinkArray)
+        {
+        // No need to copy links. Only interested whether found or not
+        OperationComplete( iResultContactLinkCnt ? KErrNone:KErrNotFound );
+        }
+    else
+        {
+        OperationComplete();
+        iResultContactLinkArray = NULL;
+        }
+    }
+
+// ----------------------------------------------------------------------------
+// Called in case the find fails for some reason.
+//
+// @param aError One of the system wide error codes.
+// ----------------------------------------------------------------------------
+void CContactMatcher::FindFailed( TInt aError )
+    {
+    OperationFailed( aError );
+    iResultContactLinkArray = NULL;
+    }
+
+// ----------------------------------------------------------------------------
+// Free old VPbk-operation.
+// ----------------------------------------------------------------------------
+void CContactMatcher::FreeOldOperation()
+    {
+    delete iOperation;
+    iOperation = NULL;
+    }
+
+// ----------------------------------------------------------------------------
+// Called when operation is completed.
+// ----------------------------------------------------------------------------
+void CContactMatcher::VPbkSingleContactOperationComplete(
+        MVPbkContactOperationBase& /*aOperation*/, MVPbkStoreContact* aContact)
+    {
+    *iResultStoreContact = aContact;
+    iResultStoreContact  = NULL;
+    OperationComplete();
+    }
+
+// ----------------------------------------------------------------------------
+// Called if the operation fails.
+// ----------------------------------------------------------------------------
+void CContactMatcher::VPbkSingleContactOperationFailed(
+    MVPbkContactOperationBase& /*aOperation*/, TInt aError)
+    {
+    OperationFailed( aError );
+    }
+
+// ----------------------------------------------------------------------------
+// Set member variables for sync operation
+// ----------------------------------------------------------------------------
+void CContactMatcher::InitOperationL( TMethodId aMethod )
+    {
+    if ( iBackup )
+        {
+        User::Leave( KErrAccessDenied );
+        }
+
+    // Check whether operation is in progress
+    if ( iApiMethodStatus == EExecuting )
+        {
+        User::Leave( KErrInUse );
+        }
+
+    iSync  = ETrue;
+    iError = KErrNone;
+    iApiMethod = aMethod;
+    iApiMethodStatus = EIdle;
+    }
+
+// ----------------------------------------------------------------------------
+// Set member variables for async operation
+// ----------------------------------------------------------------------------
+void CContactMatcher::InitOperationL( TMethodId aMethod, TRequestStatus* aStatus )
+    {
+    InitOperationL( aMethod );
+
+    iSync  = EFalse;
+    iClientStatus  = aStatus;
+    *iClientStatus = KRequestPending;
+    }
+    
+// ----------------------------------------------------------------------------
+// Set member variables for async operation
+// ----------------------------------------------------------------------------
+void CContactMatcher::InitOperation( TRequestStatus* aStatus )
+    {
+    iSync  = EFalse;
+    iClientStatus  = aStatus;
+    *iClientStatus = KRequestPending;
+    }
+
+// ----------------------------------------------------------------------------
+// Sync/async operation finished succesfully, return results to method caller.
+// ----------------------------------------------------------------------------
+void CContactMatcher::OperationComplete( TInt aErrorCode )
+    {
+    if (iSync)
+        {
+        if ( iASchedulerWait.IsStarted() )
+            {
+            iASchedulerWait.AsyncStop();
+            }
+        }
+    else
+        {
+        if ( iClientStatus )
+            {
+            User::RequestComplete( iClientStatus, aErrorCode );
+            iClientStatus = NULL;
+            }
+        }
+    iApiMethodStatus = EFinished;
+    }
+
+// ----------------------------------------------------------------------------
+// Sync/async operation failed, return results to method caller.
+// ----------------------------------------------------------------------------
+void CContactMatcher::OperationFailed( TInt aError )
+    {
+    iError = aError;
+    OperationComplete( aError );
+    }
+
+// ----------------------------------------------------------------------------
+// Free resources allocated for number matching
+// ----------------------------------------------------------------------------
+void CContactMatcher::CleanupNumberMatch()
+{
+    delete iMatchStrategy;
+    iMatchStrategy = NULL;
+
+    delete iStratConfig;
+    iStratConfig = NULL;
+
+    // store uris are not deleted here - opened array remains valid
+    // until new set of stores is opened.
+}
+
+// ---------------------------------------------------------------------------
+// CContactMatcher::GetContactStoresL
+// ---------------------------------------------------------------------------
+EXPORT_C MVPbkContactStoreList& CContactMatcher::GetContactStoresL()
+    {
+    return iContactManager->ContactStoresL();
+    }
+
+
+// -----------------------------------------------------------------------------
+// TInt CContactMatcher::GetName
+//
+// Returns the formatted name fo the contact
+// -----------------------------------------------------------------------------
+EXPORT_C HBufC* CContactMatcher::GetNameL( MVPbkStoreContactFieldCollection&
+                                                                aFieldCollection )
+    {
+    MPbk2ContactNameFormatter& nameFormatter = ContactNameFormatterL();
+    
+    HBufC* formattedName = nameFormatter.GetContactTitleOrNullL( aFieldCollection, 
+    						                                     MPbk2ContactNameFormatter::EUseSeparator );
+    return formattedName;
+    }
+
+// -----------------------------------------------------------------------------
+// TInt CContactMatcher::ContactHasFieldOfTypeL( )
+// -----------------------------------------------------------------------------
+EXPORT_C TInt CContactMatcher::ContactHasFieldOfTypeL
+        ( TAiwAddressSelectType aAddressSelectType,  const MVPbkStoreContact& aContact )
+  {
+    TInt resId = 0;
+
+    switch ( aAddressSelectType )
+        {
+      case EAiwPhoneNumberSelect:
+          resId = R_PHONE_NUMBER_SELECTOR;
+          break;
+      case EAiwEMailSelect:
+          resId = R_EMAIL_ADDRESS_SELECTOR;
+          break;
+      case EAiwMMSSelect:
+          resId = R_MMS_ADDRESS_SELECTOR;
+          break;
+      default:
+          resId = R_PHONE_NUMBER_SELECTOR;
+          break;
+        }
+
+    MVPbkContactFieldSelector* fieldTypeSelector =
+          CreateFieldTypeSelectorLC( resId );
+
+    // Check if the specified field type is included in the contact
+    const MVPbkStoreContactFieldCollection& fields = aContact.Fields();
+  TInt fieldCount = fields.FieldCount();
+
+  TInt ret = KErrNotFound;
+  for ( TInt i = 0; i < fieldCount && ret == KErrNotFound; ++i )
+    {
+    const MVPbkBaseContactField& field = fields.FieldAt( i );
+    if ( fieldTypeSelector->IsFieldIncluded( field ) )
+      {
+      ret = i;
+      }
+    }
+
+  CleanupStack::PopAndDestroy(); // fieldTypeSelector
+
+  return ret;
+  }
+
+// -----------------------------------------------------------------------------
+// CVPbkContactManager& CContactMatcher::GetContactManager( )
+// -----------------------------------------------------------------------------
+EXPORT_C CVPbkContactManager& CContactMatcher::GetContactManager()
+    {
+    return *iContactManager;
+    }
+    
+
+// ----------------------------------------------------------------------------
+// Synchronous version
+// ----------------------------------------------------------------------------
+EXPORT_C void CContactMatcher::MatchDataL( const TDesC& aData,
+    const MVPbkFieldTypeList& aFieldTypes,
+    CVPbkContactLinkArray& aLinkArray)
+    {
+    InitOperationL( EMatchData );
+    iResultContactLinkArray = &aLinkArray;
+
+    // Start asynchronous matching and wait until results are ready
+    FreeOldOperation();
+    iOperation = iContactManager->FindL(aData, aFieldTypes, *this);
+    if ( iApiMethodStatus != EFinished )
+        {
+        iApiMethodStatus = EExecuting;
+        iASchedulerWait.Start();
+        }
+
+    User::LeaveIfError( iError );
+    RemoveSimilarEmailAddressesL( aData, aLinkArray, aFieldTypes );
+   	}
+
+// ----------------------------------------------------------------------------
+// Remove contacts that do not have exactly the correct email address
+// e.g. if cbd@test.com address is requested, the for example a contact with address abcd@test.com will be removed
+// from the result.
+// This filtering is done only in the syncronous version of MatchDataL
+// ----------------------------------------------------------------------------
+void CContactMatcher::RemoveSimilarEmailAddressesL( const TDesC& aData, CVPbkContactLinkArray& aLinkArray, const MVPbkFieldTypeList& aFieldTypes )
+    {
+    TVPbkFieldVersitProperty prop;
+    prop.SetName( EVPbkVersitNameEMAIL );
+    // do extra checks for email addresses
+    
+    const MVPbkFieldType* foundType = NULL;
+    // Continue only if at least one type is EVPbkVersitNameEMAIL
+    TInt i;
+    for ( i = 0 ; i < aFieldTypes.FieldTypeCount() ; i++ )
+        {
+        foundType = &(aFieldTypes.FieldTypeAt( i ));
+        if ( foundType->VersitProperties().Count() > 0
+            && foundType->VersitProperties()[0].Name() == prop.Name() )
+            {
+            break;
+            }
+        }
+    if ( i == aFieldTypes.FieldTypeCount() )
+    	{
+    	// no email types
+    	return;
+    	}
+    
+    const MVPbkFieldTypeList& fieldTypeList = FieldTypes();
+
+    TInt index = 0;
+	TBool isExactMatch;
+    while( index < aLinkArray.Count() )
+    	{
+	    MVPbkStoreContact* storeContact;
+	    GetStoreContactL( aLinkArray.At( index ), &storeContact );
+	    storeContact->PushL();
+	    
+	    isExactMatch = EFalse;
+        for ( TInt i = 0; i < fieldTypeList.FieldTypeCount(); i++ )
+            {
+            // find the email property
+            foundType = &(fieldTypeList.FieldTypeAt( i ));
+            if ( foundType->VersitProperties().Count() > 0
+                && foundType->VersitProperties()[0].Name() == prop.Name() )
+                {
+                TPtrC src = GetFieldDataTextL(*storeContact, *foundType );
+                if ( aData.CompareF( src ) == 0 )
+        	    	{
+        	    	isExactMatch = ETrue;
+        	    	}
+                }
+            }
+	    if ( isExactMatch )
+            {
+            // go for the next contact
+            index++;
+            }
+        else
+        	{
+            // remove the contact, because the email address does not match the one queried. 
+            // the next one will take plce of this contact in the list (=do not increase index)
+            aLinkArray.Delete( index ); 
+        	}
+	    CleanupStack::PopAndDestroy( storeContact );
+    	}
+    }
+
+// ----------------------------------------------------------------------------
+// Asynchronous version
+// ----------------------------------------------------------------------------
+EXPORT_C void CContactMatcher::MatchDataL( const TDesC& aData,
+    const MVPbkFieldTypeList& aFieldTypes,
+    CVPbkContactLinkArray& aLinkArray,
+    TRequestStatus& aStatus)
+    {
+    InitOperationL( EMatchData );
+    iResultContactLinkArray = &aLinkArray;
+
+    // Start asynchronous matching
+    FreeOldOperation();
+    iOperation = iContactManager->FindL(aData, aFieldTypes, *this);
+    InitOperation( &aStatus );
+    if ( iApiMethodStatus != EFinished )
+        {
+        iApiMethodStatus = EExecuting;
+        }
+    }
+// ----------------------------------------------------------------------------
+// MatchData for searchstrings
+// ----------------------------------------------------------------------------
+EXPORT_C void CContactMatcher::MatchDataL( const MDesC16Array& aSearchStrings,
+    const MVPbkFieldTypeList& aFieldTypes,
+    CVPbkContactLinkArray& aLinkArray,
+    const TCallBack& aWordParserCallBack )
+    {
+    InitOperationL( EMatchData );
+    iResultContactLinkArray = &aLinkArray;
+
+    // Start asynchronous matching and wait here until results are ready
+    FreeOldOperation();
+    iOperation = iContactManager->FindL( aSearchStrings, aFieldTypes,
+        *this, aWordParserCallBack );
+
+    if ( iApiMethodStatus != EFinished )
+        {
+        iApiMethodStatus = EExecuting;
+        iASchedulerWait.Start();
+        }
+    User::LeaveIfError( iError );
+    }
+
+// ----------------------------------------------------------------------------
+// CContactMatcher::ContactNameFormatterL
+// ----------------------------------------------------------------------------
+EXPORT_C MPbk2ContactNameFormatter& CContactMatcher::ContactNameFormatterL()
+    {
+    //first initialise, if not already initialised
+    if ( !iSortOrderManager )
+        {
+        iSortOrderManager = CPbk2SortOrderManager::NewL( FieldTypes() );
+        }
+        
+    if ( !iNameFormatter )
+        {
+        iNameFormatter = Pbk2ContactNameFormatterFactory::CreateL( FieldTypes(),
+                                                                  *iSortOrderManager );
+        }
+    return *iNameFormatter;
+    }
+
+
+// -----------------------------------------------------------------------------
+// MVPbkContactFieldSelector* CContactMatcher::CreateFieldTypeSelectorLC( )
+// -----------------------------------------------------------------------------
+MVPbkContactFieldSelector* CContactMatcher::CreateFieldTypeSelectorLC
+  ( TInt aResId )
+  {
+    if ( !iResourceFileInitialized )
+        {
+        TFileName tmpName;
+        // Append the Resource Files Directory
+        tmpName.Append( KDC_RESOURCE_FILES_DIR );     
+        // Append the Ressource File Name
+        tmpName.Append( KMsgCommonUtilsResourceFileName );
+  
+        // Obtain the drive where the DLL is installed
+        TFileName dllDrive;
+        Dll::FileName( dllDrive );
+  
+        // Obtain the Complete path for the Resource File
+        TParse parse;
+        parse.Set( dllDrive, NULL, NULL );
+        parse.Set( parse.Drive(), &tmpName, NULL );
+        TFileName fileName;
+        fileName.Append( parse.FullName());
+
+        iResourceFile.OpenL( *iFsSession, fileName );
+        iResourceFile.ConfirmSignatureL( 0 );
+        iResourceFileInitialized = ETrue;
+        }
+
+    HBufC8* dataBuffer = iResourceFile.AllocReadLC( aResId );
+
+    TResourceReader reader;
+    reader.SetBuffer( dataBuffer );
+
+    CVPbkFieldTypeSelector* fieldTypeSelector =
+        CVPbkFieldTypeSelector::NewL( reader,
+                    FieldTypes() );
+
+    CleanupStack::PopAndDestroy( dataBuffer );
+
+    CleanupStack::PushL( fieldTypeSelector );
+    return fieldTypeSelector;
+    }
+
+// ---------------------------------------------------------------------------
+// ContactMatcherPanics::Panic
+//
+// Panic function
+// ---------------------------------------------------------------------------
+void ContactMatcherPanics::Panic( TPanic aPanic )
+    {
+    _LIT(KPanicCategory, "ContactMatcher");
+    User::Panic( KPanicCategory, aPanic );
+    }
+
+// End of File