--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/phonebookengines/contactsmodel/cntmodel/src/ccontactprivate.cpp Tue Feb 02 10:12:17 2010 +0200
@@ -0,0 +1,1060 @@
+// Copyright (c) 1997-2009 Nokia Corporation and/or its subsidiary(-ies).
+// All rights reserved.
+// This component and the accompanying materials are made available
+// under the terms of "Eclipse Public License v1.0"
+// which accompanies this distribution, and is available
+// at the URL "http://www.eclipse.org/legal/epl-v10.html".
+//
+// Initial Contributors:
+// Nokia Corporation - initial contribution.
+//
+// Contributors:
+//
+// Description:
+//
+
+/**
+ @file
+ @internalComponent
+ @released
+*/
+
+
+#include <cntdb.h>
+#include "CNTSTD.H"
+#include "rcntmodel.h"
+#include "ccontactprivate.h"
+#include "cntviewprivate.h"
+#ifdef SYMBIAN_ENABLE_SPLIT_HEADERS
+#include "cntdb_internal.h"
+#include "cntsyncecom.h"
+#endif
+
+
+const TInt KMaxItemsInTemplateCache = 8; // Maximum number of cached templates.
+const TInt KInitialSortArraySize = 20; // Initial size of sort array.
+
+
+/**
+CTextFieldMinimal destructor.
+*/
+CTextFieldMinimal::~CTextFieldMinimal()
+ {
+ delete iText;
+ }
+
+
+/**
+CTextFieldMinimal second phase constructor.
+*/
+void CTextFieldMinimal::ConstructL(const TDesC &aText, TContactItemId aId)
+ {
+ iText=aText.AllocL();
+ iId=aId;
+ }
+
+
+/**
+CSortArray first phase constructor.
+*/
+CSortArray::CSortArray()
+ :
+ iArray(KInitialSortArraySize)
+ {
+ }
+
+
+/**
+CSortArray destructor.
+*/
+CSortArray::~CSortArray()
+ {
+ iArray.ResetAndDestroy();
+ iArray.Close();
+ }
+
+
+/**
+Create a CTextFieldMinimal object using the given text and Contact ID and append
+it to the sort array.
+
+@param aText Text for CTextFieldMinimal object.
+@param aId Contact ID for CTextFieldMinimal object.
+*/
+void CSortArray::AppendL(const TDesC &aText, TContactItemId aId)
+ {
+ CTextFieldMinimal *tm=new(ELeave) CTextFieldMinimal;
+ CleanupStack::PushL(tm);
+ tm->ConstructL(aText, aId);
+ User::LeaveIfError(iArray.Append(tm));
+ CleanupStack::Pop(); // tm
+ }
+
+
+/**
+Sort the sort array using the given sort order.
+
+@param aOrder EAsc for ascending order, EDesc for descending order.
+*/
+void CSortArray::SortL(CContactDatabase::TSortPref::TOrder aOrder)
+ {
+ // If nothing to sort then return immediately.
+ if (iArray.Count()==0)
+ {
+ return;
+ }
+
+ // Sort the array in ascending sort order using the default algorithm to
+ // compare the elements in the sort array.
+ iArray.Sort(TLinearOrder<CTextFieldMinimal>(DefaultAlgorithmToCompareNames));
+
+ // If descending sort order then reverse the elements in the sort array.
+ if (aOrder==CContactDatabase::TSortPref::EDesc)
+ {
+ TInt count=Count();
+ TInt end=count/2;
+ TInt index2=count-1;
+ for(TInt index=0;index<end;index++)
+ {
+ CTextFieldMinimal *tfm=(CTextFieldMinimal *)iArray[index];
+ iArray[index]=iArray[index2];
+ iArray[index2]=tfm;
+ index2--;
+ }
+ }
+ }
+
+
+/**
+Compare the text in the given CTextFieldMinimal objects.
+
+The custom TCollation method is required to ensure that the collated comparison
+will not ignore spaces and punctuation (which it does by default).
+
+Mem::CollationMethodByIndex() is an exec call and is hence relatively expensive.
+Although it is inefficient to create a collation method each time this method is
+called, there is no benefit in storing TCollationMethod as a member of
+CSortArray because this method must be static.
+
+@param aName1
+@param aName2
+
+@return A positive value if text in aName1 is greater than text in aName2, a
+negative value if text in aName1 is less than text in aName2 and zero if the
+text in both aName1 and aName2 is the same.
+*/
+TInt CSortArray::DefaultAlgorithmToCompareNames(const CTextFieldMinimal& aName1, const CTextFieldMinimal& aName2)
+ {
+ TCollationMethod collateMethod;
+ collateMethod = *Mem::CollationMethodByIndex(0);
+ collateMethod.iFlags|=TCollationMethod::EIgnoreNone;
+ return aName1.iText->CompareC(*aName2.iText,3,&collateMethod);
+ }
+
+
+/**
+Get the Contact ID at the given index in the sort array.
+
+@return The Contact ID at the given index.
+*/
+TContactItemId CSortArray::Id(TInt aIndex) const
+ {
+ return(((CTextFieldMinimal *)iArray[aIndex])->iId);
+ }
+
+
+/**
+Get the text at the given index in the sort array.
+
+@return The text at the given index.
+*/
+HBufC* CSortArray::Text(TInt aIndex) const
+ {
+ return(((CTextFieldMinimal *)iArray[aIndex])->iText);
+ }
+
+
+/**
+Merge the given sort array with this sort array starting from the given position
+in this sort array.
+
+@param aDuplicates The sort array to be merged with this sort array.
+@param aStartPos The starting position for the merge in this sort array.
+*/
+void CSortArray::Merge(CSortArray *aDuplicates,TInt aStartPos)
+ {
+ TInt numDuplicates=aDuplicates->Count();
+ for (TInt loop=0;loop<numDuplicates;loop++)
+ {
+ const TInt index=aStartPos+loop;
+ delete iArray[index];
+ iArray[index]=aDuplicates->iArray[0];
+ aDuplicates->iArray.Remove(0);
+ }
+ }
+
+
+/**
+CCntTemplateCache object factory.
+
+@return CCntTemplateCache object.
+*/
+CCntTemplateCache* CCntTemplateCache::NewL(RCntModel& aCntSvr)
+ {
+ CCntTemplateCache* templateCache = new(ELeave) CCntTemplateCache(aCntSvr);
+ return templateCache;
+ }
+
+
+/**
+CCntTemplateCache first phase constructor.
+
+@param aCntSvr Client Contacts Model session object handle.
+*/
+CCntTemplateCache::CCntTemplateCache(RCntModel& aCntSvr)
+ :
+ iCache(KMaxItemsInTemplateCache),
+ iCntSvr(aCntSvr),
+ iTemplateId(KGoldenTemplateId)
+ {
+ }
+
+
+/**
+CCntTemplateCache destructor.
+*/
+CCntTemplateCache::~CCntTemplateCache()
+ {
+ iCache.ResetAndDestroy();
+ delete iViewDef;
+ delete iSystemTemplate;
+ }
+
+
+/**
+Delete an entry from the template cache.
+
+@param aIndex Index of entry in template cache to be deleted.
+*/
+void CCntTemplateCache::DeleteEntry(TInt aIndex)
+ {
+ delete iCache [aIndex];
+ iCache.Remove(aIndex);
+ }
+
+
+/**
+Remove a template from the template cache.
+
+@param aId ID of the template which is to be removed from the template cache.
+*/
+void CCntTemplateCache::RemoveTemplate(TContactItemId aId)
+ {
+ for(TInt ii=iCache.Count() - 1; ii >= 0; --ii)
+ {
+ if (iCache[ii]->Id() == aId)
+ {
+ DeleteEntry(ii);
+ }
+ }
+
+ // Are we removing the system template?
+ if (iSystemTemplate != NULL && iSystemTemplate->Id() == aId)
+ {
+ delete iSystemTemplate;
+ iSystemTemplate = NULL;
+ }
+ }
+
+
+/**
+Get the system template. If the system template does not yet exist then
+create it (lazy initialisation).
+
+@return CContactItem object reference for the system template.
+*/
+CContactItem& CCntTemplateCache::SystemTemplateL()
+ {
+ if (!iSystemTemplate)
+ {
+ CContactItemViewDef* matchAll = CContactItemViewDef::NewLC( CContactItemViewDef::EMaskFields,
+ CContactItemViewDef::EIncludeHiddenFields);
+ iSystemTemplate = static_cast<CContactItem*>(iCntSvr.ReadContactL(matchAll, KGoldenTemplateId));
+ CleanupStack::PopAndDestroy(matchAll);
+ }
+
+ return *iSystemTemplate;
+ }
+
+
+/**
+Dispose of the system template. The next time the system template is accessed
+via the SystemTemplateL() method it will be fetched from the Server.
+*/
+void CCntTemplateCache::ResetSystemTemplate()
+ {
+ delete iSystemTemplate;
+ iSystemTemplate = NULL;
+ }
+
+
+/**
+Get a template from the template cache with the given ID.
+
+@param Contact item ID of the template.
+
+@return CContactItem object reference for the template.
+*/
+CContactItem& CCntTemplateCache::TemplateL(TContactItemId aId)
+ {
+ if (aId == KGoldenTemplateId)
+ return SystemTemplateL();
+
+ CContactItem *retVal = NULL;
+ TInt maxCount = iCache.Count();
+ TInt ii = maxCount;
+
+ // Try to find the template in the cache.
+ while(ii)
+ {
+ --ii;
+ if (iCache[ii]->Id() == aId)
+ {
+ retVal = iCache[ii];
+ break; // Stop searching
+ }
+ }
+
+ if (!retVal) // Template does not exist in cache.
+ {
+ // Read the template from the Server.
+ CContactItemViewDef* matchAll = CContactItemViewDef::NewLC( CContactItemViewDef::EMaskFields,
+ CContactItemViewDef::EIncludeHiddenFields);
+ retVal = iCntSvr.ReadContactL(matchAll, aId);
+ CleanupStack::PopAndDestroy(matchAll);
+ if (maxCount == KMaxItemsInTemplateCache)
+ {
+ // Remove the first item from the cache (cache is maintained in
+ // using FIFO behaviour i.e. oldest template is removed when cache
+ // size is exceeded.
+ DeleteEntry(0);
+ }
+ iCache.Append(retVal);
+ }
+
+ return *retVal;
+ }
+
+
+/**
+Get the default view definition for the template cache. If the default view
+definition does not yet exist then create it (lazy initialisation).
+
+@return CContactItemViewDef object reference.
+
+@leave KErrNoMemory Out of memory.
+*/
+CContactItemViewDef& CCntTemplateCache::DefaultViewDefL()
+ {
+ if (!iViewDef)
+ {
+ iViewDef = CContactItemViewDef::NewL(CContactItemViewDef::EIncludeFields, CContactItemViewDef::EIncludeHiddenFields);
+ iViewDef->AddL(KUidContactFieldMatchAll);
+ }
+ return *iViewDef;
+ }
+
+
+/**
+Merge the given Contact Item with the template used to create the Contact Item.
+If no view definition is supplied then use the default view definition.
+
+@param aContact Contact Item to be merged with template.
+@param aViewDef View definition to use.
+*/
+void CCntTemplateCache::MergeWithTemplateL(CContactItem& aContact, const CContactItemViewDef* aViewDef)
+ {
+ if (aContact.TemplateRefId()!= KNullContactId && aContact.Type() != KUidContactCardTemplate)
+ {
+ CContactItemViewDef* viewDef = NULL;
+ if(aViewDef == NULL) // Only create a viewDef if none has been given.
+ {
+ viewDef = &(DefaultViewDefL());
+ }
+ else
+ {
+ viewDef = const_cast<CContactItemViewDef*>(aViewDef);
+ }
+
+ // Restore template fields.
+ if (aContact.TemplateRefId() != KNullContactId && aContact.Type() != KUidContactCardTemplate)
+ {
+ // Get the template ID used to create the Contact Item.
+ CContactItem* contactTemplate=&(static_cast<CContactTemplate&>(TemplateL(aContact.TemplateRefId())));
+ aContact.RestoreTemplateFieldsL(SystemTemplateL().CardFields(), contactTemplate->CardFields(), const_cast<CContactItemViewDef&> (*viewDef));
+ }
+ }
+ else if (aContact.Type()==KUidContactCardTemplate)
+ {
+ aContact.AddLabelFieldL();
+ }
+ }
+
+
+/**
+CPrivConverter object factory.
+
+@param aImplementationUid UID of the converter plugin.
+
+@return CPrivConverter object.
+*/
+CPrivConverter* CPrivConverter::NewL(TUid aImplementationUid)
+ {
+ CPrivConverter* self=new(ELeave) CPrivConverter;
+ CleanupStack::PushL(self);
+ CVersitTlsData::VersitTlsDataL();
+ self->LoadEComPluginL(aImplementationUid);
+ CleanupStack::Pop(self);
+ return self;
+ }
+/**
+CPrivConverter object factory.
+Loads PBAP contact converter plug-in.
+@param aImplementationUid UID of the converter plugin.
+@param aContactFieldFilter Specifies contact fields to be exported.
+@param aCallback Callback to client for providing intra-contact properties.
+@param aVersion Denotes the vCard version for contact export.
+@return CPrivConverter object.
+*/
+CPrivConverter* CPrivConverter::NewL(TUid aUid, TInt64 aContactFieldFilter, MConverterCallBack* aCallback, TVCardVersion aVersion, TBool aExportTel)
+ {
+ CPrivConverter* self = new(ELeave) CPrivConverter;
+ CleanupStack::PushL(self);
+ CVersitTlsData::VersitTlsDataL();
+ self->LoadEComPluginL(aUid, aContactFieldFilter, aCallback, aVersion, aExportTel);
+ CleanupStack::Pop(self);
+ return self;
+ }
+
+TInt64 CPrivConverter::GetPBAPFilter() const
+ {
+ return iPBAPFilter;
+ }
+
+TBool CPrivConverter::GetExportTel() const
+ {
+ return iExportTel;
+ }
+
+TVCardVersion CPrivConverter::GetCurrentVersion() const
+ {
+ return iVersion;
+ }
+
+/**
+CPrivConverter destructor.
+*/
+CPrivConverter::~CPrivConverter()
+ {
+ delete iConverter;
+ CVersitTlsData::CloseVersitTlsData();
+ }
+
+
+/**
+Load the ECOM plugin with the given UID.
+
+@param aUid UID of the plugin.
+@param aContactFieldFilter Specifies contact fields to be exported.
+@param aCallback Callback to client for providing intra-contact properties.
+@param aVersion Denotes the vCard version for contact export.
+*/
+void CPrivConverter::LoadEComPluginL(TUid aUid, TInt64 aContactFieldFilter, MConverterCallBack* aCallback, TVCardVersion aVersion, TBool aExportTel)
+ {
+ if(IsImplementationAvailableL(aUid))
+ {
+ iVersion = aVersion;
+ iPBAPFilter = aContactFieldFilter;
+ iExportTel = aExportTel;
+ iConverter = CContactEcomConverter::NewL(aUid, aContactFieldFilter, aCallback, aVersion, aExportTel);
+ }
+ __ASSERT_DEBUG(ETrue, User::Invariant());
+ }
+
+/**
+Load the ECOM plugin with the given UID.
+
+@param aUid UID of the plugin.
+*/
+void CPrivConverter::LoadEComPluginL(TUid aUid)
+ {
+ if(IsImplementationAvailableL(aUid))
+ {
+ iVersion = EVCard21;
+ iConverter = CContactEcomConverter::NewL(aUid);
+ }
+ __ASSERT_DEBUG(ETrue, User::Invariant());
+ }
+
+/**
+Finds out if implementation for a given plug-in uid is present as part of vCard Interface.
+
+@param aUid UID of the plugin.
+@return TBool ETrue if implementation exists.
+
+@leave KErrNoMemory
+@leave KErrNotConnected
+@leave KErrArgument
+
+*/
+TBool CPrivConverter::IsImplementationAvailableL(TUid aUid)
+ {
+ RImplInfoPtrArray implInfoArray;
+ CleanupResetAndDestroyPushL(implInfoArray);
+
+ REComSession::ListImplementationsL(KUidEcomCntVCardConverterInterface, implInfoArray);
+
+ // Check that aImplementationUid is an implementation of
+ // KUidEcomCnVCardConverterInterface by checking it is included in
+ // implInfoArray.
+ const TInt count = implInfoArray.Count();
+ __ASSERT_ALWAYS( count > 0, User::Leave(KErrNotFound));
+
+ TBool isAvailable = EFalse;
+
+ for(TInt i = 0 ; i < count ; ++i)
+ {
+ if( aUid == implInfoArray[i]->ImplementationUid())
+ {
+ switch(aUid.iUid)
+ {
+ case KUidVCardConvDefaultImpl:
+ isAvailable = ETrue;
+ break;
+ case KUidPBAPVCardConvImpl:
+ isAvailable = ETrue;
+ break;
+ default:
+ break;
+ }
+ break;
+ }
+ }
+ CleanupStack::PopAndDestroy(&implInfoArray);
+
+ return isAvailable;
+ }
+
+/**
+CContactPlugin constructor.
+*/
+CContactPlugin::CContactPlugin()
+ {
+ }
+
+/**
+CContactPlugin destructor.
+*/
+CContactPlugin::~CContactPlugin()
+ {
+ iDll.Close();
+ }
+
+
+/**
+Initialise this TSortPref object from the given stream.
+
+@param aStream Stream to read TSortPref object state from.
+*/
+EXPORT_C void CContactDatabase::TSortPref::InternalizeL(RReadStream& aStream)
+ {
+ iFieldType.iUid=aStream.ReadInt32L();
+ iOrder=STATIC_CAST(CContactDatabase::TSortPref::TOrder,aStream.ReadInt32L());
+ }
+
+/**
+Store this TSortPref object in the given stream.
+
+@param aStream Stream to write TSortPref object state to.
+*/
+EXPORT_C void CContactDatabase::TSortPref::ExternalizeL(RWriteStream& aStream) const
+ {
+ aStream.WriteInt32L(iFieldType.iUid);
+ aStream.WriteInt32L(iOrder);
+ }
+
+
+/**
+Determine if the asynchronous find is complete.
+
+@return ETrue If asynchronous find is complete, EFalse otherwise.
+*/
+EXPORT_C TBool CIdleFinder::IsComplete() const
+/** Checks whether the contact database search is complete.
+@return ETrue if search is complete, otherwise EFalse. */
+ {
+ return(iContactDatabase==NULL);
+ }
+
+
+/**
+Get and take ownership of the Contact IDs.
+
+@return Array of Contact IDs.
+*/
+EXPORT_C CContactIdArray* CIdleFinder::TakeContactIds()
+/** Gets an array of contact item IDs where the match is found.
+@return Array of contact item IDs. */
+ {
+ iOwnsIds=EFalse;
+ return(iIdsFound);
+ }
+
+
+/**
+Get the last asynchronous find error.
+
+@return The last asynchronous find error.
+*/
+EXPORT_C TInt CIdleFinder::Error() const
+/** Signals an error while searching the database.
+@return The error code, if any error occurs during the search operation. */
+ {
+ return iError;
+ }
+
+
+/**
+CIdleFinder constructor.
+*/
+CIdleFinder::CIdleFinder(CContactDatabase &aContactDatabase, const CContactItemFieldDef *aFieldDef, const CContactTextDef* aTextDef, MIdleFindObserver *aObserver)
+ :
+ CIdle(CActive::EPriorityIdle),
+ iContactDatabase(&aContactDatabase),
+ iFieldDef(aFieldDef),
+ iTextDef(aTextDef),
+ iObserver(aObserver)
+ {
+ }
+
+
+/**
+CIdleFinder destructor.
+*/
+CIdleFinder::~CIdleFinder()
+ {
+ // Only delete the found Contact IDs if ownership has not been taken with
+ // a call to TakeContactIds().
+ if (iOwnsIds)
+ {
+ delete iIdsFound;
+ }
+ delete iFindWords;
+ }
+
+
+void CIdleFinder::DoCancel()
+ {
+ // Setting to NULL indicates complete.
+ iContactDatabase=NULL;
+ }
+
+
+/**
+CIdleFinder object factory. This form of NewL() should be used when performing
+an asynchronous find using text and a field definition.
+
+@return CIdleFinder object.
+*/
+CIdleFinder* CIdleFinder::NewL(CContactDatabase &aContactDatabase, const TDesC& aText, const CContactItemFieldDef *aFieldDef, MIdleFindObserver *aObserver)
+ {
+ CIdleFinder *finder=new(ELeave) CIdleFinder(aContactDatabase, aFieldDef,NULL,aObserver);
+ CleanupStack::PushL(finder);
+ finder->ConstructL(&aText,NULL,NULL);
+ CleanupStack::Pop(); // finder
+ return(finder);
+ }
+
+
+/**
+CIdleFinder object factory. This form of NewL() should be used when performing
+an asynchronous find using "find words"/"find words parser" and a text
+definition.
+
+@return CIdleFinder object.
+*/
+CIdleFinder* CIdleFinder::NewL(CContactDatabase &aContactDatabase, const MDesCArray* aFindWords,const CContactTextDef* aTextDef, MIdleFindObserver *aObserver, const TCallBack &aWordParserCallback)
+ {
+ CIdleFinder *finder=new(ELeave) CIdleFinder(aContactDatabase,NULL,aTextDef,aObserver);
+ CleanupStack::PushL(finder);
+ finder->ConstructL(NULL,aFindWords,&aWordParserCallback);
+ CleanupStack::Pop(); // finder
+ return(finder);
+ }
+
+
+/**
+Set the CIdle object going.
+*/
+void CIdleFinder::Start()
+ {
+ CIdle::Start(TCallBack(CIdleFinder::CallbackL, this));
+ }
+
+
+TInt CIdleFinder::CallbackL(TAny *aSelf)
+ {
+ return ((CIdleFinder *)aSelf)->doFindL();
+ }
+
+
+TInt CIdleFinder::RunError(TInt aError)
+ {
+ iError = aError;
+ iContactDatabase = NULL;
+ if (iObserver)
+ {
+ iObserver->IdleFindCallback();
+ }
+ return KErrNone;
+ }
+
+
+/**
+CIdle callback method. Makes an IPC call into the Server to perform a find
+iteration.
+
+On return from the find iteration from the Server if "find words" were
+specified when initialising the find then the client supplied "find words
+parser" is invoked to search the returned Contact IDs. The search cannot be
+performed on the server because it is not possible to provide the client
+supplied callback to the server.
+
+@return ETrue if further find iterations are required otherwise EFalse.
+*/
+TBool CIdleFinder::doFindL()
+ {
+ iError = KErrNone;
+ TBool moreToGo = EFalse;
+ iOwnsIds = ETrue;
+
+ // Perform a find iteration in the Server.
+ TRAP(iError, moreToGo = iContactDatabase->iCntSvr->FindAsyncL(iIdsFound));
+
+ if (iError != KErrNone)
+ {
+ CContactIdArray* newIdArray = CContactIdArray::NewLC();
+ CleanupStack::Pop(newIdArray);
+ delete iIdsFound;
+ iIdsFound = newIdArray;
+ }
+
+ if(iFindWords != NULL)
+ {
+ // Construct a new Contacts ID array by calling CheckFindL(). This
+ // method then calls ScanForMatchL() which calls the client's function
+ // pointer (supplied when the find was initialised) for the "find
+ // words parser".
+ CContactIdArray* newIdArray = CContactIdArray::NewLC();
+ for(TInt i=0;i<iIdsFound->Count();++i)
+ {
+ if(CheckFindL((*iIdsFound)[i]))
+ {
+ newIdArray->AddL((*iIdsFound)[i]);
+ }
+ }
+ CleanupStack::Pop(newIdArray);
+
+ // Dispose of the existing found Contacts IDs and replace with the fully
+ // filtered Contacts IDs.
+ delete iIdsFound;
+ iIdsFound = newIdArray;
+ }
+
+ if(!moreToGo)
+ {
+ // Set to NULL to indicate complete.
+ iContactDatabase=NULL;
+ }
+
+ if (iObserver)
+ {
+ iObserver->IdleFindCallback();
+ }
+
+ return moreToGo;
+ }
+
+
+NONSHARABLE_CLASS(TKeyCmpTextLength) : public TKeyArrayFix
+ {
+public:
+ TKeyCmpTextLength();
+protected:
+ // From TKey.
+ virtual TInt Compare(TInt aLeft,TInt aRight) const;
+ };
+
+
+TKeyCmpTextLength::TKeyCmpTextLength()
+ :
+ // Doesn't matter using ECmpNormal, it's ignored.
+ TKeyArrayFix(0,ECmpNormal,0)
+ {
+ }
+
+
+/**
+Compare the lengths of the words.
+*/
+TInt TKeyCmpTextLength::Compare(TInt aLeft,TInt aRight) const
+ {
+ TDesC* left=(*((TDesC**)At(aLeft)));
+ TDesC* right=(*((TDesC**)At(aRight)));
+ return right->Length()-left->Length();
+ }
+
+
+/**
+Initialise and start the asynchronous find.
+*/
+void CIdleFinder::ConstructL(const TDesC *aText, const MDesCArray* aFindWords, const TCallBack *aWordParserCallback)
+ {
+ if(aFindWords != NULL) // Find using a CContactTextDef.
+ {
+ // Construct "find words" from the client supplied aFindWords.
+ iFindWords = new (ELeave) CDesCArrayFlat(5);
+ for(TInt loop=0;loop<aFindWords->MdcaCount();loop++)
+ {
+ // Construct iFindWords which contains all the strings in the search
+ // surrounded by a *.
+ TPtrC findWord(aFindWords->MdcaPoint(loop));
+ TKeyCmpTextLength key;
+ HBufC* bufPtr=findWord.AllocLC();
+ iFindWords->CArrayFixBase::InsertIsqAllowDuplicatesL(&bufPtr,key);
+ CleanupStack::Pop(); // bufPtr
+ }
+
+ // This is the client supplied "find words parser" callback method.
+ iWordParserCallback = *aWordParserCallback;
+
+ // Initialise the asynchronous find in the Server.
+ iContactDatabase->iCntSvr->FindAsyncTextDefInitL(*iFindWords,const_cast<CContactTextDef*>(iTextDef));
+ }
+ else // Find using text and a CContactItemFieldDef.
+ {
+ // Initialise the asynchronous find in the Server.
+ iContactDatabase->iCntSvr->FindAsyncInitL(*aText,const_cast<CContactItemFieldDef*>(iFieldDef));
+ }
+
+ // Start the asynchronous find.
+ CActiveScheduler::Add(this);
+ Start();
+ }
+
+
+class TFoundMatch
+ {
+public:
+ inline TFoundMatch(TFieldType aFieldType,TInt aPos) : iFieldType(aFieldType),iPos(aPos) {};
+ inline TBool operator==(const TFoundMatch &aMatch) const;
+
+private:
+ TFieldType iFieldType;
+ TInt iPos;
+ };
+
+
+inline TBool TFoundMatch::operator==(const TFoundMatch &aMatch) const
+ {
+ return(aMatch.iFieldType==iFieldType && aMatch.iPos==iPos);
+ }
+
+
+/**
+List of matches.
+*/
+class CFoundMatches : public CArrayFixFlat<TFoundMatch>
+ {
+public:
+ inline CFoundMatches() : CArrayFixFlat<TFoundMatch>(8) {};
+ inline void SetCurrentMatchField(TFieldType aFieldType) {iFieldType=aFieldType;};
+ TBool AddMatchL(TInt aPos);
+
+private:
+ TFieldType iFieldType;
+ };
+
+
+TBool CFoundMatches::AddMatchL(TInt aPos)
+ {
+ TFoundMatch newMatch(iFieldType,aPos);
+ for(TInt loop=0;loop<Count();loop++)
+ {
+ if (At(loop)==newMatch)
+ {
+ return(EFalse);
+ }
+ }
+ AppendL(newMatch);
+ return(ETrue);
+ }
+
+
+TBool CIdleFinder::ScanForMatchL(const TDesC &aFieldText,const TDesC &aFindText, CFoundMatches *aFoundMatches) const
+ {
+ CDesCArray *wordArray=new(ELeave) CDesCArrayFlat(10);
+ CleanupStack::PushL(wordArray);
+
+ SFindInTextDefWordParser parser(&aFieldText,wordArray);
+ (*iWordParserCallback.iFunction)(&parser);
+
+ TBool matched=EFalse;
+
+ TInt findLen=aFindText.Length();
+
+ for(TInt loop=0;loop<wordArray->Count();loop++)
+ {
+ TPtrC fieldWord((*wordArray)[loop]);
+ if (findLen<=fieldWord.Length() && fieldWord.Left(findLen).CompareF(aFindText)==0)
+ {
+ if (aFoundMatches->AddMatchL(loop))
+ {
+ matched=ETrue;
+ break;
+ }
+ }
+ }
+
+ CleanupStack::PopAndDestroy(); // wordArray
+
+ return(matched);
+ }
+
+
+/**
+Use the client supplied "find words parser" to check for a match of the "find
+words" within the text fields in the given Contact Item.
+
+@param aContactID Contact Item to check for match.
+*/
+TBool CIdleFinder::CheckFindL(TContactItemId aContactId) const
+ {
+ // If iTextDef is NULL can't check so return EFalse to indicate no match.
+ if (!iTextDef)
+ {
+ return(EFalse);
+ }
+
+ // Use ReadMininalContactLC() to read the Contact Item. We don't need the
+ // template and groups data for the find check.
+ CContactItem* item = iContactDatabase->ReadMinimalContactLC(aContactId);
+ const CContactItemFieldSet& fieldSet = item->CardFields();
+
+ TBool found=ETrue;
+ CFoundMatches *foundWords=new(ELeave) CFoundMatches;
+ CleanupStack::PushL(foundWords);
+
+ // Iterate through iFindWords.
+ for(TInt searchWord=0;found && searchWord<iFindWords->Count();searchWord++)
+ {
+ const TPtrC findMe((*iFindWords)[searchWord]);
+ TBool foundInTextDef=EFalse;
+
+ // Iterate through iTextDef field types then fallback field type.
+ for(TInt loop=0;!foundInTextDef && loop<=iTextDef->Count();loop++)
+ {
+ TFieldType fieldType;
+
+ if (loop==iTextDef->Count())
+ {
+ fieldType=iTextDef->FallbackField();
+ }
+ else
+ {
+ fieldType=(*iTextDef)[loop].iFieldType;
+ }
+
+ // If field type is KUidContactFieldNone, skip this field.
+ if (fieldType==KUidContactFieldNone)
+ {
+ continue;
+ }
+
+ TBuf<KTextFieldMinimalLength> textFieldMin;
+
+ // While that field type is found in the Contact Item field text...
+ TInt pos=0;
+ while (pos!=KErrNotFound)
+ {
+ // Get the field text for this field type.
+ pos=fieldSet.FieldText(fieldType,textFieldMin,pos);
+
+ // Scan for match in this field text.
+ foundWords->SetCurrentMatchField(fieldType);
+ if (ScanForMatchL(textFieldMin,findMe,foundWords))
+ {
+ foundInTextDef=ETrue;
+ break;
+ }
+ if (pos!=KErrNotFound)
+ {
+ pos++;
+ }
+ }
+ }
+
+ // If there wasn't a match then set found to EFalse.
+ if (!foundInTextDef)
+ {
+ found=EFalse;
+ }
+ }
+
+ CleanupStack::PopAndDestroy(2,item); // + foundWords
+
+ return(found);
+ }
+
+
+/**
+Reserved (private) virtual function to allow further extension of the
+MContactSynchroniser interface without requiring changes to all derived classes.
+This can be used to return a pointer to an additional extension class.
+*/
+EXPORT_C void MContactSynchroniser::MContactSynchroniser_Reserved_1()
+ {
+ }
+
+
+EXPORT_C CContactSynchroniser::~CContactSynchroniser()
+ {
+ REComSession::DestroyedImplementation(iDtor_ID_Key);
+ }
+
+
+/**
+Panic the current thread with CNTMODEL as the category
+*/
+GLDEF_C void Panic(TCntModelPanic aPanic)
+ {
+ User::Panic(_L("CNTMODEL"),aPanic);
+ }
+
+
+#ifdef __VC32__
+extern "C" void __E32Dll(void)
+ {
+ }
+#endif
+
+
+/**
+ Standard Epoc32 DLL entry point.
+*/
+#ifndef EKA2
+GLDEF_C TInt E32Dll(TInt /*aReason*/)
+ {
+ return KErrNone;
+ }
+#endif