homescreensrv_plat/context_utility_api/tsrc/src/hgctxcontactmatcher.cpp
changeset 0 79c6a41cd166
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/homescreensrv_plat/context_utility_api/tsrc/src/hgctxcontactmatcher.cpp	Thu Dec 17 08:54:17 2009 +0200
@@ -0,0 +1,2539 @@
+/*
+* Copyright (c) 2008 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:  Contact matching class
+*
+*/
+
+
+// System includes
+#include <e32base.h>
+#include <bamdesca.h>
+#include <cntitem.h>
+#include <eikenv.h>
+#include <bautils.h>
+#include <fbs.h>
+#include <imageconversion.h>
+#include <data_caging_path_literals.hrh>
+
+#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 <MVPbkContactFieldUriData.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 <TVPbkWordParserCallbackParam.h>
+#include <CVPbkContactViewDefinition.h>
+#include <MVPbkContactViewBase.h>
+#include <coemain.h>
+#include <CPbk2SortOrderManager.h>
+#include <Pbk2ContactNameFormatterFactory.h>
+
+#include "hgctxcontactmatcher.h"
+
+
+#include "hgctxutilslogging.h"
+
+
+// ================= 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
+    };
+
+// number of digits that must match from the right side of a phone number
+const TInt KNumberMatchLenFromRight = 7;
+
+// granularity for CDesCArray
+const TInt KArrayGranularity = 4;
+
+//               YYYYMMDD:HHMMSS.MMMMMM
+_LIT(KNullTime, "11110000:010101.00000");
+
+// ================= STATIC FUNCTIONS =======================
+
+// ---------------------------------------------------------
+// FindWordSplitterL
+// ---------------------------------------------------------
+//
+static TInt FindWordSplitterL( TAny* aParams )
+	{
+	TVPbkWordParserCallbackParam* parser = 
+        static_cast<TVPbkWordParserCallbackParam*>( aParams );
+        
+    const TText* ptr = parser->iStringToParse->Ptr();
+	const TText* end = ptr + parser->iStringToParse->Length();
+
+	const TText* startOfWord=NULL;
+	for ( ; ; )
+		{
+		if ( ptr==end || TChar(*ptr).IsSpace() || *ptr == ',' || *ptr == ';' )
+			{
+			if ( startOfWord )
+				{
+				TPtrC addWord( startOfWord,ptr - startOfWord );
+				parser->iWordArray->AppendL( addWord );
+				startOfWord = NULL;
+				}
+			if ( ptr == end )
+                {
+				break;
+                }
+			}
+		else if ( !startOfWord )
+            {
+			startOfWord = ptr;
+            }
+		ptr++;
+		}
+	return( KErrNone );
+	}
+
+static HBufC* CombineStringsLC( CDesCArray& aArray )
+    {
+    TInt len = 0;
+    for ( TInt i = 0, ie = aArray.Count(); i != ie; ++i )
+        {
+        len += aArray[i].Length() + 1;
+        }
+    HBufC* result = HBufC::NewLC( len );
+    TPtr p( result->Des() );
+    for ( TInt i = 0, ie = aArray.Count(); i != ie; ++i )
+        {
+        if ( i )
+            {
+            p.Append( ' ' );
+            }
+        p.Append( aArray[i] );
+        }
+    return result;
+    }
+    
+// ================= MEMBER FUNCTIONS =======================
+
+// ----------------------------------------------------------------------------
+// Two-phase constructor for CHgCtxContactMatcher class.
+// ----------------------------------------------------------------------------
+EXPORT_C CHgCtxContactMatcher* CHgCtxContactMatcher::NewL(
+    RFs* aFsSession )
+    {
+    CHgCtxContactMatcher* self = CHgCtxContactMatcher::NewLC( aFsSession );
+    CleanupStack::Pop(self);
+    return self;
+    }
+
+// ----------------------------------------------------------------------------
+// Two-phase constructor for CHgCtxContactMatcher class.
+// ----------------------------------------------------------------------------
+EXPORT_C CHgCtxContactMatcher* CHgCtxContactMatcher::NewLC(
+    RFs* aFsSession )
+    {
+    CHgCtxContactMatcher* self = new ( ELeave ) CHgCtxContactMatcher( aFsSession );
+    CleanupStack::PushL(self);
+    self->ConstructL();
+    return self;
+    }
+
+// ----------------------------------------------------------------------------
+// C++ destructor.
+// ----------------------------------------------------------------------------
+EXPORT_C CHgCtxContactMatcher::~CHgCtxContactMatcher()
+    {
+    delete iNameFieldTypes;
+    delete iNumberFieldTypes;
+    delete iEmailFieldTypes;
+    delete iXspIdFieldTypes;
+    delete iAddressFieldTypes;
+	delete iWebAddressFieldTypes;
+    delete iHomeAddressFieldTypes;
+    delete iWorkAddressFieldTypes;
+    
+    FreeOldOperation();
+    CleanupNumberMatch();
+    delete iStoreUris;
+    delete iContactManager;
+    delete iSortOrderManager;
+    delete iNameFormatter;
+
+    if ( iClientStatus )
+        {
+        User::RequestComplete( iClientStatus, KErrCancel );
+        }
+    if ( iASchedulerWait.IsStarted() )
+        {
+        iASchedulerWait.AsyncStop();
+        }
+        
+    iContactObservers.Close();
+    
+    if ( iFsSessionOwned && iFsSession )
+        {
+        iFsSession->Close();
+        delete iFsSession;
+        }
+    }
+
+// ----------------------------------------------------------------------------
+// C++ Constructor.
+// ----------------------------------------------------------------------------
+CHgCtxContactMatcher::CHgCtxContactMatcher( RFs* aFsSession) : iFsSession( aFsSession )
+    {
+    }
+
+// ----------------------------------------------------------------------------
+// Second phase constructor
+// ----------------------------------------------------------------------------
+void CHgCtxContactMatcher::ConstructL()
+    {
+    if ( !iFsSession )
+        {
+        // The contact manager would be okay with NULL but some of our own functions
+        // need an RFs.
+        iFsSessionOwned = ETrue;
+        iFsSession = new ( ELeave ) RFs;
+        User::LeaveIfError( iFsSession->Connect() );
+        }
+        
+    iContactManager = CVPbkContactManager::NewL(
+        *CVPbkContactStoreUriArray::NewLC(), iFsSession );
+    CleanupStack::PopAndDestroy(); // CVPbkContactStoreUriArray
+
+    // No stores open yet
+    iStoreUris = CVPbkContactStoreUriArray::NewL();
+    }
+
+//******************* API-methods *********************************************
+
+// ----------------------------------------------------------------------------
+// Synchronous version
+// ----------------------------------------------------------------------------
+EXPORT_C void CHgCtxContactMatcher::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 CHgCtxContactMatcher::OpenStoreL(
+    const CVPbkContactStoreUriArray& aUriArray, TRequestStatus&  aStatus )
+    {
+    InitOperationL( EOpenStore );
+    OpenStoreCommonL( aUriArray );
+    InitOperation( &aStatus );
+
+    if ( iApiMethodStatus != EFinished )
+        {
+        iApiMethodStatus = EExecuting;
+        }
+    }
+
+
+// ----------------------------------------------------------------------------
+// Common code to sync/async versions.
+// ----------------------------------------------------------------------------
+void CHgCtxContactMatcher::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 CHgCtxContactMatcher::OpenAllStoresL()
+    {
+    OpenStoreL(AllStoreUris);
+    }
+
+// ----------------------------------------------------------------------------
+// Asynchronous version
+// ----------------------------------------------------------------------------
+EXPORT_C void CHgCtxContactMatcher::OpenAllStoresL( TRequestStatus& aStatus )
+    {
+    OpenStoreL(AllStoreUris, aStatus);
+    }
+
+// ----------------------------------------------------------------------------
+// Synchronous version
+// ----------------------------------------------------------------------------
+EXPORT_C void CHgCtxContactMatcher::OpenDefaultMatchStoresL()
+    {
+    OpenStoreL(NumberMatchStoreUris);
+    }
+
+// ----------------------------------------------------------------------------
+// Asynchronous version
+// ----------------------------------------------------------------------------
+EXPORT_C void CHgCtxContactMatcher::OpenDefaultMatchStoresL( TRequestStatus& aStatus )
+    {
+    OpenStoreL(NumberMatchStoreUris, aStatus);
+    }
+
+// ----------------------------------------------------------------------------
+// Open OwnNumber stores.
+// Synchronous version
+// ----------------------------------------------------------------------------
+EXPORT_C void CHgCtxContactMatcher::OpenOwnNumberStoresL()
+    {
+    OpenStoreL(OwnNumberStoreUris);
+    }
+
+// ----------------------------------------------------------------------------
+// Open OwnNumber stores.
+// Asynchronous version
+// ----------------------------------------------------------------------------
+EXPORT_C void CHgCtxContactMatcher::OpenOwnNumberStoresL( TRequestStatus& aStatus )
+    {
+    OpenStoreL(OwnNumberStoreUris, aStatus);
+    }
+
+// ----------------------------------------------------------------------------
+// Close all open stores.
+// ----------------------------------------------------------------------------
+EXPORT_C void CHgCtxContactMatcher::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 CHgCtxContactMatcher::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 CHgCtxContactMatcher::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 CHgCtxContactMatcher::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 CHgCtxContactMatcher::FindFromStoreSucceededL( MVPbkContactStore& /*aStore*/,
+        MVPbkContactLinkArray* aResultsFromStore )
+    {
+    __ASSERT_DEBUG( aResultsFromStore, HgContactMatcherPanics::Panic(
+        HgContactMatcherPanics::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 CHgCtxContactMatcher::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 CHgCtxContactMatcher::FindFromStoreFailed( MVPbkContactStore& /*aStore*/, TInt /*aError*/ )
+    {
+    //no operation, search to continue from the other stores
+    }
+
+
+// ----------------------------------------------------------------------------
+// Find complete
+// ----------------------------------------------------------------------------
+void CHgCtxContactMatcher::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& CHgCtxContactMatcher::FieldTypes() const
+    {
+    return iContactManager->FieldTypes();
+    }
+
+// ----------------------------------------------------------------------------
+// Synchronous version
+// ----------------------------------------------------------------------------
+EXPORT_C void CHgCtxContactMatcher::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 CHgCtxContactMatcher::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 CHgCtxContactMatcher::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 CHgCtxContactMatcher::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 CHgCtxContactMatcher::CancelOperation()
+    {
+    if (iApiMethodStatus != EExecuting)
+        {
+        return;
+        }
+
+    __ASSERT_DEBUG(!iSync, HgContactMatcherPanics::Panic(
+        HgContactMatcherPanics::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 CHgCtxContactMatcher::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 CHgCtxContactMatcher::GetFieldDataDateTimeL(
+    const MVPbkStoreContact& aContact,
+    const MVPbkFieldType& aFType ) const
+    {
+    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 CHgCtxContactMatcher::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* CHgCtxContactMatcher::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* CHgCtxContactMatcher::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 CHgCtxContactMatcher::OpenStoreL(const TDesC& (* const aFuncPtrs[])())
+    {
+    CVPbkContactStoreUriArray* uriArray = GetStoreArrayLC(aFuncPtrs);
+
+    CHgCtxContactMatcher::OpenStoreL(*uriArray);
+    CleanupStack::PopAndDestroy(uriArray);
+    }
+
+// ----------------------------------------------------------------------------
+// Open stores. Asynchronous version
+// ----------------------------------------------------------------------------
+void CHgCtxContactMatcher::OpenStoreL(const TDesC& (* const aFuncPtrs[])(),
+    TRequestStatus&  aStatus)
+    {
+    CVPbkContactStoreUriArray* uriArray = GetStoreArrayLC(aFuncPtrs);
+
+    CHgCtxContactMatcher::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 CHgCtxContactMatcher::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 CHgCtxContactMatcher::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 CHgCtxContactMatcher::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 CHgCtxContactMatcher::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;
+            }
+        case TVPbkContactStoreEvent::EContactAdded:
+        case TVPbkContactStoreEvent::EContactDeleted:
+        case TVPbkContactStoreEvent::EContactChanged:
+            {
+            for ( TInt i = 0, ie = iContactObservers.Count(); i != ie; ++i )
+                {
+                iContactObservers[i]->HandleContactEventL();
+                }
+            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 CHgCtxContactMatcher::FindCompleteL( MVPbkContactLinkArray* aResults )
+    {
+    __ASSERT_DEBUG( aResults, HgContactMatcherPanics::Panic(
+        HgContactMatcherPanics::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 CHgCtxContactMatcher::FindFailed( TInt aError )
+    {
+    OperationFailed( aError );
+    iResultContactLinkArray = NULL;
+    }
+
+// ----------------------------------------------------------------------------
+// Free old VPbk-operation.
+// ----------------------------------------------------------------------------
+void CHgCtxContactMatcher::FreeOldOperation()
+    {
+    delete iOperation;
+    iOperation = NULL;
+    }
+
+// ----------------------------------------------------------------------------
+// Called when operation is completed.
+// ----------------------------------------------------------------------------
+void CHgCtxContactMatcher::VPbkSingleContactOperationComplete(
+        MVPbkContactOperationBase& /*aOperation*/, MVPbkStoreContact* aContact)
+    {
+    *iResultStoreContact = aContact;
+    iResultStoreContact  = NULL;
+    OperationComplete();
+    }
+
+// ----------------------------------------------------------------------------
+// Called if the operation fails.
+// ----------------------------------------------------------------------------
+void CHgCtxContactMatcher::VPbkSingleContactOperationFailed(
+    MVPbkContactOperationBase& /*aOperation*/, TInt aError)
+    {
+    OperationFailed( aError );
+    }
+
+// ----------------------------------------------------------------------------
+// Set member variables for sync operation
+// ----------------------------------------------------------------------------
+void CHgCtxContactMatcher::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 CHgCtxContactMatcher::InitOperationL( TMethodId aMethod, TRequestStatus* aStatus )
+    {
+    InitOperationL( aMethod );
+
+    iSync  = EFalse;
+    iClientStatus  = aStatus;
+    *iClientStatus = KRequestPending;
+    }
+    
+// ----------------------------------------------------------------------------
+// Set member variables for async operation
+// ----------------------------------------------------------------------------
+void CHgCtxContactMatcher::InitOperation( TRequestStatus* aStatus )
+    {
+    iSync  = EFalse;
+    iClientStatus  = aStatus;
+    *iClientStatus = KRequestPending;
+    }
+
+// ----------------------------------------------------------------------------
+// Sync/async operation finished succesfully, return results to method caller.
+// ----------------------------------------------------------------------------
+void CHgCtxContactMatcher::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 CHgCtxContactMatcher::OperationFailed( TInt aError )
+    {
+    iError = aError;
+    OperationComplete( aError );
+    }
+
+// ----------------------------------------------------------------------------
+// Free resources allocated for number matching
+// ----------------------------------------------------------------------------
+void CHgCtxContactMatcher::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.
+}
+
+// ---------------------------------------------------------------------------
+// CHgCtxContactMatcher::GetContactStoresL
+// ---------------------------------------------------------------------------
+EXPORT_C MVPbkContactStoreList& CHgCtxContactMatcher::GetContactStoresL()
+    {
+    return iContactManager->ContactStoresL();
+    }
+
+
+// -----------------------------------------------------------------------------
+// TInt CHgCtxContactMatcher::GetName
+//
+// Returns the formatted name fo the contact
+// -----------------------------------------------------------------------------
+EXPORT_C HBufC* CHgCtxContactMatcher::GetNameL( MVPbkStoreContactFieldCollection&
+                                                                aFieldCollection )
+    {
+    MPbk2ContactNameFormatter& nameFormatter = ContactNameFormatterL();
+    
+    HBufC* formattedName = nameFormatter.GetContactTitleOrNullL( aFieldCollection, 
+    						                                     MPbk2ContactNameFormatter::EUseSeparator );
+    return formattedName;
+    }
+
+// -----------------------------------------------------------------------------
+// CVPbkContactManager& CHgCtxContactMatcher::GetContactManager( )
+// -----------------------------------------------------------------------------
+EXPORT_C CVPbkContactManager& CHgCtxContactMatcher::GetContactManager()
+    {
+    return *iContactManager;
+    }
+    
+
+// ----------------------------------------------------------------------------
+// Synchronous version
+// ----------------------------------------------------------------------------
+EXPORT_C void CHgCtxContactMatcher::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 CHgCtxContactMatcher::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 CHgCtxContactMatcher::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 CHgCtxContactMatcher::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 );
+    }
+
+// ----------------------------------------------------------------------------
+// CHgCtxContactMatcher::ContactNameFormatterL
+// ----------------------------------------------------------------------------
+EXPORT_C MPbk2ContactNameFormatter& CHgCtxContactMatcher::ContactNameFormatterL()
+    {
+    //first initialise, if not already initialised
+    if ( !iSortOrderManager )
+        {
+        iSortOrderManager = CPbk2SortOrderManager::NewL( FieldTypes() );
+        }
+        
+    if ( !iNameFormatter )
+        {
+        iNameFormatter = Pbk2ContactNameFormatterFactory::CreateL( FieldTypes(),
+                                                                  *iSortOrderManager );
+        }
+    return *iNameFormatter;
+    }
+
+
+// ---------------------------------------------------------------------------
+// HgContactMatcherPanics::Panic
+//
+// Panic function
+// ---------------------------------------------------------------------------
+void HgContactMatcherPanics::Panic( TPanic aPanic )
+    {
+    _LIT(KPanicCategory, "ContactMatcher");
+    User::Panic( KPanicCategory, aPanic );
+    }
+
+// ----------------------------------------------------------------------------
+// CHgCtxContactMatcher::SplitAndMatchL
+// ----------------------------------------------------------------------------
+EXPORT_C void CHgCtxContactMatcher::SplitAndMatchL( const TDesC& aData,
+        const MVPbkFieldTypeList& aFieldTypes,
+        CVPbkContactLinkArray& aLinkArray)
+    {
+    CDesCArray* wordArray = SplitFindStringL( aData );
+    CleanupStack::PushL( wordArray );
+    TCallBack findParser( FindWordSplitterL );
+    MatchDataL( *wordArray, aFieldTypes, aLinkArray, findParser );
+    CleanupStack::PopAndDestroy( wordArray );
+    }
+
+// ----------------------------------------------------------------------------
+// CHgCtxContactMatcher::RegisterContactObserverL
+// ----------------------------------------------------------------------------
+EXPORT_C void CHgCtxContactMatcher::RegisterContactObserverL(
+        MHgCtxContactObserver& aObserver )
+    {
+    if ( iContactObservers.Find( &aObserver ) == KErrNotFound )
+        {
+        iContactObservers.AppendL( &aObserver );
+        }
+    }
+
+// ----------------------------------------------------------------------------
+// CHgCtxContactMatcher::UnregisterContactObserver
+// ----------------------------------------------------------------------------
+EXPORT_C void CHgCtxContactMatcher::UnregisterContactObserver(
+        MHgCtxContactObserver& aObserver )
+    {
+    TInt pos = iContactObservers.Find( &aObserver );
+    if ( pos >= 0 )
+        {
+        iContactObservers.Remove( pos );
+        }
+    }
+
+// ----------------------------------------------------------------------------
+// CHgCtxContactMatcher::LookupL
+// ----------------------------------------------------------------------------
+EXPORT_C void CHgCtxContactMatcher::LookupL( const TDesC& aData,
+        CVPbkContactLinkArray& aLinkArray )
+    {
+    HGLOG_CONTEXT( LookupL, HGLOG_LOCAL );
+    HGLOG1_IN( "'%S'", &aData );
+
+    // Take part_A from "part_A <part_B>"
+    // or part_A from "part_A".
+    TPtrC input( aData );
+    TInt ltPos = input.Locate( '<' );
+    TInt gtPos = input.Locate( '>' );
+    if ( ltPos != KErrNotFound && gtPos> ltPos )
+        {
+        input.Set( aData.Mid( 0, ltPos ) );
+        }
+    HBufC* trimmedInput = input.AllocLC();
+    trimmedInput->Des().Trim();
+
+    TInt oldCount = aLinkArray.Count();
+    if ( IsPhoneNumberL( *trimmedInput ) )
+        {
+        TryNumberLookupL( *trimmedInput, aLinkArray );
+        }
+    else
+        {
+        TryTextLookupL( *trimmedInput, aLinkArray );
+        }
+
+    CleanupStack::PopAndDestroy( trimmedInput );
+
+    if ( aLinkArray.Count() == oldCount && ltPos != KErrNotFound && gtPos > ltPos )
+        {
+        // lookup for part_A was not successful so try part_B
+        trimmedInput = aData.Mid( ltPos + 1, gtPos - ltPos - 1 ).AllocLC();
+        trimmedInput->Des().Trim();
+        if ( IsPhoneNumberL( *trimmedInput ) )
+            {
+            TryNumberLookupL( *trimmedInput, aLinkArray );
+            }
+        else
+            {
+            TryTextLookupL( *trimmedInput, aLinkArray );
+            }
+        CleanupStack::PopAndDestroy( trimmedInput );
+        }
+        
+    HGLOG1_OUT( "got %d results", aLinkArray.Count() - oldCount );
+    }
+
+// ----------------------------------------------------------------------------
+// CHgCtxContactMatcher::PreCreateNameFieldTypesL
+// ----------------------------------------------------------------------------
+void CHgCtxContactMatcher::PreCreateNameFieldTypesL()
+    {
+    HGLOG_CONTEXT( PreCreateNameFieldTypesL, HGLOG_LOCAL );
+    HGLOG_IN();
+
+    iNameFieldTypes = CVPbkFieldTypeRefsList::NewL();
+    const MVPbkFieldTypeList& types( FieldTypes() );
+    TVPbkFieldVersitProperty prop;
+    const MVPbkFieldType* t;
+
+    prop.SetName( EVPbkVersitNameFN );
+    prop.SetSubField( EVPbkVersitSubFieldNone );
+    t = types.FindMatch( prop, 0 );
+    if ( t )
+        {
+        iNameFieldTypes->AppendL( *t );
+        HGLOG0( HGLOG_INFO, "will try FN" );
+        }
+
+    prop.SetName( EVPbkVersitNameN );
+    prop.SetSubField( EVPbkVersitSubFieldGivenName );
+    t = types.FindMatch( prop, 0 );
+    if ( t )
+        {
+        iNameFieldTypes->AppendL( *t );
+        HGLOG0( HGLOG_INFO, "will try given name" );
+        }
+    
+    prop.SetName( EVPbkVersitNameN );
+    prop.SetSubField( EVPbkVersitSubFieldFamilyName );
+    t = types.FindMatch( prop, 0 );
+    if ( t )
+        {
+        iNameFieldTypes->AppendL( *t );
+        HGLOG0( HGLOG_INFO, "will try family name" );
+        }
+    
+    prop.SetName( EVPbkVersitNameORG );
+    prop.SetSubField( EVPbkVersitSubFieldOrgName );
+    t = types.FindMatch( prop, 0 );
+    if ( t )
+        {
+        iNameFieldTypes->AppendL( *t );
+        HGLOG0( HGLOG_INFO, "will try org name" );
+        }
+        
+    HGLOG_OUT();
+    }
+
+// ----------------------------------------------------------------------------
+// CHgCtxContactMatcher::PreCreateEmailFieldTypesL
+// ----------------------------------------------------------------------------
+void CHgCtxContactMatcher::PreCreateEmailFieldTypesL()
+    {
+    HGLOG_CONTEXT( PreCreateEmailFieldTypesL, HGLOG_LOCAL );
+    HGLOG_IN();
+
+    iEmailFieldTypes = CVPbkFieldTypeRefsList::NewL();
+    const MVPbkFieldTypeList& types( FieldTypes() );
+    TVPbkFieldVersitProperty prop;
+    const MVPbkFieldType* t;
+
+    prop.SetName( EVPbkVersitNameEMAIL );
+    prop.SetSubField( EVPbkVersitSubFieldNone );
+    prop.Parameters().Reset();
+    prop.Parameters().Add( EVPbkVersitParamINTERNET );
+    t = types.FindMatch( prop, 0 );
+    if ( t )
+        {
+        iEmailFieldTypes->AppendL( *t );
+        HGLOG0( HGLOG_INFO, "will try general email" );
+        }
+
+    prop.SetName( EVPbkVersitNameEMAIL );
+    prop.SetSubField( EVPbkVersitSubFieldNone );
+    prop.Parameters().Reset();
+    prop.Parameters().Add( EVPbkVersitParamINTERNET );
+    prop.Parameters().Add( EVPbkVersitParamWORK );
+    t = types.FindMatch( prop, 0 );
+    if ( t )
+        {
+        iEmailFieldTypes->AppendL( *t );
+        HGLOG0( HGLOG_INFO, "will try work email" );
+        }
+
+    prop.SetName( EVPbkVersitNameEMAIL );
+    prop.SetSubField( EVPbkVersitSubFieldNone );
+    prop.Parameters().Reset();
+    prop.Parameters().Add( EVPbkVersitParamINTERNET );
+    prop.Parameters().Add( EVPbkVersitParamHOME );
+    t = types.FindMatch( prop, 0 );
+    if ( t )
+        {
+        iEmailFieldTypes->AppendL( *t );
+        HGLOG0( HGLOG_INFO, "will try home email" );
+        }
+        
+    HGLOG_OUT();
+    }
+
+// ----------------------------------------------------------------------------
+// CHgCtxContactMatcher::PreCreateXspIdFieldTypesL
+// ----------------------------------------------------------------------------
+void CHgCtxContactMatcher::PreCreateXspIdFieldTypesL()
+    {
+    HGLOG_CONTEXT( PreCreateXspIdFieldTypesL, HGLOG_LOCAL );
+    HGLOG_IN();
+
+    iXspIdFieldTypes = CVPbkFieldTypeRefsList::NewL();
+    const MVPbkFieldTypeList& types( FieldTypes() );
+    TVPbkFieldVersitProperty prop;
+    const MVPbkFieldType* t;
+
+    prop.SetName( EVPbkVersitNameIMPP );
+    t = types.FindMatch( prop, 0 );
+    if ( t )
+        {
+        iXspIdFieldTypes->AppendL( *t );
+        }
+        
+    HGLOG1_OUT( "found %d xsp id field types",
+        iXspIdFieldTypes->FieldTypeCount() );
+    }
+
+// ----------------------------------------------------------------------------
+// CHgCtxContactMatcher::PreCreateNumberFieldTypesL
+// ----------------------------------------------------------------------------
+void CHgCtxContactMatcher::PreCreateNumberFieldTypesL()
+    {
+    HGLOG_CONTEXT( PreCreateNumberFieldTypesL, HGLOG_LOCAL );
+    HGLOG_IN();
+
+    iNumberFieldTypes = CVPbkFieldTypeRefsList::NewL();
+    const MVPbkFieldTypeList& types( FieldTypes() );
+    TVPbkFieldVersitProperty prop;
+    const MVPbkFieldType* t;
+
+    prop.SetName( EVPbkVersitNameTEL );
+    prop.SetSubField( EVPbkVersitSubFieldNone );
+    prop.Parameters().Reset();
+    prop.Parameters().Add( EVPbkVersitParamCELL );
+    prop.Parameters().Add( EVPbkVersitParamHOME );
+    t = types.FindMatch( prop, 0 );
+    if ( t )
+        {
+        iNumberFieldTypes->AppendL( *t );
+        HGLOG0( HGLOG_INFO, "will try home mobile" );
+        }
+
+    prop.SetName( EVPbkVersitNameTEL );
+    prop.SetSubField( EVPbkVersitSubFieldNone );
+    prop.Parameters().Reset();
+    prop.Parameters().Add( EVPbkVersitParamCELL );
+    prop.Parameters().Add( EVPbkVersitParamWORK );
+    t = types.FindMatch( prop, 0 );
+    if ( t )
+        {
+        iNumberFieldTypes->AppendL( *t );
+        HGLOG0( HGLOG_INFO, "will try work mobile" );
+        }
+
+    prop.SetName( EVPbkVersitNameTEL );
+    prop.SetSubField( EVPbkVersitSubFieldNone );
+    prop.Parameters().Reset();
+    prop.Parameters().Add( EVPbkVersitParamCELL );
+    t = types.FindMatch( prop, 0 );
+    if ( t )
+        {
+        iNumberFieldTypes->AppendL( *t );
+        HGLOG0( HGLOG_INFO, "will try general mobile" );
+        }
+
+    prop.SetName( EVPbkVersitNameTEL );
+    prop.SetSubField( EVPbkVersitSubFieldNone );
+    prop.Parameters().Reset();
+    prop.Parameters().Add( EVPbkVersitParamHOME );
+    t = types.FindMatch( prop, 0 );
+    if ( t )
+        {
+        iNumberFieldTypes->AppendL( *t );
+        HGLOG0( HGLOG_INFO, "will try home landline" );
+        }
+
+    prop.SetName( EVPbkVersitNameTEL );
+    prop.SetSubField( EVPbkVersitSubFieldNone );
+    prop.Parameters().Reset();
+    prop.Parameters().Add( EVPbkVersitParamWORK );
+    t = types.FindMatch( prop, 0 );
+    if ( t )
+        {
+        iNumberFieldTypes->AppendL( *t );
+        HGLOG0( HGLOG_INFO, "will try work landline" );
+        }
+
+    prop.SetName( EVPbkVersitNameTEL );
+    prop.SetSubField( EVPbkVersitSubFieldNone );
+    prop.Parameters().Reset();
+    t = types.FindMatch( prop, 0 );
+    if ( t )
+        {
+        iNumberFieldTypes->AppendL( *t );
+        HGLOG0( HGLOG_INFO, "will try general landline" );
+        }
+        
+    HGLOG_OUT();
+    }
+
+// ----------------------------------------------------------------------------
+// CHgCtxContactMatcher::PreCreateAddressFieldTypesL
+// ----------------------------------------------------------------------------
+void CHgCtxContactMatcher::PreCreateAddressFieldTypesL()
+    {
+    HGLOG_CONTEXT( PreCreateAddressFieldTypesL, HGLOG_LOCAL );
+    HGLOG_IN();
+
+    iAddressFieldTypes = CVPbkFieldTypeRefsList::NewL();
+    const MVPbkFieldTypeList& types( FieldTypes() );
+    TVPbkFieldVersitProperty prop;
+    const MVPbkFieldType* t;
+
+    prop.SetName( EVPbkVersitNameADR );
+    prop.SetSubField( EVPbkVersitSubFieldCountry );
+    t = types.FindMatch( prop, 0 );
+    if ( t )
+        {
+        iAddressFieldTypes->AppendL( *t );
+        HGLOG0( HGLOG_INFO, "will try general country" );
+        }
+
+    prop.SetName( EVPbkVersitNameADR );
+    prop.SetSubField( EVPbkVersitSubFieldRegion );
+    t = types.FindMatch( prop, 0 );
+    if ( t )
+        {
+        iAddressFieldTypes->AppendL( *t );
+        HGLOG0( HGLOG_INFO, "will try general region" );
+        }
+
+    prop.SetName( EVPbkVersitNameADR );
+    prop.SetSubField( EVPbkVersitSubFieldLocality );
+    t = types.FindMatch( prop, 0 );
+    if ( t )
+        {
+        iAddressFieldTypes->AppendL( *t );
+        HGLOG0( HGLOG_INFO, "will try general locality" );
+        }
+
+    prop.SetName( EVPbkVersitNameADR );
+    prop.SetSubField( EVPbkVersitSubFieldStreet );
+    t = types.FindMatch( prop, 0 );
+    if ( t )
+        {
+        iAddressFieldTypes->AppendL( *t );
+        HGLOG0( HGLOG_INFO, "will try general street" );
+        }
+        
+    HGLOG_OUT();
+    }
+
+
+// ----------------------------------------------------------------------------
+// CHgCtxContactMatcher::PreCreateWebAddressFieldTypesL
+// ----------------------------------------------------------------------------
+void CHgCtxContactMatcher::PreCreateWebAddressFieldTypesL()
+    {
+    HGLOG_CONTEXT( PreCreateWebAddressFieldTypesL, HGLOG_LOCAL );
+    HGLOG_IN();
+
+    iWebAddressFieldTypes = CVPbkFieldTypeRefsList::NewL();
+    const MVPbkFieldTypeList& types( FieldTypes() );
+    TVPbkFieldVersitProperty prop;
+    const MVPbkFieldType* t;
+
+    prop.Parameters().Add( EVPbkVersitParamPREF );
+    prop.SetName( EVPbkVersitNameURL );
+    t = types.FindMatch( prop, 0 );
+    if ( t )
+        {
+        iWebAddressFieldTypes->AppendL( *t );
+        HGLOG0( HGLOG_INFO, "will try prefered url" );
+        }        
+    
+    HGLOG_OUT();
+    }
+
+// ----------------------------------------------------------------------------
+// CHgCtxContactMatcher::PreCreateWebAddressFieldTypesL
+// ----------------------------------------------------------------------------
+void CHgCtxContactMatcher::PreCreateWebAddressHomeFieldTypesL()
+    {
+    HGLOG_CONTEXT( PreCreateWebAddressHomeFieldTypesL, HGLOG_LOCAL );
+    HGLOG_IN();
+
+    iWebAddressHomeFieldTypes = CVPbkFieldTypeRefsList::NewL();
+    const MVPbkFieldTypeList& types( FieldTypes() );
+    TVPbkFieldVersitProperty prop;
+    const MVPbkFieldType* t;
+
+    prop.Parameters().Add( EVPbkVersitParamHOME );
+    prop.SetName( EVPbkVersitNameURL );
+    t = types.FindMatch( prop, 0 );
+    if ( t )
+        {
+        iWebAddressHomeFieldTypes->AppendL( *t );
+        HGLOG0( HGLOG_INFO, "will try home url" );
+        }   
+    
+    HGLOG_OUT();
+    }
+
+// ----------------------------------------------------------------------------
+// CHgCtxContactMatcher::PreCreateWebAddressFieldTypesL
+// ----------------------------------------------------------------------------
+void CHgCtxContactMatcher::PreCreateWebAddressWorkFieldTypesL()
+    {
+    HGLOG_CONTEXT( PreCreateWebAddressWorkFieldTypesL, HGLOG_LOCAL );
+    HGLOG_IN();
+
+    iWebAddressWorkFieldTypes = CVPbkFieldTypeRefsList::NewL();
+    const MVPbkFieldTypeList& types( FieldTypes() );
+    TVPbkFieldVersitProperty prop;
+    const MVPbkFieldType* t;
+
+    prop.Parameters().Add( EVPbkVersitParamWORK );
+    prop.SetName( EVPbkVersitNameURL );
+    t = types.FindMatch( prop, 0 );
+    if ( t )
+        {
+        iWebAddressWorkFieldTypes->AppendL( *t );
+        HGLOG0( HGLOG_INFO, "will try work url" );
+        }      
+    
+    HGLOG_OUT();
+    }
+
+// ----------------------------------------------------------------------------
+// CHgCtxContactMatcher::PreCreateHomeAddressFieldTypesL
+// ----------------------------------------------------------------------------
+void CHgCtxContactMatcher::PreCreateHomeAddressFieldTypesL()
+    {
+    HGLOG_CONTEXT( PreCreateHomeAddressFieldTypesL, HGLOG_LOCAL );
+    HGLOG_IN();
+
+    iHomeAddressFieldTypes = CVPbkFieldTypeRefsList::NewL();
+    const MVPbkFieldTypeList& types( FieldTypes() );
+    TVPbkFieldVersitProperty prop;
+    const MVPbkFieldType* t;
+    prop.Parameters().Add( EVPbkVersitParamHOME );
+
+    prop.SetName( EVPbkVersitNameADR );
+    prop.SetSubField( EVPbkVersitSubFieldCountry );
+    t = types.FindMatch( prop, 0 );
+    if ( t )
+        {
+        iHomeAddressFieldTypes->AppendL( *t );
+        HGLOG0( HGLOG_INFO, "will try home country" );
+        }
+
+    prop.SetName( EVPbkVersitNameADR );
+    prop.SetSubField( EVPbkVersitSubFieldRegion );
+    t = types.FindMatch( prop, 0 );
+    if ( t )
+        {
+        iHomeAddressFieldTypes->AppendL( *t );
+        HGLOG0( HGLOG_INFO, "will try home region" );
+        }
+
+    prop.SetName( EVPbkVersitNameADR );
+    prop.SetSubField( EVPbkVersitSubFieldLocality );
+    t = types.FindMatch( prop, 0 );
+    if ( t )
+        {
+        iHomeAddressFieldTypes->AppendL( *t );
+        HGLOG0( HGLOG_INFO, "will try home locality" );
+        }
+
+    prop.SetName( EVPbkVersitNameADR );
+    prop.SetSubField( EVPbkVersitSubFieldStreet );
+    t = types.FindMatch( prop, 0 );
+    if ( t )
+        {
+        iHomeAddressFieldTypes->AppendL( *t );
+        HGLOG0( HGLOG_INFO, "will try home street" );
+        }
+        
+    HGLOG_OUT();
+    }
+
+// ----------------------------------------------------------------------------
+// CHgCtxContactMatcher::PreCreateWorkAddressFieldTypesL
+// ----------------------------------------------------------------------------
+void CHgCtxContactMatcher::PreCreateWorkAddressFieldTypesL()
+    {
+    HGLOG_CONTEXT( PreCreateWorkAddressFieldTypesL, HGLOG_LOCAL );
+    HGLOG_IN();
+
+    iWorkAddressFieldTypes = CVPbkFieldTypeRefsList::NewL();
+    const MVPbkFieldTypeList& types( FieldTypes() );
+    TVPbkFieldVersitProperty prop;
+    const MVPbkFieldType* t;
+    prop.Parameters().Add( EVPbkVersitParamWORK );
+
+    prop.SetName( EVPbkVersitNameADR );
+    prop.SetSubField( EVPbkVersitSubFieldCountry );
+    t = types.FindMatch( prop, 0 );
+    if ( t )
+        {
+        iWorkAddressFieldTypes->AppendL( *t );
+        HGLOG0( HGLOG_INFO, "will try work country" );
+        }
+
+    prop.SetName( EVPbkVersitNameADR );
+    prop.SetSubField( EVPbkVersitSubFieldRegion );
+    t = types.FindMatch( prop, 0 );
+    if ( t )
+        {
+        iWorkAddressFieldTypes->AppendL( *t );
+        HGLOG0( HGLOG_INFO, "will try work region" );
+        }
+
+    prop.SetName( EVPbkVersitNameADR );
+    prop.SetSubField( EVPbkVersitSubFieldLocality );
+    t = types.FindMatch( prop, 0 );
+    if ( t )
+        {
+        iWorkAddressFieldTypes->AppendL( *t );
+        HGLOG0( HGLOG_INFO, "will try work locality" );
+        }
+
+    prop.SetName( EVPbkVersitNameADR );
+    prop.SetSubField( EVPbkVersitSubFieldStreet );
+    t = types.FindMatch( prop, 0 );
+    if ( t )
+        {
+        iWorkAddressFieldTypes->AppendL( *t );
+        HGLOG0( HGLOG_INFO, "will try work street" );
+        }
+        
+    HGLOG_OUT();
+    }
+
+// ----------------------------------------------------------------------------
+// CHgCtxContactMatcher::TryTextLookupL
+// ----------------------------------------------------------------------------
+void CHgCtxContactMatcher::TryTextLookupL( const TDesC& aName,
+        CVPbkContactLinkArray& aLinkArray )
+    {
+    HGLOG_CONTEXT( TryTextLookupL, HGLOG_LOCAL );
+    HGLOG_IN();
+
+    CVPbkFieldTypeRefsList* fieldTypes = CVPbkFieldTypeRefsList::NewL();
+    CleanupStack::PushL( fieldTypes );
+
+    // try name and email and ovi id fields
+    if ( !iNameFieldTypes )
+        {
+        PreCreateNameFieldTypesL();
+        }
+    for ( TInt i = 0, ie = iNameFieldTypes->FieldTypeCount(); i != ie; ++i )
+        {
+        fieldTypes->AppendL( iNameFieldTypes->FieldTypeAt( i ) );
+        }
+    if ( !iEmailFieldTypes )
+        {
+        PreCreateEmailFieldTypesL();
+        }
+    for ( TInt i = 0, ie = iEmailFieldTypes->FieldTypeCount(); i != ie; ++i )
+        {
+        fieldTypes->AppendL( iEmailFieldTypes->FieldTypeAt( i ) );
+        }
+    if ( !iXspIdFieldTypes )
+        {
+        PreCreateXspIdFieldTypesL();
+        }
+    for ( TInt i = 0, ie = iXspIdFieldTypes->FieldTypeCount(); i != ie; ++i )
+        {
+        fieldTypes->AppendL( iXspIdFieldTypes->FieldTypeAt( i ) );
+        }
+
+    SplitAndMatchL( aName, *fieldTypes, aLinkArray );
+
+    CleanupStack::PopAndDestroy( fieldTypes );
+    HGLOG_OUT();
+    }
+
+// ----------------------------------------------------------------------------
+// CHgCtxContactMatcher::TryNumberLookupL
+// ----------------------------------------------------------------------------
+void CHgCtxContactMatcher::TryNumberLookupL( const TDesC& aNumber,
+        CVPbkContactLinkArray& aLinkArray )
+    {
+    HGLOG_CONTEXT( TryNumberLookupL, HGLOG_LOCAL );
+    HGLOG_IN();
+    
+    MatchPhoneNumberL( aNumber,
+        KNumberMatchLenFromRight,
+        CVPbkPhoneNumberMatchStrategy::EVPbkMatchFlagsNone,
+        aLinkArray );
+        
+    HGLOG_OUT();
+    }
+
+// ----------------------------------------------------------------------------
+// CHgCtxContactMatcher::GetTextFieldsL
+// ----------------------------------------------------------------------------
+void CHgCtxContactMatcher::GetTextFieldsL(
+        const CVPbkFieldTypeRefsList& aList,
+        const MVPbkStoreContactFieldCollection& aFieldCollection,
+        CDesCArray& aArray )
+    {
+    HGLOG_CONTEXT( GetTextFieldsL, HGLOG_LOCAL );
+    HGLOG_IN();
+        
+    for ( TInt i = 0, ie = aFieldCollection.FieldCount(); i != ie; ++i )
+        {
+        const MVPbkStoreContactField& field( aFieldCollection.FieldAt( i ) );
+        const MVPbkFieldType* type = field.BestMatchingFieldType();
+        if ( type && aList.ContainsSame( *type ) )
+            {
+            const MVPbkContactFieldData& fdata( field.FieldData() );
+            if ( fdata.DataType() == EVPbkFieldStorageTypeText )
+                {
+                const MVPbkContactFieldTextData& fdata2 =
+                    MVPbkContactFieldTextData::Cast( fdata );
+                const TDesC& text( fdata2.Text() );
+                aArray.AppendL( text );
+                HGLOG1( HGLOG_INFO, "found: '%S'", &text );
+                }
+            }
+        }
+        
+    HGLOG_OUT();
+    }
+
+// ----------------------------------------------------------------------------
+// CHgCtxContactMatcher::GetNumbersL
+// ----------------------------------------------------------------------------
+EXPORT_C void CHgCtxContactMatcher::GetNumbersL(
+        MVPbkStoreContactFieldCollection& aFieldCollection,
+        CDesCArray& aArray )
+    {
+    HGLOG_CONTEXT( GetNumbersL, HGLOG_LOCAL );
+    HGLOG_IN();
+
+    if ( !iNumberFieldTypes )
+        {
+        PreCreateNumberFieldTypesL();
+        }
+    GetTextFieldsL( *iNumberFieldTypes, aFieldCollection, aArray );
+
+    HGLOG_OUT();
+    }
+
+// ----------------------------------------------------------------------------
+// CHgCtxContactMatcher::GetEmailAddressesL
+// ----------------------------------------------------------------------------
+EXPORT_C void CHgCtxContactMatcher::GetEmailAddressesL(
+        MVPbkStoreContactFieldCollection& aFieldCollection,
+        CDesCArray& aArray )
+    {
+    HGLOG_CONTEXT( GetEmailAddressesL, HGLOG_LOCAL );
+    HGLOG_IN();
+
+    if ( !iEmailFieldTypes )
+        {
+        PreCreateEmailFieldTypesL();
+        }
+    GetTextFieldsL( *iEmailFieldTypes, aFieldCollection, aArray );
+
+    HGLOG_OUT();
+    }
+
+// ----------------------------------------------------------------------------
+// CHgCtxContactMatcher::GetAddressesL
+// ----------------------------------------------------------------------------
+EXPORT_C void CHgCtxContactMatcher::GetAddressesL(
+        MVPbkStoreContactFieldCollection& aFieldCollection,
+        CDesCArray& aArray )
+    {
+    HGLOG_CONTEXT( GetAddressesL, HGLOG_LOCAL );
+    HGLOG_IN();
+    
+    CDesC16ArrayFlat* arr = new ( ELeave ) CDesC16ArrayFlat( KArrayGranularity );
+    CleanupStack::PushL( arr );
+
+    if ( !iAddressFieldTypes )
+        {
+        PreCreateAddressFieldTypesL();
+        }
+    GetTextFieldsL( *iAddressFieldTypes, aFieldCollection, *arr );
+    if ( arr->Count() )
+        {
+        HBufC* combined = CombineStringsLC( *arr );
+        aArray.AppendL( *combined );
+        HGLOG1( HGLOG_INFO, "added '%S'", combined );
+        CleanupStack::PopAndDestroy( combined );
+        }
+
+    arr->Reset();
+    if ( !iHomeAddressFieldTypes )
+        {
+        PreCreateHomeAddressFieldTypesL();
+        }
+    GetTextFieldsL( *iHomeAddressFieldTypes, aFieldCollection, *arr );
+    if ( arr->Count() )
+        {
+        HBufC* combined = CombineStringsLC( *arr );
+        aArray.AppendL( *combined );
+        HGLOG1( HGLOG_INFO, "added '%S'", combined );
+        CleanupStack::PopAndDestroy( combined );
+        }
+
+    arr->Reset();
+    if ( !iWorkAddressFieldTypes )
+        {
+        PreCreateWorkAddressFieldTypesL();
+        }
+    GetTextFieldsL( *iWorkAddressFieldTypes, aFieldCollection, *arr );
+    if ( arr->Count() )
+        {
+        HBufC* combined = CombineStringsLC( *arr );
+        aArray.AppendL( *combined );
+        HGLOG1( HGLOG_INFO, "added '%S'", combined );
+        CleanupStack::PopAndDestroy( combined );
+        }
+
+    CleanupStack::PopAndDestroy( arr );
+    HGLOG_OUT();
+    }
+
+
+// ----------------------------------------------------------------------------
+// CHgCtxContactMatcher::GetWebAddressesL
+// ----------------------------------------------------------------------------
+EXPORT_C void CHgCtxContactMatcher::GetWebAddressesL(
+        MVPbkStoreContactFieldCollection& aFieldCollection,
+        CDesCArray& aArray,
+        TWebAddressesType aType  )
+    {
+    HGLOG_CONTEXT( GetWebAddressesL, HGLOG_LOCAL );
+    HGLOG_IN();
+    CVPbkFieldTypeRefsList* addressFieldTypes( NULL );
+    
+    switch ( aType )
+        {
+        case EWebAddresses:
+            {
+            if ( !iWebAddressFieldTypes )
+               {
+               PreCreateWebAddressFieldTypesL();
+               }
+            addressFieldTypes = iWebAddressFieldTypes;
+            }
+            break;
+            
+        case EWebAddressesHome:
+            {
+            if ( !iWebAddressHomeFieldTypes )
+               {
+               PreCreateWebAddressHomeFieldTypesL();
+               }
+            addressFieldTypes = iWebAddressHomeFieldTypes;
+            }
+            break;
+
+        case EWebAddressesWork:
+            {
+            if ( !iWebAddressWorkFieldTypes )
+                {
+                PreCreateWebAddressWorkFieldTypesL();
+                }
+            addressFieldTypes = iWebAddressWorkFieldTypes;
+            }
+            break;
+            
+        default:
+            break;
+        }
+    
+    if( addressFieldTypes )
+        {
+        GetTextFieldsL( *addressFieldTypes, aFieldCollection, aArray );
+        }
+    
+    HGLOG_OUT();
+    }
+
+// ----------------------------------------------------------------------------
+// CHgCtxContactMatcher::GetThumbnailL
+// ----------------------------------------------------------------------------
+EXPORT_C CFbsBitmap* CHgCtxContactMatcher::GetThumbnailL(
+        MVPbkStoreContactFieldCollection& aFieldCollection )
+    {
+    HGLOG_CONTEXT( GetThumbnailL, HGLOG_LOCAL );
+    HGLOG_IN();
+    
+    CFbsBitmap* result = 0;
+    TVPbkFieldVersitProperty prop;
+    prop.SetName( EVPbkVersitNamePHOTO );
+    const MVPbkFieldType* t = FieldTypes().FindMatch( prop, 0 );
+    if ( t )
+        {
+        HGLOG0( HGLOG_INFO, "photo field type found" );
+        for ( TInt i = 0, ie = aFieldCollection.FieldCount(); i != ie; ++i )
+            {
+            const MVPbkStoreContactField& field( aFieldCollection.FieldAt( i ) );
+            const MVPbkFieldType* type = field.BestMatchingFieldType();
+            if ( type && type->IsSame( *t ) )
+                {
+                const MVPbkContactFieldData& fdata( field.FieldData() );
+                if ( fdata.DataType() == EVPbkFieldStorageTypeBinary )
+                    {
+                    HGLOG0( HGLOG_INFO, "found thumbnail" );
+                    const MVPbkContactFieldBinaryData& fdata2 =
+                        MVPbkContactFieldBinaryData::Cast( fdata );
+                    TPtrC8 data( fdata2.BinaryData() );
+                    CImageDecoder* decoder = 0;
+                    // DataNewL does not seem to work properly with
+                    // EOptionAlwaysThread, it will hang in WaitForRequest
+                    // for ever, at least in the panel app.
+                    // So write the image to a temporary file (duhhh...)
+                    // and use FileNewL.
+                    RFile f;
+                    TFileName tempFileName;
+                    iFsSession->CreatePrivatePath( EDriveC );
+                    iFsSession->PrivatePath( tempFileName );
+                    _LIT( KDriveC, "C:" );
+                    _LIT( KTempName, "hgctxthumb" );
+                    tempFileName.Insert( 0, KDriveC );
+                    tempFileName.Append( KTempName );
+                    HGLOG1( HGLOG_INFO, "tempfn='%S'", &tempFileName );
+                    User::LeaveIfError( f.Replace( *iFsSession, tempFileName,
+                                    EFileWrite ) );
+                    f.Write( data, data.Length() );
+                    f.Close();
+                    TRAPD( err, decoder = CImageDecoder::FileNewL( *iFsSession,
+                                    tempFileName,
+                                    CImageDecoder::EOptionAlwaysThread ) );
+                    HGLOG1( HGLOG_INFO, "decoder NewL result: %d", err );
+                    if ( err == KErrNone )
+                        {
+                        CleanupStack::PushL( decoder );
+                        result = new ( ELeave ) CFbsBitmap;
+                        CleanupStack::PushL( result );
+                        TSize sz( decoder->FrameInfo().iOverallSizeInPixels );
+                        TDisplayMode mode( decoder->FrameInfo().iFrameDisplayMode );
+                        HGLOG3( HGLOG_INFO, "size=%dx%d, mode=%d", sz.iWidth,
+                                sz.iHeight, mode );
+                        User::LeaveIfError( result->Create( sz, mode ) );
+        
+                        TRequestStatus status;
+                        HGLOG0( HGLOG_INFO, "starting to convert" );
+                        decoder->Convert( &status, *result );
+                        User::WaitForRequest( status );
+                        HGLOG1( HGLOG_INFO, "decoder Convert result: %d",
+                                status.Int() );
+                        CleanupStack::Pop( result );
+                        CleanupStack::PopAndDestroy( decoder );
+        
+                        if ( status.Int() != KErrNone )
+                            {
+                            delete result;
+                            result = 0;
+                            }
+                        else
+                            {
+                            // stop and return the bitmap
+                            break;
+                            }
+                        }                    
+                    }
+                }
+            }
+        }
+        
+    HGLOG_OUT();
+    return result;
+    }
+
+// ----------------------------------------------------------------------------
+// CHgCtxContactMatcher::IsPhoneNumberL
+// ----------------------------------------------------------------------------
+EXPORT_C TBool CHgCtxContactMatcher::IsPhoneNumberL( const TDesC& aData )
+    {
+    TBool result = EFalse;
+    CFindItemEngine::SFoundItem item;
+    CFindItemEngine* search = CFindItemEngine::NewL( aData,
+        CFindItemEngine::EFindItemSearchPhoneNumberBin );
+    if ( search->ItemCount() )
+        {
+        search->Item( item );
+        result = item.iStartPos == 0;
+        }
+    delete search;
+    return result;
+    }
+
+// ----------------------------------------------------------------------------
+// CHgCtxContactMatcher::IsEmailAddressL
+// ----------------------------------------------------------------------------
+EXPORT_C TBool CHgCtxContactMatcher::IsEmailAddressL( const TDesC& aData )
+    {
+    TBool result = EFalse;
+    CFindItemEngine::SFoundItem item;
+    CFindItemEngine* search = CFindItemEngine::NewL( aData,
+        CFindItemEngine::EFindItemSearchMailAddressBin );
+    if ( search->ItemCount() )
+        {
+        search->Item( item );
+        result = item.iStartPos == 0;
+        }
+    delete search;
+    return result;
+    }
+
+// ----------------------------------------------------------------------------
+// CHgCtxContactMatcher::GetNamesForFindL
+// ----------------------------------------------------------------------------
+EXPORT_C void CHgCtxContactMatcher::GetNamesForFindL(
+        MVPbkStoreContactFieldCollection& aFieldCollection,
+        CDesCArray& aArray )
+    {
+    CVPbkFieldTypeRefsList* nameTypes = CVPbkFieldTypeRefsList::NewL();
+    CleanupStack::PushL( nameTypes );
+    const MVPbkFieldTypeList& types( FieldTypes() );
+    TVPbkFieldVersitProperty prop;
+    const MVPbkFieldType* t;
+    
+    prop.SetName( EVPbkVersitNameN );
+    prop.SetSubField( EVPbkVersitSubFieldGivenName );
+    t = types.FindMatch( prop, 0 );
+    if ( t )
+        {
+        nameTypes->AppendL( *t );
+        }
+    
+    prop.SetName( EVPbkVersitNameN );
+    prop.SetSubField( EVPbkVersitSubFieldFamilyName );
+    t = types.FindMatch( prop, 0 );
+    if ( t )
+        {
+        nameTypes->AppendL( *t );
+        }
+    
+    for ( TInt i = 0, ie = aFieldCollection.FieldCount(); i != ie; ++i )
+        {
+        const MVPbkStoreContactField& field( aFieldCollection.FieldAt( i ) );
+        t = field.MatchFieldType( 0 );
+        if ( t && nameTypes->ContainsSame( *t ) )
+            {
+            const MVPbkContactFieldData& fdata( field.FieldData() );
+            if ( fdata.DataType() == EVPbkFieldStorageTypeText )
+                {
+                const MVPbkContactFieldTextData& fdata2 =
+                    MVPbkContactFieldTextData::Cast( fdata );
+                aArray.AppendL( fdata2.Text() );
+                }
+            }
+        }
+
+    CleanupStack::PopAndDestroy( nameTypes );
+    }
+
+// ----------------------------------------------------------------------------
+// CHgCtxContactMatcher::GetNamesForFindL
+// ----------------------------------------------------------------------------
+EXPORT_C HBufC* CHgCtxContactMatcher::GetNamesForFindL(
+        MVPbkStoreContactFieldCollection& aFieldCollection )
+    {
+    CDesC16ArrayFlat* arr = new ( ELeave ) CDesC16ArrayFlat( KArrayGranularity );
+    CleanupStack::PushL( arr );
+    GetNamesForFindL( aFieldCollection, *arr );
+    HBufC* result = CombineStringsLC( *arr );
+    CleanupStack::Pop( result );
+    CleanupStack::PopAndDestroy( arr );
+    return result;
+    }
+
+// ----------------------------------------------------------------------------
+// CHgCtxContactMatcher::SplitFindStringL
+// ----------------------------------------------------------------------------
+EXPORT_C CDesCArray* CHgCtxContactMatcher::SplitFindStringL(const TDesC& aFindString)
+    {
+	CDesCArray* wordArray = new ( ELeave ) CDesCArrayFlat( KArrayGranularity );
+	CleanupStack::PushL( wordArray );	
+	
+    TVPbkWordParserCallbackParam parser( &aFindString, wordArray );
+	FindWordSplitterL( &parser );
+	
+	CleanupStack::Pop(); // wordArray
+	return parser.iWordArray;
+    }
+
+// ----------------------------------------------------------------------------
+// CHgCtxContactMatcher::SplitMsgContactL
+// ----------------------------------------------------------------------------
+EXPORT_C void CHgCtxContactMatcher::SplitMsgContactL( const TDesC& aString,
+        CDesCArray& aArray )
+    {
+    TInt pos = aString.Locate( '<' );
+    if ( pos >= 0 )
+        {
+        // skip spaces before '<'
+        TInt endPos = pos - 1;
+        while ( endPos > 0 && TChar( aString[endPos] ).IsSpace() )
+            {
+            --endPos;
+            }
+        // take the text before '<'
+        aArray.AppendL( aString.Left( endPos + 1 ) );
+        // take the text between '<' and '>'
+        TInt closePos = aString.Locate( '>' );
+        if ( closePos > pos )
+            {
+            aArray.AppendL( aString.Mid( pos + 1, closePos - pos - 1 ) );
+            }
+        }
+    else
+        {
+        aArray.AppendL( aString );
+        }
+    }
+
+// ----------------------------------------------------------------------------
+// CHgCtxContactMatcher::GetCustomFieldL
+// ----------------------------------------------------------------------------
+EXPORT_C void CHgCtxContactMatcher::GetCustomFieldL(
+        MVPbkStoreContactFieldCollection& aFieldCollection,
+        CDesCArray& aArray,
+        TVPbkFieldTypeName aVersitName,
+        TVPbkFieldTypeParameter aVersitParam )
+    {
+    HGLOG_CONTEXT( GetCustomFieldL, HGLOG_LOCAL );
+    HGLOG_IN();
+    
+    CVPbkFieldTypeRefsList* typeList = GetCustomFieldTypeLC(
+        aVersitName, aVersitParam );
+
+    GetTextFieldsL( *typeList, aFieldCollection, aArray );
+    
+    CleanupStack::PopAndDestroy( typeList );
+    HGLOG_OUT();
+    }
+
+// ----------------------------------------------------------------------------
+// CHgCtxContactMatcher::GetCustomFieldTypeLC
+// ----------------------------------------------------------------------------
+EXPORT_C CVPbkFieldTypeRefsList* CHgCtxContactMatcher::GetCustomFieldTypeLC(
+        TVPbkFieldTypeName aVersitName,
+        TVPbkFieldTypeParameter aVersitParam )
+    {
+    HGLOG_CONTEXT( GetCustomFieldTypeLC, HGLOG_LOCAL );
+    HGLOG_IN();
+    
+    CVPbkFieldTypeRefsList* typeList = CVPbkFieldTypeRefsList::NewL();
+    CleanupStack::PushL( typeList );
+    const MVPbkFieldTypeList& types( FieldTypes() );
+    TVPbkFieldVersitProperty prop;
+    const MVPbkFieldType* t;
+
+    prop.SetName( aVersitName );
+    prop.Parameters().Add( aVersitParam );
+    t = types.FindMatch( prop, 0 );
+    if ( t )
+        {
+        typeList->AppendL( *t );
+        HGLOG0( HGLOG_INFO, "field found" );
+        }
+
+    HGLOG_OUT();
+    return typeList;
+    }
+
+// ----------------------------------------------------------------------------
+// CHgCtxContactMatcher::GetImppFieldL
+// ----------------------------------------------------------------------------
+EXPORT_C void CHgCtxContactMatcher::GetImppFieldL(
+        MVPbkStoreContactFieldCollection& aFieldCollection,
+        CDesCArray* aSchemeOnlyArray,
+        CDesCArray* aUriOnlyArray,
+        CDesCArray* aFullArray )
+    {
+    HGLOG_CONTEXT( GetImppFieldL, HGLOG_LOCAL );
+    HGLOG_IN();
+
+    // this function will not build on TUBE
+    CVPbkFieldTypeRefsList* typeList = CVPbkFieldTypeRefsList::NewL();
+    CleanupStack::PushL( typeList );
+    const MVPbkFieldTypeList& types( FieldTypes() );
+    TVPbkFieldVersitProperty prop;
+    const MVPbkFieldType* t;
+    prop.SetName( EVPbkVersitNameIMPP );
+    t = types.FindMatch( prop, 0 );
+    if ( t )
+        {
+        typeList->AppendL( *t );
+        HGLOG0( HGLOG_INFO, "type found" );
+        }
+    for ( TInt i = 0, ie = aFieldCollection.FieldCount(); i != ie; ++i )
+        {
+        const MVPbkStoreContactField& field( aFieldCollection.FieldAt( i ) );
+        const MVPbkFieldType* type = field.BestMatchingFieldType();
+        if ( type && typeList->ContainsSame( *type ) )
+            {
+            const MVPbkContactFieldData& fdata( field.FieldData() );
+            HGLOG1( HGLOG_INFO, "field found %d", fdata.DataType() );
+            if ( fdata.DataType() == EVPbkFieldStorageTypeUri )
+                {
+                const MVPbkContactFieldUriData& fdata2 =
+                    MVPbkContactFieldUriData::Cast( fdata );
+                const TDesC& schemeOnly( fdata2.Scheme() );
+                const TDesC& uriOnly( fdata2.Text() );
+                const TDesC& fullText( fdata2.Uri() );
+                HGLOG3( HGLOG_INFO, "'%S' + '%S' = '%S'",
+                    &schemeOnly, &uriOnly, &fullText );
+                if ( aSchemeOnlyArray )
+                    {
+                    aSchemeOnlyArray->AppendL( schemeOnly );
+                    }
+                if ( aUriOnlyArray )
+                    {
+                    aUriOnlyArray->AppendL( uriOnly );
+                    }
+                if ( aFullArray )
+                    {
+                    aFullArray->AppendL( fullText );
+                    }
+                }
+            }
+        }                    
+    CleanupStack::PopAndDestroy( typeList );
+    
+    HGLOG_OUT();
+    }
+
+// ----------------------------------------------------------------------------
+// CHgCtxContactMatcher::FindContactWithBirthdayL
+// ----------------------------------------------------------------------------
+EXPORT_C void CHgCtxContactMatcher::FindContactWithBirthdayL(
+        const TTime& aDate,
+        CVPbkContactLinkArray& aLinkArray )
+    {
+    HGLOG_CONTEXT( FindContactWithBirthdayL, HGLOG_LOCAL );
+    HGLOG1_IN( "%Ld", aDate.Int64() );
+
+    // extract month and day
+    TDateTime dt = aDate.DateTime();
+    TInt month = dt.Month();
+    TInt day = dt.Day();
+    HGLOG2( HGLOG_INFO, "wanted month = %d day = %d", month, day );
+
+    CVPbkFieldTypeRefsList* emptyList = CVPbkFieldTypeRefsList::NewL();
+    CleanupStack::PushL( emptyList );
+
+    // create view with all contacts
+    CVPbkContactViewDefinition* def = CVPbkContactViewDefinition::NewLC();
+    def->SetType( EVPbkContactsView );
+    def->SetUriL( VPbkContactStoreUris::DefaultCntDbUri() );
+    MVPbkContactViewBase* view = iContactManager->CreateContactViewLC(
+        *this, *def, *emptyList );
+
+    HGLOG0( HGLOG_INFO, "starting wait" );
+    iASchedulerWait.Start();
+    HGLOG0( HGLOG_INFO, "after wait" );
+
+    // view is ready
+    TInt ctCount = view->ContactCountL();
+    HGLOG1( HGLOG_INFO, "contact count: %d", ctCount );
+
+    // find the birthday field type
+    const MVPbkFieldTypeList& types( FieldTypes() );
+    TVPbkFieldVersitProperty prop;
+    const MVPbkFieldType* bdayFt;
+    prop.SetName( EVPbkVersitNameBDAY );
+    prop.SetSubField( EVPbkVersitSubFieldNone );
+    bdayFt = types.FindMatch( prop, 0 );
+
+    if ( bdayFt && ctCount )
+        {
+        HGLOG0( HGLOG_INFO, "found bday field type" );
+        TTime nullTime( KNullTime );
+        // go through all contacts and check birthday field values
+        for ( TInt i = 0; i < ctCount; ++i )
+            {
+            MVPbkContactLink* link( view->CreateLinkLC( i ) );
+            MVPbkStoreContact* contact = 0;
+            GetStoreContactL( *link, &contact );
+            if ( contact )
+                {
+                HGLOG1( HGLOG_INFO, "got contact, idx %d", i );
+                contact->PushL();
+                TTime bday;
+                bday = GetFieldDataDateTimeL( *contact, *bdayFt );
+                if ( bday != nullTime )
+                    {
+                    HGLOG1( HGLOG_INFO, "found bday %Ld", bday.Int64() );
+                    dt = bday.DateTime();
+                    TInt thisMonth = dt.Month();
+                    TInt thisDay = dt.Day();
+                    HGLOG2( HGLOG_INFO, "for this contact month = %d day = %d",
+                        thisMonth, thisDay );
+                    if ( thisMonth == month && thisDay == day )
+                        {
+                        HGLOG0( HGLOG_INFO, "match" );
+                        aLinkArray.AppendL( link );
+                        link = 0;
+                        }
+                    }
+                CleanupStack::PopAndDestroy(); // contact
+                }
+            CleanupStack::Pop(); // if matched then no ownership and link is NULL by now
+            delete link;
+            }
+        }
+
+    CleanupStack::PopAndDestroy(); // view
+    CleanupStack::PopAndDestroy( def );
+    CleanupStack::PopAndDestroy( emptyList );
+
+    HGLOG_OUT();
+    }
+
+// ----------------------------------------------------------------------------
+// CHgCtxContactMatcher::ContactViewReady
+// ----------------------------------------------------------------------------
+void CHgCtxContactMatcher::ContactViewReady(
+        MVPbkContactViewBase& aView ) 
+    {
+    HGLOG_CONTEXT( ContactViewReady, HGLOG_LOCAL );
+    HGLOG_IN();
+
+    if ( iASchedulerWait.IsStarted() )
+        {
+        iASchedulerWait.AsyncStop();
+        }
+
+    aView.RemoveObserver( *this ); 
+
+    HGLOG_OUT();
+    }
+
+// ----------------------------------------------------------------------------
+// CHgCtxContactMatcher::ContactViewUnavailable
+// ----------------------------------------------------------------------------
+void CHgCtxContactMatcher::ContactViewUnavailable(
+        MVPbkContactViewBase& /*aView*/ )
+    {
+    // means that view is unavailable for now
+    // but ContactViewReady will be called at some point
+    }
+
+// ----------------------------------------------------------------------------
+// CHgCtxContactMatcher::ContactAddedToView
+// ----------------------------------------------------------------------------
+void CHgCtxContactMatcher::ContactAddedToView(
+        MVPbkContactViewBase& /*aView*/, 
+        TInt /*aIndex*/,
+        const MVPbkContactLink& /*aContactLink*/ )
+    {
+    }
+
+// ----------------------------------------------------------------------------
+// CHgCtxContactMatcher::ContactRemovedFromView
+// ----------------------------------------------------------------------------
+ void CHgCtxContactMatcher::ContactRemovedFromView(
+        MVPbkContactViewBase& /*aView*/, 
+        TInt /*aIndex*/, 
+        const MVPbkContactLink& /*aContactLink*/ )
+    {
+    }
+
+// ----------------------------------------------------------------------------
+// CHgCtxContactMatcher::ContactViewError
+// ----------------------------------------------------------------------------
+ void CHgCtxContactMatcher::ContactViewError(
+        MVPbkContactViewBase& aView, 
+        TInt aError, 
+        TBool /*aErrorNotified*/ )
+    {
+    HGLOG_CONTEXT( ContactViewError, HGLOG_LOCAL );
+    HGLOG1_IN( "aError = %d", aError );
+
+    if ( iASchedulerWait.IsStarted() )
+        {
+        iASchedulerWait.AsyncStop();
+        }
+
+    aView.RemoveObserver( *this ); 
+    
+    HGLOG_OUT();
+    }
+
+
+// End of File