phonebookengines/contactsmodel/cntplsql/src/cplcollectioniterator.cpp
branchRCL_3
changeset 63 f4a778e096c2
child 64 c1e8ba0c2b16
equal deleted inserted replaced
62:5b6f26637ad3 63:f4a778e096c2
       
     1 // Copyright (c) 2007-2009 Nokia Corporation and/or its subsidiary(-ies).
       
     2 // All rights reserved.
       
     3 // This component and the accompanying materials are made available
       
     4 // under the terms of "Eclipse Public License v1.0"
       
     5 // which accompanies this distribution, and is available
       
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     7 //
       
     8 // Initial Contributors:
       
     9 // Nokia Corporation - initial contribution.
       
    10 //
       
    11 // Contributors:
       
    12 //
       
    13 // Description:
       
    14 //
       
    15 
       
    16 /**
       
    17  @file
       
    18  @internalComponent
       
    19  @released
       
    20 */
       
    21 
       
    22 #include "persistencelayerimpl.h"
       
    23 #include "clplcontactproperties.h"
       
    24 #include <cntfilt.h>
       
    25 #include "cntsqlprovider.h"
       
    26 #include "dbsqlconstants.h"
       
    27 #include "cntpersistenceutility.h"
       
    28 #include "CNTSTD.H"
       
    29 #include <sqldb.h>
       
    30 
       
    31 //
       
    32 // The TFindFieldFlags enumeration is duplicated in cviewiterator.h.  It should
       
    33 // be refactored into a shared header if possible.
       
    34 //
       
    35 enum TFindFieldFlags
       
    36 	{
       
    37 	EFindInAllFields				=0x00000001,
       
    38 	EFindFirstName					=0x00000002,
       
    39 	EFindLastName					=0x00000004,
       
    40 	EFindCompanyName				=0x00000008,
       
    41 	EFindInEmailField				=0x00000010,
       
    42 	EFindInAnyIdentityField			=0x00000020,
       
    43 	EFindFirstNamePronunciation		=0x00000040,
       
    44 	EFindLastNamePronunciation		=0x00000080,
       
    45 	EFindCompanyNamePronunciation	=0x00000100,
       
    46 	EFindInSIPField					=0x00000200
       
    47 	};
       
    48 
       
    49 
       
    50 // Maximum number of find iterations to perform in the CPlCollection::FindL()
       
    51 // method before returning.
       
    52 const TInt KFindIterations = 16;
       
    53 
       
    54 // These flags must be in the same order as the corresponding fields in
       
    55 // RPplIdentityTable::TIdentityField.
       
    56 const TFindFieldFlags KNameFlags[] = 
       
    57 	{
       
    58 	EFindFirstName,
       
    59 	EFindLastName,
       
    60 	EFindCompanyName,
       
    61 	EFindFirstNamePronunciation,
       
    62 	EFindLastNamePronunciation,
       
    63 	EFindCompanyNamePronunciation
       
    64 	};
       
    65 
       
    66 // Collation level that ignore accents (i.e. a == &auml; ).
       
    67 const TInt KCollationLevel= 0;
       
    68 
       
    69 //
       
    70 // The TKeyCmpTextLength class is duplicated in ccontactprivate.cpp.  It should
       
    71 // be refactored into shared code/library if possible.
       
    72 //
       
    73 NONSHARABLE_CLASS(TKeyCmpTextLength) : public TKeyArrayFix
       
    74 	{
       
    75 public:
       
    76 	TKeyCmpTextLength();
       
    77 protected:
       
    78 	// From TKey.
       
    79 	virtual TInt Compare(TInt aLeft,TInt aRight) const;
       
    80 	};
       
    81 
       
    82 
       
    83 TKeyCmpTextLength::TKeyCmpTextLength()
       
    84 	// Doesn't matter using ECmpNormal, it's ignored.
       
    85 	:
       
    86 	TKeyArrayFix(0,ECmpNormal,0)
       
    87 	{
       
    88 	}
       
    89 
       
    90 
       
    91 /**
       
    92 Compare the lengths of the words.
       
    93 */
       
    94 TInt TKeyCmpTextLength::Compare(TInt aLeft,TInt aRight) const
       
    95 	{
       
    96 	TDesC* left=(*((TDesC**)At(aLeft)));
       
    97 	TDesC* right=(*((TDesC**)At(aRight)));
       
    98 	return right->Length()-left->Length();
       
    99 	}
       
   100 
       
   101 	
       
   102 /**
       
   103 Used as a cleanup item for buffer allocation in CreateFindTextL().
       
   104 
       
   105 @param aHBufC The buffer to be cleaned up (deleted).
       
   106 */
       
   107 GLDEF_C void DestroyHBufC(TAny* aHBufC)
       
   108 	{
       
   109 	delete *STATIC_CAST(HBufC**, aHBufC);
       
   110 	}
       
   111 
       
   112 
       
   113 /**
       
   114 Create the "find text", used for the SQL query on the view, from the given text.
       
   115 
       
   116 @param aText Text to turn into "find text".
       
   117 
       
   118 @return "Find text" form of the given text.
       
   119 */
       
   120 HBufC* CreateFindTextL(const TDesC& aText)
       
   121 	{
       
   122 	_LIT(KApostrophe, "'");
       
   123 	TInt location = aText.Find(KApostrophe);
       
   124 
       
   125 	HBufC* buf=HBufC::NewL(aText.Length()+2);
       
   126 	TPtr ptr=buf->Des();
       
   127 	ptr.Zero();
       
   128 	ptr.Append('%');
       
   129 	ptr += aText;
       
   130 	ptr.Append('%');
       
   131 	
       
   132 	// Insert additional apostrophes if required.  This is so the SQL search
       
   133 	// string behaves correctly.
       
   134 	if(location != KErrNotFound)
       
   135 		{
       
   136 		CleanupStack::PushL(buf);
       
   137 
       
   138 		TPtrC rightBuf = *buf;		
       
   139 		HBufC* leftBuf=HBufC::NewL(0);
       
   140 		CleanupStack::PushL(TCleanupItem(DestroyHBufC, &leftBuf));
       
   141 
       
   142 		// Increment location because we have added the * character.
       
   143 		location++;
       
   144 		
       
   145 		while (location != KErrNotFound)
       
   146 			{
       
   147 			// Copy left hand string up to the first apostrophe into a new
       
   148 			// buffer and append an apostrophe.
       
   149 			leftBuf = leftBuf->ReAllocL(leftBuf->Length()+location+2); 
       
   150 			TPtr ptrLeftBuf = leftBuf->Des();
       
   151 			ptrLeftBuf.Append(rightBuf.Left(location+1));
       
   152 			ptrLeftBuf += (KApostrophe);
       
   153 
       
   154 			// Make a copy of the right hand part.
       
   155 			TInt rightLength = rightBuf.Length()-location-1;
       
   156 			rightBuf.Set(rightBuf.Right(rightLength));
       
   157 			
       
   158 			// Search for another apostrophe.
       
   159 			location = rightBuf.Find(KApostrophe);
       
   160 			}
       
   161 		
       
   162 		// Now append the rest of the right hand part.
       
   163 		leftBuf = leftBuf->ReAllocL(leftBuf->Length()+rightBuf.Length()); 
       
   164 		TPtr ptrLeftBuf = leftBuf->Des();
       
   165 		ptrLeftBuf.Append(rightBuf);
       
   166 
       
   167 		CleanupStack::Pop(&leftBuf);	
       
   168 		CleanupStack::PopAndDestroy(buf);
       
   169 		
       
   170 		return (leftBuf);
       
   171 		}	
       
   172 	
       
   173 	return (buf);	
       
   174 	}
       
   175 
       
   176 
       
   177 /**
       
   178 For the given field type UID, increase aIdentityColumnsCount if the field maps
       
   179 to one of the columns in the Identity table and add the relevant find flag.
       
   180 
       
   181 @param aUid Field type UID.
       
   182 @param aFindFlags Updated with find flag which maps to the given field type UID.
       
   183 @param aIdentityColumnsCount Incremented if the field type UID maps to a column
       
   184 in the Identity table.
       
   185 */
       
   186 //
       
   187 // This method is duplicated in cviewiterator.cpp.  It should be refactored into
       
   188 // shared code/library if possible.
       
   189 //
       
   190 void SetFindFlagsAndColumnsCount(TInt32 aUid,TInt& aFindFlags,TInt& aIdentityColumnsCount)
       
   191 	{
       
   192 	switch(aUid)
       
   193 		{
       
   194 		case KUidContactFieldGivenNameValue:
       
   195 			{
       
   196 			++aIdentityColumnsCount;
       
   197 			aFindFlags |= EFindFirstName;
       
   198 			break;
       
   199 			}
       
   200 		case KUidContactFieldFamilyNameValue:
       
   201 			{
       
   202 			++aIdentityColumnsCount;
       
   203 			aFindFlags |= EFindLastName;
       
   204 			break;
       
   205 			}
       
   206 		case KUidContactFieldCompanyNameValue:
       
   207 			{
       
   208 			++aIdentityColumnsCount;
       
   209 			aFindFlags |= EFindCompanyName;
       
   210 			break;
       
   211 			}
       
   212 		case KUidContactFieldGivenNamePronunciationValue:
       
   213 			{
       
   214 			++aIdentityColumnsCount;
       
   215 			aFindFlags |= EFindFirstNamePronunciation;
       
   216 			break;
       
   217 			}
       
   218 		case KUidContactFieldFamilyNamePronunciationValue:
       
   219 			{
       
   220 			++aIdentityColumnsCount;
       
   221 			aFindFlags |= EFindLastNamePronunciation;
       
   222 			break;
       
   223 			}
       
   224 		case KUidContactFieldCompanyNamePronunciationValue:
       
   225 			{
       
   226 			++aIdentityColumnsCount;
       
   227 			aFindFlags |= EFindCompanyNamePronunciation;
       
   228 			break;
       
   229 			}
       
   230 		case KUidContactFieldEMailValue:
       
   231 			{
       
   232 			aFindFlags |= EFindInEmailField;
       
   233 			break;
       
   234 			}
       
   235 		case KUidContactFieldSIPIDValue:
       
   236 			{
       
   237 			aFindFlags |= EFindInSIPField;
       
   238 			break;			
       
   239 			}
       
   240 		case KUidContactFieldMatchAllValue:
       
   241 			{
       
   242 			//added to address issues raised in INC049017
       
   243 			//needed as a seperate case instead of modifying the default value because Identitys should not always be searched
       
   244 			//if a valid KUid is used. e.g.: KUidContactFieldAddress. If the default value was modified and someone wanted to
       
   245 			//perform an address search using Elizabeth (as in elizabeth road) contacts of that name would also be found.
       
   246 			aFindFlags |= EFindInAllFields|EFindInAnyIdentityField;
       
   247 			break;
       
   248 			}
       
   249 		default:
       
   250 			aFindFlags |= EFindInAllFields;
       
   251 		}
       
   252 	}
       
   253 
       
   254 
       
   255 /**
       
   256 Determine if the Identity table requires to be searched for the given find
       
   257 flags.
       
   258 
       
   259 @param aFindFlags Set of find flags describing which fields will be searched.
       
   260 
       
   261 @return ETrue If one of the flags in aFindFlags maps to a column in the Identity
       
   262 table, EFalse otherwise.
       
   263 */
       
   264 //
       
   265 // This method is duplicated in cviewiterator.cpp.  It should be refactored into
       
   266 // shared code/library if possible.
       
   267 //
       
   268 TBool SearchIdentityFieldsRequired(TInt aFindFlags)
       
   269 	{
       
   270 	return aFindFlags &
       
   271 		( EFindInAnyIdentityField | EFindFirstName | EFindLastName | EFindCompanyName |
       
   272 			EFindFirstNamePronunciation | EFindLastNamePronunciation | EFindCompanyNamePronunciation);
       
   273 	}
       
   274 
       
   275 
       
   276 /**
       
   277 Determine if only the Identity table requires to be searched for the given find
       
   278 flags.
       
   279 
       
   280 @param aFindFlags Set of find flags describing which fields will be searched.
       
   281 
       
   282 @return ETrue If one of the flags in aFindFlags maps to a column in the Identity
       
   283 table and no columns in any other table, EFalse otherwise.
       
   284 */
       
   285 //
       
   286 // This method is duplicated in cviewiterator.cpp.  It should be refactored into
       
   287 // shared code/library if possible.
       
   288 //
       
   289 TBool CPlCollection::UsesIdentityFieldsOnly(TInt aFindFlags)
       
   290 	{
       
   291 	return (aFindFlags & (EFindFirstName | EFindLastName | EFindCompanyName |
       
   292 			EFindFirstNamePronunciation |EFindLastNamePronunciation |EFindCompanyNamePronunciation) ) &&
       
   293 		! (aFindFlags & (EFindInAllFields | EFindInEmailField | EFindInSIPField) );
       
   294 	}
       
   295 
       
   296 
       
   297 /**
       
   298 Update a set of find flags and an Identity table column count from the field
       
   299 type UIDs in the given field definition.
       
   300 
       
   301 @param aFindFlags Updated with those flags which map to the field type UIDs in
       
   302 aFieldDef.
       
   303 @param aIdentityColumnsCount Updated with the number of field type UIDs in
       
   304 aFieldDef which map to columns in the Identity table.
       
   305 @param aFieldDef Field definition from which to create set of find flags and
       
   306 Identity table column count.
       
   307 */
       
   308 //
       
   309 // This method is duplicated in cviewiterator.cpp.  It should be refactored into
       
   310 // shared code/library if possible.
       
   311 //
       
   312 void ConstructBitwiseFindFlags(TInt& aFindFlags,TInt& aIdentityColumnsCount,const CContactItemFieldDef* aFieldDef)
       
   313 	{
       
   314 	if(aFieldDef!=NULL && aFieldDef->Count()>0)
       
   315 		{
       
   316 		for(TInt ii = 0;ii < aFieldDef->Count();ii++)
       
   317 			{
       
   318 			SetFindFlagsAndColumnsCount(aFieldDef->At(ii).iUid,aFindFlags,aIdentityColumnsCount);
       
   319 			}
       
   320 		}
       
   321 	else
       
   322 		{
       
   323 		aFindFlags |= EFindInAllFields|EFindInAnyIdentityField;
       
   324 		}
       
   325 	}
       
   326 
       
   327 
       
   328 /**
       
   329 Update a set of find flags and an Identity table column count from the field
       
   330 type UIDs in the given text definition.  This can be used to tell the find
       
   331 method what tables need to be searched for a given text definition.  If the text
       
   332 definition is NULL we search in all tables.
       
   333 
       
   334 @param aFindFlags Updated with those flags which map to the field type UIDs in
       
   335 aTextDef.
       
   336 @param aIdentityColumnsCount Updated with the number of field type UIDs in
       
   337 aTextDef which map to columns in the Identity table.
       
   338 @param aTextDef Text definition from which to create set of find flags and
       
   339 Identity table column count.
       
   340 */
       
   341 //
       
   342 // This method is duplicated in cviewiterator.cpp.  It should be refactored into
       
   343 // shared code/library if possible.
       
   344 //
       
   345 void CPlCollection::ConstructBitwiseFlagsFromTextDef(TInt& aFindFlags,TInt& aIdentityColumnsCount,const CContactTextDef* aTextDef)
       
   346 	{
       
   347 	if(aTextDef != NULL && aTextDef->Count()>0)
       
   348 		{
       
   349 		for(TInt ii = 0;ii < aTextDef->Count();ii++)
       
   350 			{
       
   351 			SetFindFlagsAndColumnsCount(aTextDef->At(ii).iFieldType.iUid,aFindFlags,aIdentityColumnsCount);
       
   352 			}
       
   353 		TFieldType fallback = aTextDef->FallbackField();
       
   354 		if (fallback != KUidContactFieldNone)
       
   355 		SetFindFlagsAndColumnsCount(fallback.iUid,aFindFlags,aIdentityColumnsCount);
       
   356 		}
       
   357 	else
       
   358 		{
       
   359 		aFindFlags |= EFindInAllFields|EFindInAnyIdentityField;
       
   360 		}
       
   361 	}
       
   362 
       
   363 
       
   364 /**
       
   365 Utility method used to search a contact id in contact database.
       
   366 
       
   367 @param aReqId requested contact id to look for
       
   368 @param aId out parameter; will be filled with the actual found contact item id 
       
   369 @param aContactType specifies contact type to be search
       
   370 @param aDeleted set to ETrue if a search through deleted contacts is required
       
   371 
       
   372 @return ETrue if a contact item with contact id greater or equal with aReqId exists in contact database
       
   373 		EFalse otherwise
       
   374 */
       
   375 TBool CPlCollection::SeekContactL(TContactItemId aReqId,TContactItemId& aId,TUid& aContactType, TBool& aDeleted)
       
   376 	{
       
   377 	TBool ret = ETrue;
       
   378 
       
   379 	HBufC* selectString = HBufC::NewLC(KSelectTwoFieldsWithGreater().Length() + 
       
   380 									KContactId().Length() + 
       
   381 									KContactTypeFlags().Length() + 
       
   382 									KSqlContactTableName().Length() + 					
       
   383 									KContactId().Length() + 3); 
       
   384 	TPtr ptrSelectString = selectString->Des();
       
   385 	ptrSelectString.Format(KSelectTwoFieldsWithGreater, &KContactId, &KContactTypeFlags, &KSqlContactTableName, &KContactId, aReqId);
       
   386 
       
   387 	RSqlStatement selectStatement;
       
   388 	CleanupClosePushL(selectStatement);
       
   389 		
       
   390 	User::LeaveIfError(selectStatement.Prepare(iContactsFile.NamedDatabase(), ptrSelectString));
       
   391 
       
   392 	const TInt idIndex = selectStatement.ColumnIndex(KContactId);
       
   393 	User::LeaveIfError(idIndex);
       
   394 	const TInt typeIndex = selectStatement.ColumnIndex(KContactTypeFlags);
       
   395 	User::LeaveIfError(typeIndex);
       
   396 	TInt err;
       
   397 	if((err = selectStatement.Next()) == KSqlAtRow) 
       
   398 		{
       
   399 		aId = selectStatement.ColumnInt(idIndex);
       
   400 		TInt typeFlags = selectStatement.ColumnInt(typeIndex);
       
   401 		aContactType = TCntPersistenceUtility::TypeFlagsToContactTypeUid(typeFlags); 
       
   402 		TInt attr = (typeFlags & EContactAttributes_Mask) >> EContactAttributes_Shift; 
       
   403 		aDeleted = (attr == EContactAttrsFlags_Deleted);
       
   404 		}
       
   405 	else 
       
   406 		{
       
   407 		User::LeaveIfError(err);
       
   408 		ret = EFalse;	
       
   409 		}
       
   410 	
       
   411 	CleanupStack::PopAndDestroy(2, selectString); //selectStatement, selectString	
       
   412 	return ret;
       
   413 	}
       
   414 	
       
   415 /**
       
   416 CPlCollection constructor.
       
   417 
       
   418 @param aContactsFile Contacts file object from the Persistence Layer.
       
   419 */
       
   420 CPlCollection::CPlCollection(CPplContactsFile& aContactsFile)
       
   421 	: 
       
   422 	iContactsFile( aContactsFile ), iRSqlstatementsWorking( EFalse )
       
   423 	{
       
   424 	}
       
   425 	
       
   426 /**
       
   427 CPlCollection ConstructL
       
   428 */	
       
   429 void CPlCollection::ConstructL()
       
   430 	{
       
   431 	TCntSqlStatementType statementType(ESelect, KSqlContactTableName);
       
   432 	iSelectStatement = TSqlProvider::GetSqlStatementL(statementType);
       
   433 	}
       
   434 	
       
   435 /**
       
   436 CPlCollection NewL
       
   437 */		
       
   438 CPlCollection* CPlCollection::NewL(CPplContactsFile& aContactsFile)
       
   439 	{
       
   440 	CPlCollection* self = new (ELeave) CPlCollection(aContactsFile);
       
   441 	CleanupStack::PushL(self);
       
   442 	self->ConstructL();
       
   443 	CleanupStack::Pop(self);
       
   444 	return self;
       
   445 	}
       
   446 	
       
   447 
       
   448 /**
       
   449 CPlCollection destructor.
       
   450 */
       
   451 CPlCollection::~CPlCollection()
       
   452 	{
       
   453 	Reset();
       
   454 	delete iSelectStatement;
       
   455 	iSelectStatement = NULL;
       
   456 	}
       
   457 
       
   458 
       
   459 /**
       
   460 Get the count of contacts in the Contacts table.
       
   461 
       
   462 @return Count of contacts in the Contacts table.
       
   463 */
       
   464 TInt CPlCollection::ContactCountL()
       
   465 	{
       
   466 	TInt count = 0;
       
   467 
       
   468 	//count contact cards
       
   469 	HBufC* selectString = HBufC::NewLC(KCountTypeSelect().Length() + 
       
   470 						KSqlContactTableName().Length() + KContactTypeFlags().Length() + KContactTypeFlags().Length() + 6); 
       
   471 	TPtr ptrSelectString = selectString->Des();
       
   472 	ptrSelectString.Format(KCountTypeSelect, &KSqlContactTableName, &KContactTypeFlags, EContactType_Shift, EContactTypeFlags_ContactCard,
       
   473 							&KContactTypeFlags, EContactAttributes_Shift, EContactAttrsFlags_Deleted);
       
   474 
       
   475 	TSqlScalarFullSelectQuery scalarQuery(iContactsFile.NamedDatabase());
       
   476 	
       
   477 	count = scalarQuery.SelectIntL(ptrSelectString);
       
   478 	CleanupStack::PopAndDestroy(selectString);
       
   479 
       
   480 	//count own card
       
   481 	selectString = HBufC::NewLC(KCountTypeSelect().Length() + 
       
   482 				KSqlContactTableName().Length() + KContactTypeFlags().Length() + KContactTypeFlags().Length() + 6); 
       
   483 	ptrSelectString = selectString->Des();
       
   484 	ptrSelectString.Format(KCountTypeSelect, &KSqlContactTableName, &KContactTypeFlags, EContactType_Shift, EContactTypeFlags_OwnCard,
       
   485 							&KContactTypeFlags, EContactAttributes_Shift, EContactAttrsFlags_Deleted);
       
   486 	
       
   487 	count += scalarQuery.SelectIntL(ptrSelectString);
       
   488 	CleanupStack::PopAndDestroy(selectString);
       
   489 	
       
   490 	//count groups
       
   491 	selectString = HBufC::NewLC(KCountTypeSelect().Length() + 
       
   492 				KSqlContactTableName().Length() + KContactTypeFlags().Length() + KContactTypeFlags().Length() + 6); 
       
   493 	ptrSelectString = selectString->Des();
       
   494 	ptrSelectString.Format(KCountTypeSelect, &KSqlContactTableName, &KContactTypeFlags, EContactType_Shift, EContactTypeFlags_Group,
       
   495 							&KContactTypeFlags, EContactAttributes_Shift, EContactAttrsFlags_Deleted);
       
   496 	
       
   497 	count += scalarQuery.SelectIntL(ptrSelectString);
       
   498 	CleanupStack::PopAndDestroy(selectString);
       
   499 	
       
   500 	//card template
       
   501 	selectString = HBufC::NewLC(KCountTypeSelect().Length() + 
       
   502 				KSqlContactTableName().Length() + KContactTypeFlags().Length() + KContactTypeFlags().Length() + 6); 
       
   503 	ptrSelectString = selectString->Des();
       
   504 	ptrSelectString.Format(KCountTypeSelect, &KSqlContactTableName, &KContactTypeFlags, EContactType_Shift, EContactTypeFlags_CardTemplate,
       
   505 							&KContactTypeFlags, EContactAttributes_Shift, EContactAttrsFlags_Deleted);
       
   506 	
       
   507 	count += scalarQuery.SelectIntL(ptrSelectString);
       
   508 	CleanupStack::PopAndDestroy(selectString);
       
   509 			
       
   510 	return count;
       
   511 	}
       
   512 
       
   513 
       
   514 /**
       
   515 Get a collection of contact IDs using the specified view/collection parameters.
       
   516 
       
   517 @param aViewType Type of view/collection.
       
   518 @param aTime Used if view/collection type is "changed since".
       
   519 @param aGuid Used if view/collection type is "find GUID".
       
   520 
       
   521 @return Contact ID array of those contacts which match the specified collection
       
   522 parameters.
       
   523 */
       
   524 CContactIdArray* CPlCollection::CollectionL(TLplViewType aViewType,TTime aTime,const TDesC& aGuid)
       
   525 	{
       
   526 	CContactIdArray* idArray=NULL;
       
   527 	switch(aViewType)
       
   528 		{
       
   529 		case EChangedSince :
       
   530 			{
       
   531 			idArray = ChangedSinceL(aTime);
       
   532 			}
       
   533 			break;
       
   534 		case EDeleted :
       
   535 			{
       
   536 			idArray = DeletedL();
       
   537 			}
       
   538 			break;
       
   539 		case EUnfiled :
       
   540 			{
       
   541 			idArray = UnfiledL();
       
   542 			}
       
   543 			break;
       
   544 		case EFindGuid :
       
   545 			{
       
   546 			idArray = GuidL(aGuid);
       
   547 			}
       
   548 			break;
       
   549 		default:
       
   550 			{
       
   551 			User::Leave(KErrNotFound);
       
   552 			}
       
   553 			break;
       
   554 		}
       
   555 	return idArray;
       
   556 	}
       
   557 
       
   558 	
       
   559 /**
       
   560 Utility method used to serach hint field for provided contact id
       
   561 
       
   562 @param aBitWiseFileter filter used for hint matching
       
   563 @param aContactId contact item id
       
   564 
       
   565 @return ETrue if a hint is found 
       
   566 		EFalse otherwise
       
   567 */	
       
   568 TBool CPlCollection::ContactMatchesHintFieldL(TInt aBitWiseFilter, TContactItemId aContactId)
       
   569 	{
       
   570 	TBool hintMatch = EFalse;
       
   571 	
       
   572 	HBufC* searchCond = HBufC::NewLC(KConditionClause().Length() + KContactId().Length() + 32);
       
   573 	searchCond->Des().Format(KConditionClause, &KContactId, aContactId);
       
   574 
       
   575 	RSqlStatement selectStatement;
       
   576 	CleanupClosePushL(selectStatement);
       
   577 		
       
   578 	iSelectStatement->Reset();	
       
   579 	iSelectStatement->SetParamL(KContactId, KSpace);
       
   580 	iSelectStatement->SetParamL(KContactTypeFlagsParam, KSpace);
       
   581 	iSelectStatement->SetConditionL(*searchCond);
       
   582 	
       
   583 	User::LeaveIfError(selectStatement.Prepare(iContactsFile.NamedDatabase(), iSelectStatement->SqlStringL()));
       
   584 
       
   585 	TInt err;
       
   586 	if((err = selectStatement.Next()) == KSqlAtRow)
       
   587 		{
       
   588 		const TInt typeFlagsIndex = iSelectStatement->ParameterIndex(KContactTypeFlags);
       
   589 		TInt typeFlags = selectStatement.ColumnInt(typeFlagsIndex);
       
   590 		TUid contactType = TCntPersistenceUtility::TypeFlagsToContactTypeUid(typeFlags);
       
   591 		if (iContactsFile.ContactProperties().CheckType(contactType))
       
   592 			{
       
   593 			TInt hint = typeFlags & EContactHintFlags_Mask;
       
   594 			hintMatch = HintFieldMatchesFilter(hint, aBitWiseFilter);	
       
   595 			}
       
   596 		}
       
   597 	else
       
   598 		{
       
   599 		User::LeaveIfError(err);
       
   600 		}	
       
   601 	
       
   602 	CleanupStack::PopAndDestroy(2, searchCond); //searchCond, selectStatement
       
   603 	return hintMatch;
       
   604 	}
       
   605 
       
   606 /**
       
   607 Utility method used for phone matching
       
   608 
       
   609 @param aNumber phone number to be matched
       
   610 @param aMatchLengthFromRight specifies the number of relevant characters to be matched
       
   611 @return array with contact ids matching passed phone number
       
   612 */
       
   613 CContactIdArray* CPlCollection::MatchPhoneNumberL(const TDesC& aNumber, const TInt aMatchLengthFromRight)
       
   614 	{
       
   615 	return iContactsFile.FieldMatcher().MatchPhoneNumberL(aNumber, aMatchLengthFromRight);
       
   616 	}
       
   617 
       
   618 
       
   619 /**
       
   620 Get a collection of contact IDs which have the given GUID.  Since GUIDs are
       
   621 unique (i.e. no two contacts can have the same GUID) there will only ever be
       
   622 one contact ID in this collection.
       
   623 
       
   624 @param aGuid Contact GUID.
       
   625 
       
   626 @return Contact ID array containing the contact with the given GUID.
       
   627 */
       
   628 CContactIdArray* CPlCollection::GuidL(const TDesC& aGuid)
       
   629 	{
       
   630 	// Create the database query string.
       
   631 	TBuf<256> searchCond;
       
   632 	_LIT(KFormat,"%S = '%S'");
       
   633 	searchCond.Format(KFormat, &KContactGuidString, &aGuid);
       
   634 
       
   635 	RSqlStatement selectStatement;
       
   636 	CleanupClosePushL(selectStatement);
       
   637 		
       
   638 	iSelectStatement->Reset();	
       
   639 	iSelectStatement->SetParamL(KContactId, KSpace);
       
   640 	iSelectStatement->SetConditionL(searchCond);
       
   641 	
       
   642 	User::LeaveIfError(selectStatement.Prepare(iContactsFile.NamedDatabase(), iSelectStatement->SqlStringL()));
       
   643 
       
   644 	CContactIdArray* array = CContactIdArray::NewL();
       
   645 	CleanupStack::PushL(array);
       
   646 	
       
   647 	TInt idIndex = iSelectStatement->ParameterIndex(KContactId);
       
   648 	TInt err;
       
   649 	while((err = selectStatement.Next()) == KSqlAtRow)
       
   650 		{
       
   651 		array->AddL(selectStatement.ColumnInt(idIndex));	
       
   652 		}
       
   653 
       
   654 	if(err != KSqlAtEnd)
       
   655 		{
       
   656 		User::LeaveIfError(err);	
       
   657 		}
       
   658 		
       
   659 	CleanupStack::Pop(array);
       
   660 	CleanupStack::PopAndDestroy(&selectStatement);
       
   661 	
       
   662 	return array;
       
   663 	}
       
   664 
       
   665 
       
   666 /**
       
   667 Get a collection of contact IDs which have changed since the given time.
       
   668 
       
   669 @param aTime Changed since time.
       
   670 
       
   671 @return Contact ID array of those contacts which have changed since the given
       
   672 time.
       
   673 */
       
   674 CContactIdArray* CPlCollection::ChangedSinceL(TTime aTime)
       
   675 	{
       
   676 	// Create the database query string.
       
   677 	_LIT(KFormat,"%S >= %LD or %S >= %LD");
       
   678 	HBufC* searchCond = HBufC::NewLC(KFormat().Length()+
       
   679 		KContactCreationDate().Length()+KContactLastModified().Length()+
       
   680 		2 * 64);
       
   681 
       
   682 	TPtr ptr = searchCond->Des();
       
   683 	ptr.Format(KFormat, &KContactCreationDate, aTime.Int64(), &KContactLastModified, aTime.Int64());
       
   684 
       
   685 	RSqlStatement selectStatement;
       
   686 	CleanupClosePushL(selectStatement);
       
   687 		
       
   688 	iSelectStatement->Reset();	
       
   689 	iSelectStatement->SetParamL(KContactId, KSpace);
       
   690 	iSelectStatement->SetParamL(KContactTypeFlags, KSpace);
       
   691 	iSelectStatement->SetConditionL(*searchCond);
       
   692 	
       
   693 	User::LeaveIfError(selectStatement.Prepare(iContactsFile.NamedDatabase(), iSelectStatement->SqlStringL()));
       
   694 
       
   695 	CContactIdArray* array = CContactIdArray::NewL();
       
   696 	CleanupStack::PushL(array);
       
   697 
       
   698 	const TInt idIndex = iSelectStatement->ParameterIndex(KContactId);
       
   699 	const TInt typeFlagsIndex = iSelectStatement->ParameterIndex(KContactTypeFlags);
       
   700 	TInt err;
       
   701 
       
   702 	// Iterate through the view and include only those contacts of the desired
       
   703 	// type (as determined by CheckType()).
       
   704 	while((err = selectStatement.Next()) == KSqlAtRow)
       
   705 		{
       
   706 		TInt typeFlags = selectStatement.ColumnInt(typeFlagsIndex);
       
   707 		TUid contactType = TCntPersistenceUtility::TypeFlagsToContactTypeUid(typeFlags);
       
   708 		if (iContactsFile.ContactProperties().CheckType(contactType))
       
   709 			{
       
   710 			array->AddL(selectStatement.ColumnInt(idIndex));		
       
   711 			}
       
   712 		}
       
   713 
       
   714 	if(err != KSqlAtEnd)
       
   715 		{
       
   716 		User::LeaveIfError(err);
       
   717 		}
       
   718 		
       
   719 	CleanupStack::Pop(array);
       
   720 	CleanupStack::PopAndDestroy(2,searchCond); // searchCond, selectStatement
       
   721 
       
   722 	return array;
       
   723 	}
       
   724 
       
   725 
       
   726 /**
       
   727 Get a collection of contact IDs which are 'unfiled'.
       
   728 
       
   729 @return Contact ID array of those contacts which are 'unfiled'.
       
   730 */
       
   731 CContactIdArray* CPlCollection::UnfiledL()
       
   732 	{
       
   733 	RSqlStatement selectStmt;
       
   734 	CleanupClosePushL(selectStmt);
       
   735 		
       
   736 	iSelectStatement->Reset();	
       
   737 	iSelectStatement->SetParamL(KContactId, KSpace);
       
   738 	iSelectStatement->SetParamL(KContactTypeFlags, KSpace);
       
   739 	
       
   740     User::LeaveIfError(selectStmt.Prepare(iContactsFile.NamedDatabase(), iSelectStatement->SqlStringL()));
       
   741 
       
   742 	CContactIdArray* array = CContactIdArray::NewL();
       
   743 	CleanupStack::PushL(array);
       
   744 	
       
   745 	TInt idIndex = iSelectStatement->ParameterIndex(KContactId);
       
   746 	TInt typeFlagsIndex = iSelectStatement->ParameterIndex(KContactTypeFlags);
       
   747 
       
   748 	// for WHERE contact_group_member_id = [contact id value]
       
   749 	const TInt KWhereMemberClauseBufSize(KGroupContactGroupMemberId().Size() + KWhereStringEqualsStringFormatText().Size() + KGroupContactGroupMemberIdParam().Size() );
       
   750 	HBufC* whereMemberIdClause = HBufC::NewLC(KWhereMemberClauseBufSize);
       
   751 	whereMemberIdClause->Des().AppendFormat(KWhereStringEqualsStringFormatText, &KGroupContactGroupMemberId, &KGroupContactGroupMemberIdParam );
       
   752 	
       
   753 	// select group id
       
   754 	// For a statement in the following format:
       
   755 	// 	SELECT contact_group_id FROM groups 
       
   756 	//		WHERE contact_group_member_id = [contact id value];
       
   757 	//
       
   758 	TCntSqlStatementType statementType(ESelect, KSqlContactGroupTableName);
       
   759 	CCntSqlStatement* selectGroupsStmnt = TSqlProvider::GetSqlStatementL(statementType);
       
   760 	CleanupStack::PushL(selectGroupsStmnt);
       
   761 	selectGroupsStmnt->SetParamL(KGroupContactGroupId(), KNullDesC() );
       
   762 	selectGroupsStmnt->SetConditionL(*whereMemberIdClause);
       
   763 	const TInt KGroupContactGroupMemberIdParamIndex(KFirstIndex); // second parameter in the query
       
   764 
       
   765 	TInt err;
       
   766 	while((err = selectStmt.Next()) == KSqlAtRow)
       
   767 		{
       
   768 		TInt typeFlags = selectStmt.ColumnInt(typeFlagsIndex);
       
   769 		TUid contactType = TCntPersistenceUtility::TypeFlagsToContactTypeUid(typeFlags);
       
   770 		TInt contactAttrib = (typeFlags & EContactAttributes_Mask) >> EContactAttributes_Shift;
       
   771 		
       
   772 		if (contactAttrib & CContactItem::EDeleted)
       
   773 			{
       
   774 			continue;
       
   775 			}
       
   776 			
       
   777 		if (contactType == KUidContactCard || contactType == KUidContactOwnCard)
       
   778 			{
       
   779 			TInt contactId = selectStmt.ColumnInt(idIndex);
       
   780             			
       
   781         	RSqlStatement selectGroupSqlStmt;
       
   782         	CleanupClosePushL(selectGroupSqlStmt);
       
   783         	
       
   784         	selectGroupSqlStmt.PrepareL(iContactsFile.NamedDatabase(), selectGroupsStmnt->SqlStringL() );
       
   785         	User::LeaveIfError(selectGroupSqlStmt.BindInt(KGroupContactGroupMemberIdParamIndex, contactId));
       
   786         	if((err = selectGroupSqlStmt.Next()) == KSqlAtEnd)
       
   787         	    {
       
   788         	    //add the contact id which is not in any group
       
   789     			array->AddL(contactId);
       
   790         	    }
       
   791         	    
       
   792         	User::LeaveIfError(err);    
       
   793         	CleanupStack::PopAndDestroy(&selectGroupSqlStmt); 
       
   794 			}
       
   795 		}
       
   796 
       
   797 	if(err != KSqlAtEnd)
       
   798 		{
       
   799 		User::LeaveIfError(err);
       
   800 		}
       
   801 		
       
   802 	CleanupStack::PopAndDestroy(2, whereMemberIdClause);  //whereMemberIdClause, selectGroupsStmnt #
       
   803 	CleanupStack::Pop(array);
       
   804 	CleanupStack::PopAndDestroy(&selectStmt);
       
   805 	return array;
       
   806 	}
       
   807 
       
   808 
       
   809 /**
       
   810 Get a collection of contact IDs which are marked as deleted.
       
   811 
       
   812 @return Contact ID array of those contacts which are marked as deleted.
       
   813 */
       
   814 CContactIdArray* CPlCollection::DeletedL()
       
   815 	{
       
   816 	RSqlStatement selectStatement;
       
   817 	CleanupClosePushL(selectStatement);
       
   818 		
       
   819 	iSelectStatement->Reset();	
       
   820 	iSelectStatement->SetParamL(KContactId, KSpace);
       
   821 	iSelectStatement->SetParamL(KContactTypeFlags, KSpace);
       
   822 
       
   823 	User::LeaveIfError(selectStatement.Prepare(iContactsFile.NamedDatabase(), iSelectStatement->SqlStringL()));
       
   824 	
       
   825 	CContactIdArray* array = CContactIdArray::NewL();
       
   826 	CleanupStack::PushL(array);
       
   827 	
       
   828 	TInt idIndex = iSelectStatement->ParameterIndex(KContactId);
       
   829 	TInt typeFlagsIndex = iSelectStatement->ParameterIndex(KContactTypeFlags);
       
   830 	TInt err;
       
   831 	while((err = selectStatement.Next()) == KSqlAtRow)
       
   832 		{
       
   833 		TInt typeFlags = selectStatement.ColumnInt(typeFlagsIndex);
       
   834 		TInt contactAttrib = (typeFlags & EContactAttributes_Mask) >> EContactAttributes_Shift;
       
   835 		
       
   836 		if (contactAttrib & CContactItem::EDeleted)
       
   837 			{
       
   838 			array->AddL(selectStatement.ColumnInt(idIndex));
       
   839 			}			
       
   840 		}
       
   841 	
       
   842 	if(err != KSqlAtEnd)
       
   843 		{
       
   844 		User::LeaveIfError(err);	
       
   845 		}
       
   846 	
       
   847 	CleanupStack::Pop(array);
       
   848 	CleanupStack::PopAndDestroy(&selectStatement); 
       
   849 
       
   850 	return array;
       
   851 	}
       
   852 
       
   853 
       
   854 /**
       
   855 Perform a synchronous find for the given text and field definition.
       
   856 
       
   857 @param aText Text to find.
       
   858 @param aFieldDef Field definition to use.
       
   859 @param aSessionID
       
   860 
       
   861 @return Array of contact IDs resulting from the search.
       
   862 */
       
   863 CContactIdArray* CPlCollection::FindL(const TDesC& aText, const CContactItemFieldDef* aFieldDef, TUint aSessionId)
       
   864 	{
       
   865 	CContactIdArray* idsFound = CContactIdArray::NewL();
       
   866 	CleanupStack::PushL(idsFound);
       
   867 
       
   868 	// Create the "find text" from the given text.
       
   869 	HBufC *findText = CreateFindTextL(aText);
       
   870 	CleanupStack::PushL(findText);
       
   871 
       
   872 	// Find out what tables need to included in the search as determined by the
       
   873 	// given field definition.
       
   874 	TInt findFlags = 0;
       
   875 	TInt identityTableFieldsCount = 0;
       
   876 	ConstructBitwiseFindFlags(findFlags,identityTableFieldsCount,aFieldDef);
       
   877 	
       
   878 	// Search through the first/last name (and their pronunciation) and company
       
   879 	// names fields in the Identity table.
       
   880 	if ( SearchIdentityFieldsRequired(findFlags) )
       
   881 		{
       
   882 		_LIT(KWhereClause,"(%S LIKE '%S') OR (%S LIKE '%S') OR (%S LIKE '%S') OR (%S LIKE '%S') OR (%S LIKE '%S') OR (%S LIKE '%S')");
       
   883 		HBufC* searchCond = HBufC::NewLC(KWhereClause().Length() +
       
   884 								KContactFirstName().Length() + findText->Length() +
       
   885 								KContactLastName().Length() + findText->Length() +
       
   886 								KContactCompanyName().Length() + findText->Length() +
       
   887 								KContactFirstNamePrn().Length() + findText->Length() +
       
   888 								KContactLastNamePrn().Length() + findText->Length() +
       
   889 								KContactCompanyNamePrn().Length() + findText->Length());
       
   890 		searchCond->Des().Format(KWhereClause, &KContactFirstName, findText,
       
   891 								&KContactLastName, findText, &KContactCompanyName, findText,
       
   892 								&KContactFirstNamePrn, findText, &KContactLastNamePrn, findText,
       
   893 								&KContactCompanyNamePrn, findText);
       
   894 			
       
   895 		RSqlStatement selectStatement;
       
   896 		CleanupClosePushL(selectStatement);
       
   897 		
       
   898 		iSelectStatement->Reset();	
       
   899 		iSelectStatement->SetParamL(KContactId, KSpace);
       
   900 		iSelectStatement->SetParamL(KContactTypeFlags, KSpace);
       
   901 		iSelectStatement->SetParamL(KContactFirstName, KSpace);
       
   902 		iSelectStatement->SetParamL(KContactLastName, KSpace);
       
   903 		iSelectStatement->SetParamL(KContactCompanyName, KSpace);
       
   904 		iSelectStatement->SetParamL(KContactFirstNamePrn, KSpace);
       
   905 		iSelectStatement->SetParamL(KContactLastNamePrn, KSpace);
       
   906 		iSelectStatement->SetParamL(KContactCompanyNamePrn, KSpace);
       
   907 		iSelectStatement->SetConditionL(*searchCond);
       
   908 		
       
   909 		User::LeaveIfError(selectStatement.Prepare(iContactsFile.NamedDatabase(), iSelectStatement->SqlStringL()));
       
   910 		
       
   911 		while(PerformFindIterationL(idsFound, aText, selectStatement, findFlags, aSessionId)) 
       
   912 			{
       
   913 			// Keep performing find iteration until EFalse is returned.
       
   914 			}
       
   915 		
       
   916 		CleanupStack::PopAndDestroy(2, searchCond); // searchCond, selectStatement
       
   917 		}
       
   918 
       
   919 	// Search through the email address fields
       
   920 	if (findFlags & (EFindInAllFields | EFindInEmailField))
       
   921 		{
       
   922 		TCntSqlStatementType statementType(ESelect, KSqlContactCommAddrTableName);
       
   923 		CCntSqlStatement* cntSelectStatement = TSqlProvider::GetSqlStatementL(statementType);
       
   924 		CleanupStack::PushL(cntSelectStatement);
       
   925 		
       
   926 		_LIT(KWhereClause, "(%S = %d) AND (%S LIKE '%S')");
       
   927 		HBufC* searchCond = HBufC::NewLC(KWhereClause().Length()+ 
       
   928 			KCommAddrType().Length() + 
       
   929 			KCommAddrValue().Length() + findText->Length());
       
   930 		searchCond->Des().Format(KWhereClause, 
       
   931 			&KCommAddrType, CPplCommAddrTable::EEmailAddress, 
       
   932 			&KCommAddrValue, findText);
       
   933 		
       
   934 		RSqlStatement selectStatement;
       
   935 		CleanupClosePushL(selectStatement);
       
   936 		
       
   937 		cntSelectStatement->SetParamL(KContactId, KSpace);
       
   938 		cntSelectStatement->SetConditionL(*searchCond);
       
   939 
       
   940 		User::LeaveIfError(selectStatement.Prepare(iContactsFile.NamedDatabase(), cntSelectStatement->SqlStringL()));
       
   941 		
       
   942 		while(PerformIdFindIterationL(idsFound, selectStatement))
       
   943 			{
       
   944 			// Keep performing find iteration until EFalse is returned.
       
   945 			}
       
   946 			
       
   947 		CleanupStack::PopAndDestroy(3, cntSelectStatement); //selectStatement, searchCond, cntSelectStatement
       
   948 		}
       
   949 
       
   950 	// Search through the sip address fields
       
   951 	if (findFlags & (EFindInAllFields | EFindInSIPField))
       
   952 		{
       
   953 		TCntSqlStatementType statementType(ESelect, KSqlContactCommAddrTableName);
       
   954 		CCntSqlStatement* cntSelectStatement = TSqlProvider::GetSqlStatementL(statementType);
       
   955 		CleanupStack::PushL(cntSelectStatement);
       
   956 		
       
   957 		_LIT(KWhereClause, "(%S = %d) AND (%S LIKE '%S')");
       
   958 		HBufC* searchCond = HBufC::NewLC(KWhereClause().Length()+ 
       
   959 			KCommAddrType().Length() + 
       
   960 			KCommAddrValue().Length() + findText->Length());
       
   961 		searchCond->Des().Format(KWhereClause, 
       
   962 			&KCommAddrType, CPplCommAddrTable::ESipAddress, 
       
   963 			&KCommAddrValue, findText);
       
   964 		
       
   965 		RSqlStatement selectStatement;
       
   966 		CleanupClosePushL(selectStatement);
       
   967 		
       
   968 		cntSelectStatement->SetParamL(KContactId, KSpace);
       
   969 		cntSelectStatement->SetConditionL(*searchCond);
       
   970 
       
   971 		User::LeaveIfError(selectStatement.Prepare(iContactsFile.NamedDatabase(), cntSelectStatement->SqlStringL()));
       
   972 		
       
   973 		while(PerformIdFindIterationL(idsFound, selectStatement))
       
   974 			{
       
   975 			// Keep performing find iteration until EFalse is returned.
       
   976 			}
       
   977 			
       
   978 		CleanupStack::PopAndDestroy(3, cntSelectStatement); //selectStatement, searchCond, cntSelectStatement
       
   979 		}
       
   980 		
       
   981 	// Search through the searchable text for any other fields.
       
   982 	if (findFlags & EFindInAllFields)
       
   983 		{
       
   984 		iSelectStatement->Reset();
       
   985 		iSelectStatement->SetParamL(KContactId, KSpace);
       
   986 		iSelectStatement->SetParamL(KContactTypeFlags, KSpace);
       
   987 		iSelectStatement->SetParamL(KContactTextFieldHeader, KSpace);
       
   988 		iSelectStatement->SetParamL(KContactTextFields, KSpace);
       
   989 		
       
   990 		RSqlStatement selectStatement;
       
   991 		CleanupClosePushL(selectStatement);
       
   992 	
       
   993 		User::LeaveIfError(selectStatement.Prepare(iContactsFile.NamedDatabase(), iSelectStatement->SqlStringL()));
       
   994 
       
   995  		while(FindL(idsFound,*findText,aFieldDef, selectStatement, aSessionId))
       
   996 			{
       
   997 			// Keep performing find iteration until EFalse is returned.
       
   998 			}
       
   999 		
       
  1000 		CleanupStack::PopAndDestroy(&selectStatement);
       
  1001 		}
       
  1002 
       
  1003 	CleanupStack::PopAndDestroy(findText);
       
  1004 	CleanupStack::Pop(idsFound);
       
  1005 
       
  1006 	return(idsFound);
       
  1007 	}
       
  1008 
       
  1009 
       
  1010 /**
       
  1011 Get a collection of contact IDs which match the given filter.
       
  1012 
       
  1013 @param aFilter Filter to match.
       
  1014 
       
  1015 @return Contact ID array of those contacts which match the given filter.
       
  1016 */
       
  1017 CContactIdArray* CPlCollection::FilterDatabaseL(CCntFilter& aFilter)
       
  1018 	{
       
  1019 	_LIT(KWhereCondition,"%S >= %LD");
       
  1020 
       
  1021 	iSelectStatement->Reset();
       
  1022 	iSelectStatement->SetParamL(KContactId, KSpace);
       
  1023 	iSelectStatement->SetParamL(KContactTypeFlags, KSpace);
       
  1024 
       
  1025 	if (aFilter.IncludeModifiedContacts() || aFilter.IncludeDeletedContacts())
       
  1026 		{
       
  1027 		// Create query to search for modified/deleted contacts.
       
  1028 		HBufC* searchCond=HBufC::NewLC(KWhereCondition().Length() + 
       
  1029 			KContactLastModified().Length() + 64); 
       
  1030 			
       
  1031 		TPtr ptr=searchCond->Des();
       
  1032 		ptr.Format(KWhereCondition, &KContactLastModified, aFilter.GetFilterDateTime().Int64());
       
  1033 	
       
  1034 		iSelectStatement->SetConditionL(*searchCond);
       
  1035 			
       
  1036 		CleanupStack::PopAndDestroy(searchCond);	
       
  1037 		}
       
  1038 	else if (aFilter.IncludeNewContacts())
       
  1039 		{
       
  1040 		// Create query to search for inserted contacts.
       
  1041 		HBufC* searchCond=HBufC::NewLC(KWhereCondition().Length() +
       
  1042 			KContactCreationDate().Length() + 64);
       
  1043 
       
  1044 		TPtr ptr=searchCond->Des();
       
  1045 		ptr.Format(KWhereCondition, &KContactCreationDate, aFilter.GetFilterDateTime().Int64());
       
  1046 		
       
  1047 		iSelectStatement->SetConditionL(*searchCond);
       
  1048 		
       
  1049 		CleanupStack::PopAndDestroy(searchCond);
       
  1050 		}
       
  1051 
       
  1052 	RSqlStatement selectStatement;
       
  1053 	CleanupClosePushL(selectStatement);
       
  1054 	
       
  1055 	const TInt idIndex = iSelectStatement->ParameterIndex(KContactId);
       
  1056 	const TInt typeFlagsIndex = iSelectStatement->ParameterIndex(KContactTypeFlags);
       
  1057 
       
  1058 	TBool filterIncludesAllContacts = !(aFilter.IncludeDeletedContacts() ||
       
  1059 		aFilter.IncludeNewContacts() || aFilter.IncludeModifiedContacts());
       
  1060 
       
  1061 	CContactIdArray* idArray = CContactIdArray::NewL();
       
  1062 	CleanupStack::PushL(idArray);
       
  1063 
       
  1064 	User::LeaveIfError(selectStatement.Prepare(iContactsFile.NamedDatabase(), iSelectStatement->SqlStringL()));
       
  1065 		
       
  1066 	TInt err;
       
  1067 	while((err = selectStatement.Next()) == KSqlAtRow)
       
  1068 		{
       
  1069 		TInt typeFlags = selectStatement.ColumnInt(typeFlagsIndex);
       
  1070 		
       
  1071 		TUid type = TCntPersistenceUtility::TypeFlagsToContactTypeUid(typeFlags);
       
  1072 		TUint32 attribs = (typeFlags & EContactAttributes_Mask) >> EContactAttributes_Shift;
       
  1073 
       
  1074 		if (((aFilter.IncludeDeletedContacts() && (attribs & CContactItem::EDeleted)) 
       
  1075 		||  (aFilter.IncludeNewContacts() 
       
  1076 		||   aFilter.IncludeModifiedContacts()) && (aFilter.TestContactFilterType(type)))
       
  1077 		|| (filterIncludesAllContacts && aFilter.TestContactFilterType(type))) 
       
  1078 			{
       
  1079 			TContactItemId id = selectStatement.ColumnInt(idIndex);
       
  1080 			idArray->AddL(id);
       
  1081 			}
       
  1082 		}
       
  1083 		
       
  1084 	if(err != KSqlAtEnd)
       
  1085 		{
       
  1086 		User::LeaveIfError(err);
       
  1087 		}
       
  1088 
       
  1089 	CleanupStack::Pop(idArray);
       
  1090 	CleanupStack::PopAndDestroy(&selectStatement);
       
  1091 	
       
  1092 	return idArray;
       
  1093 	}
       
  1094 
       
  1095 
       
  1096 /**
       
  1097 Perform a find interation based on given sql statement for the given text.
       
  1098 
       
  1099 @param aIdsFound On return the contact IDs found.
       
  1100 @param aText Text to find.
       
  1101 @param aStatement sql statement
       
  1102 @param aFieldsToSearch Fields within the view to search.
       
  1103 @param aSessionId Session ID (only relevant for ICC contacts).
       
  1104 
       
  1105 @return ETrue if further iterations are required (i.e. view has not been fully
       
  1106 evaluated and searched), EFalse otherwise.
       
  1107 */
       
  1108 TBool CPlCollection::PerformFindIterationL(CContactIdArray* aIdsFound,const TDesC& aText,RSqlStatement aStatement,  TInt aFieldsToSearch, TUint aSessionId)
       
  1109 	{
       
  1110 	TContactItemId contactId;
       
  1111 
       
  1112 	const TInt idIndex = aStatement.ColumnIndex(KContactId);
       
  1113 	User::LeaveIfError(idIndex);
       
  1114 	const TInt typeFlagsIndex = aStatement.ColumnIndex(KContactTypeFlags);
       
  1115 	User::LeaveIfError(typeFlagsIndex);
       
  1116 	TInt err;
       
  1117 	
       
  1118 	const TInt firstNameIndex = aStatement.ColumnIndex(KContactFirstName);
       
  1119 	User::LeaveIfError(firstNameIndex);
       
  1120 	const TInt lastNameIndex = aStatement.ColumnIndex(KContactLastName);
       
  1121 	User::LeaveIfError(lastNameIndex);
       
  1122 	const TInt companyNameIndex = aStatement.ColumnIndex(KContactCompanyName);
       
  1123 	User::LeaveIfError(companyNameIndex);
       
  1124 	const TInt firstNamePrnIndex = aStatement.ColumnIndex(KContactFirstNamePrn);
       
  1125 	User::LeaveIfError(firstNamePrnIndex);
       
  1126 	const TInt lastNamePrnIndex = aStatement.ColumnIndex(KContactLastNamePrn);
       
  1127 	User::LeaveIfError(lastNamePrnIndex);
       
  1128 	const TInt companyNamePrnIndex = aStatement.ColumnIndex(KContactCompanyNamePrn);
       
  1129 	User::LeaveIfError(companyNamePrnIndex);
       
  1130 	
       
  1131 	while((err = aStatement.Next()) == KSqlAtRow)
       
  1132 		{
       
  1133 		// Do not include contact if it is not of the desired type.
       
  1134 		TInt typeFlags = aStatement.ColumnInt(typeFlagsIndex);
       
  1135 		TUid contactType = TCntPersistenceUtility::TypeFlagsToContactTypeUid(typeFlags);
       
  1136 
       
  1137 		if(iContactsFile.ContactProperties().CheckType(contactType) == EFalse)
       
  1138 			{
       
  1139 			continue;
       
  1140 			}
       
  1141 
       
  1142 		contactId = aStatement.ColumnInt(idIndex);
       
  1143 
       
  1144 		// Check that the contact is not already present in the given contact
       
  1145 		// IDs before searching for the given text.
       
  1146 		if(aIdsFound->Find(contactId)==KErrNotFound)
       
  1147 			{
       
  1148 			TBool findTextInFields = ((aFieldsToSearch & EFindInAllFields) || (aFieldsToSearch & EFindFirstName)) ? (aStatement.ColumnTextL(firstNameIndex).FindC(aText.Ptr(), aText.Length(), KCollationLevel) != KErrNotFound ) : EFalse;
       
  1149 			findTextInFields = findTextInFields || (((aFieldsToSearch & EFindInAllFields) || (aFieldsToSearch & EFindLastName)) ? (aStatement.ColumnTextL(lastNameIndex).FindC(aText.Ptr(), aText.Length(), KCollationLevel) != KErrNotFound ) : EFalse);
       
  1150 			findTextInFields = findTextInFields || (((aFieldsToSearch & EFindInAllFields) || (aFieldsToSearch & EFindCompanyName)) ? (aStatement.ColumnTextL(companyNameIndex).FindC(aText.Ptr(), aText.Length(), KCollationLevel) != KErrNotFound ) : EFalse);
       
  1151 			findTextInFields = findTextInFields || (((aFieldsToSearch & EFindInAllFields) || (aFieldsToSearch & EFindFirstNamePronunciation)) ? (aStatement.ColumnTextL(firstNamePrnIndex).FindC(aText.Ptr(), aText.Length(), KCollationLevel) != KErrNotFound ) :EFalse);
       
  1152 			findTextInFields = findTextInFields || (((aFieldsToSearch & EFindInAllFields) || (aFieldsToSearch & EFindLastNamePronunciation)) ? (aStatement.ColumnTextL(lastNamePrnIndex).FindC(aText.Ptr(), aText.Length(), KCollationLevel) != KErrNotFound ) :EFalse);
       
  1153 			findTextInFields = findTextInFields || (((aFieldsToSearch & EFindInAllFields) || (aFieldsToSearch & EFindCompanyNamePronunciation)) ? (aStatement.ColumnTextL(companyNamePrnIndex).FindC(aText.Ptr(), aText.Length(), KCollationLevel) != KErrNotFound ) : EFalse);
       
  1154 			
       
  1155 			if(findTextInFields)
       
  1156 				{
       
  1157 				if (contactType == KUidContactICCEntry)
       
  1158 					{
       
  1159 					TInt error(iContactsFile.ContactProperties().ContactSynchroniserL(aSessionId).ValidateContact(MContactSynchroniser::ESearch,contactId));
       
  1160 					User::LeaveIfError(error);
       
  1161 					}
       
  1162 				aIdsFound->AddL(contactId);
       
  1163 				}
       
  1164 			}
       
  1165 		}
       
  1166 	User::LeaveIfError(err);	
       
  1167 
       
  1168 	return (EFalse);
       
  1169 	}
       
  1170 
       
  1171 /**
       
  1172 Perform a find interation based on the given sql statement for the given text.
       
  1173 
       
  1174 @param aIdsFound On return the contact IDs found.
       
  1175 @param aStatement sql statement
       
  1176 
       
  1177 @return ETrue if further iterations are required (i.e. view has not been fully
       
  1178 evaluated and searched), EFalse otherwise.
       
  1179 */
       
  1180 TBool CPlCollection::PerformIdFindIterationL(CContactIdArray *aIdsFound, RSqlStatement aStatement)
       
  1181 	{
       
  1182 	const TInt idIndex = aStatement.ColumnIndex(KContactId);
       
  1183 	User::LeaveIfError(idIndex);	
       
  1184 	TInt err;
       
  1185 	while((err = aStatement.Next()) == KSqlAtRow)
       
  1186 		{
       
  1187 		TInt contactId = aStatement.ColumnInt(idIndex);
       
  1188 		
       
  1189 		// Check that the contact is not already present in the given contact
       
  1190 		// IDs before adding it to the array of contact IDs.
       
  1191 		if(aIdsFound->Find(contactId) == KErrNotFound)
       
  1192 			{
       
  1193 			aIdsFound->AddL(contactId);
       
  1194 			}
       
  1195 		}
       
  1196 	User::LeaveIfError(err);	
       
  1197 
       
  1198 	return (EFalse);
       
  1199 	}
       
  1200 
       
  1201 /**
       
  1202 Utility method used to build the search string
       
  1203 */
       
  1204 void AppendSearchStringSegment(TDes16& aOrderFields,const TDesC& aColName,  
       
  1205 	const TPtrC aTxtPtr, TBool aAppendOr)
       
  1206 	{
       
  1207 	aOrderFields.Append(KLeftBracket);
       
  1208 	aOrderFields.Append(aColName);
       
  1209 	aOrderFields.Append(KLikeString);
       
  1210 	aOrderFields.Append(aTxtPtr);
       
  1211 	aOrderFields.Append(KLikeStringRight);
       
  1212 	if(aAppendOr)
       
  1213 		{
       
  1214 		aOrderFields.Append(KOR);
       
  1215 		}
       
  1216 	}
       
  1217 
       
  1218 /**
       
  1219 Utility method used to build search string
       
  1220 */
       
  1221 void ConstructSearchString(TInt aFieldDef,TInt aNoFields,TDes16& aOrderFields,TPtrC aTxtPtr)
       
  1222 	{
       
  1223 	const void* KColNamesFields[] =
       
  1224 		{
       
  1225 		&KContactFirstName, &KContactLastName, &KContactCompanyName,
       
  1226 		&KContactFirstNamePrn, &KContactLastNamePrn,
       
  1227 		&KContactLastNamePrn
       
  1228 		};
       
  1229 		
       
  1230  	for(TInt ii=0;ii<aNoFields;ii++)
       
  1231 		{
       
  1232 		for(TInt name = 0; name < sizeof(KNameFlags)/sizeof(TFindFieldFlags); ++name)
       
  1233 			{
       
  1234 			if(aFieldDef&KNameFlags[name])
       
  1235 				{
       
  1236 				AppendSearchStringSegment(aOrderFields,*((TDesC*)KColNamesFields[name]),  aTxtPtr, (ii+1)<aNoFields);
       
  1237 				aFieldDef &= ~KNameFlags[name];
       
  1238 				break;
       
  1239 				}
       
  1240 			}
       
  1241 		}
       
  1242 	}
       
  1243 
       
  1244 
       
  1245 /**
       
  1246 This method is required for asynchronous finds which have an initialisation
       
  1247 method followed by one or more calls to the FindAsyncL() method.  The class
       
  1248 needs to be reset to a known state when a find is completed.
       
  1249 */
       
  1250 void CPlCollection::Reset()
       
  1251 	{
       
  1252 	if ( !iRSqlstatementsWorking )
       
  1253         {
       
  1254         //If RSqlstatements was reseted, don't reset it again.
       
  1255         return;
       
  1256         }
       
  1257 	// Could introduce methods specific to the find operation such that this
       
  1258 	// method is called only if an asynchronous find has taken place. 
       
  1259 	delete iFieldDef;
       
  1260 	iFieldDef = NULL;
       
  1261 	delete iTextDef;
       
  1262 	iTextDef = NULL;
       
  1263 	delete iText;
       
  1264 	iText = NULL;
       
  1265 	delete iOriginalText;
       
  1266 	iOriginalText = NULL;
       
  1267 	delete iFindWords;
       
  1268 	iFindWords = NULL;
       
  1269 	delete iFindWords2;
       
  1270 	iFindWords2 = NULL;
       
  1271 	iNoIdentitySearchColumns = 0;
       
  1272 	iFindFlags = 0;
       
  1273 	iFindState = 0;	
       
  1274 	
       
  1275 	selectBlobStatement.Close();
       
  1276 	selectIdentityStatement.Close();
       
  1277 	selectEmailStatement.Close();
       
  1278 	selectSIPStatement.Close();
       
  1279 	selectIdFromIdentityStatement.Close();
       
  1280 	iRSqlstatementsWorking = EFalse;
       
  1281 	}
       
  1282 
       
  1283 
       
  1284 /**
       
  1285 Initialise the Persistence Layer collection class ready for iterative calls to
       
  1286 the FindAsyncL() method.  This form of initialisation is for an asynchronous
       
  1287 find which uses text and a field definition.
       
  1288 
       
  1289 @param aText Find text.
       
  1290 @param aFieldDef Field definition to use in find.
       
  1291 
       
  1292 @leave KErrNoMemory Out of memory.
       
  1293 */
       
  1294 void CPlCollection::FindAsyncInitL(const TDesC& aText,CContactItemFieldDef* aFieldDef)
       
  1295 	{
       
  1296 	_LIT(KWhereEmailSIPClause, "(%S = %d) AND (%S LIKE '%S')");
       
  1297 	// Persistence Layer CPlCollection is not deleted but Reset()'s the member
       
  1298 	// variables for iterative FindAsyncL() calls.
       
  1299 	Reset();
       
  1300 	iRSqlstatementsWorking = ETrue;
       
  1301 	iText = CreateFindTextL(aText);
       
  1302 	iFieldDef = aFieldDef;
       
  1303 	iOriginalText = aText.AllocL();
       
  1304 	ConstructBitwiseFindFlags(iFindFlags,iNoIdentitySearchColumns,iFieldDef);
       
  1305 	// Construct RSqlStatements used for search
       
  1306 	
       
  1307 	HBufC *findText = CreateFindTextL(*iOriginalText);
       
  1308 	CleanupStack::PushL(findText);
       
  1309 	
       
  1310 	// first construct select statement for searching in identity fields
       
  1311 	if ( SearchIdentityFieldsRequired(iFindFlags) )
       
  1312 		{
       
  1313 		_LIT(KWhereClause,"(%S LIKE '%S') OR (%S LIKE '%S') OR (%S LIKE '%S') OR (%S LIKE '%S') OR (%S LIKE '%S') OR (%S LIKE '%S')");
       
  1314 		HBufC* searchCond=HBufC::NewLC(KWhereClause().Length() +
       
  1315 						KContactFirstName().Length() + findText->Length() +
       
  1316 						KContactLastName().Length() + findText->Length() +
       
  1317 						KContactCompanyName().Length() + findText->Length() +
       
  1318 						KContactFirstNamePrn().Length() + findText->Length() +
       
  1319 						KContactLastNamePrn().Length() + findText->Length() +
       
  1320 						KContactCompanyNamePrn().Length() + findText->Length());
       
  1321 		searchCond->Des().Format(KWhereClause, &KContactFirstName, findText,
       
  1322 						&KContactLastName, findText, &KContactCompanyName, findText,
       
  1323 						&KContactFirstNamePrn, findText, &KContactLastNamePrn, findText,
       
  1324 						&KContactCompanyNamePrn, findText);
       
  1325 					
       
  1326 		iSelectStatement->Reset();	
       
  1327 		iSelectStatement->SetParamL(KContactId, KSpace);
       
  1328 		iSelectStatement->SetParamL(KContactTypeFlags, KSpace);
       
  1329 		iSelectStatement->SetParamL(KContactFirstName, KSpace);
       
  1330 		iSelectStatement->SetParamL(KContactLastName, KSpace);
       
  1331 		iSelectStatement->SetParamL(KContactCompanyName, KSpace);
       
  1332 		iSelectStatement->SetParamL(KContactFirstNamePrn, KSpace);
       
  1333 		iSelectStatement->SetParamL(KContactLastNamePrn, KSpace);
       
  1334 		iSelectStatement->SetParamL(KContactCompanyNamePrn, KSpace);
       
  1335 		iSelectStatement->SetConditionL(*searchCond);
       
  1336 		
       
  1337 		User::LeaveIfError(selectIdentityStatement.Prepare(iContactsFile.NamedDatabase(), iSelectStatement->SqlStringL()));
       
  1338 		CleanupStack::PopAndDestroy(searchCond); 
       
  1339 		}
       
  1340 	//end construction for statement for searching in identity fields
       
  1341 
       
  1342 	//construct statement for search email
       
  1343 	if (iFindFlags & (EFindInAllFields | EFindInEmailField))
       
  1344 		{
       
  1345 		TCntSqlStatementType statementType(ESelect, KSqlContactCommAddrTableName);
       
  1346 		CCntSqlStatement* cntSelectStatement = TSqlProvider::GetSqlStatementL(statementType);
       
  1347 		CleanupStack::PushL(cntSelectStatement);
       
  1348 	
       
  1349 		HBufC* searchCond = HBufC::NewLC(KWhereEmailSIPClause().Length()+ 
       
  1350 				KCommAddrType().Length() + 
       
  1351 				KCommAddrValue().Length() + findText->Length());
       
  1352 		searchCond->Des().Format(KWhereEmailSIPClause, 
       
  1353 				&KCommAddrType, CPplCommAddrTable::EEmailAddress, 
       
  1354 				&KCommAddrValue, findText);
       
  1355 	
       
  1356 		cntSelectStatement->SetParamL(KContactId, KSpace);
       
  1357 		cntSelectStatement->SetConditionL(*searchCond);
       
  1358 
       
  1359 		User::LeaveIfError(selectEmailStatement.Prepare(iContactsFile.NamedDatabase(), cntSelectStatement->SqlStringL()));
       
  1360 		CleanupStack::PopAndDestroy(2, cntSelectStatement); // cntSelectStatement, searchCond
       
  1361 		}
       
  1362 	//end construction for statement for search email
       
  1363 
       
  1364 	//construct statement for search sip values
       
  1365 	if (iFindFlags & (EFindInAllFields | EFindInSIPField))
       
  1366 		{
       
  1367 		TCntSqlStatementType statementType(ESelect, KSqlContactCommAddrTableName);
       
  1368 		CCntSqlStatement* cntSelectStatement = TSqlProvider::GetSqlStatementL(statementType);
       
  1369 		CleanupStack::PushL(cntSelectStatement);
       
  1370 	
       
  1371 		HBufC* searchCond = HBufC::NewLC(KWhereEmailSIPClause().Length()+ 
       
  1372 				KCommAddrType().Length() + 
       
  1373 				KCommAddrValue().Length() + findText->Length());
       
  1374 		searchCond->Des().Format(KWhereEmailSIPClause, 
       
  1375 				&KCommAddrType, CPplCommAddrTable::ESipAddress, 
       
  1376 				&KCommAddrValue, findText);
       
  1377 	
       
  1378 		cntSelectStatement->SetParamL(KContactId, KSpace);
       
  1379 		cntSelectStatement->SetConditionL(*searchCond);
       
  1380 
       
  1381 		User::LeaveIfError(selectSIPStatement.Prepare(iContactsFile.NamedDatabase(), cntSelectStatement->SqlStringL()));
       
  1382 		CleanupStack::PopAndDestroy(2, cntSelectStatement); // cntSelectStatement, searchCond
       
  1383 		}
       
  1384 	//end construction for statement for search sip values
       
  1385 
       
  1386 	//construct statement for search in blob
       
  1387 	if (iFindFlags & EFindInAllFields)
       
  1388 		{
       
  1389 		iSelectStatement->Reset();
       
  1390 		iSelectStatement->SetParamL(KContactId, KSpace);
       
  1391 		iSelectStatement->SetParamL(KContactTypeFlags, KSpace);
       
  1392 		iSelectStatement->SetParamL(KContactTextFieldHeader, KSpace);
       
  1393 		iSelectStatement->SetParamL(KContactTextFields, KSpace);
       
  1394 		
       
  1395 		User::LeaveIfError(selectBlobStatement.Prepare(iContactsFile.NamedDatabase(), iSelectStatement->SqlStringL()));
       
  1396 		}
       
  1397 	//end construction for statement for search in blob
       
  1398 	
       
  1399 	CleanupStack::PopAndDestroy(findText);
       
  1400 	}
       
  1401 
       
  1402 
       
  1403 /**
       
  1404 Add the required fields and search text for SQL query.  Used for asynchronous
       
  1405 find which uses a text definition.
       
  1406 
       
  1407 @see CPlCollection::FindAsyncTextDefInitL()
       
  1408 	
       
  1409 @param aOrderFields On return contains the required fields and search text for
       
  1410 SQL query.
       
  1411 */
       
  1412 void CPlCollection::doAppendFieldsToSearchString(HBufC* aOrderFields) const
       
  1413   	{
       
  1414   	TInt noOfFindWords = iFindWords2->Count();
       
  1415   	TPtr16 orderFieldPtr = aOrderFields->Des();
       
  1416   	for(TInt searchWord = 0;searchWord < noOfFindWords; ++searchWord)
       
  1417   		{
       
  1418   		ConstructSearchString(iFindFlags,iNoIdentitySearchColumns,orderFieldPtr,(*iFindWords2)[searchWord]);
       
  1419   		if ((searchWord+1) < noOfFindWords)
       
  1420   			{
       
  1421   			orderFieldPtr.Append(KOR);
       
  1422   			}
       
  1423   		}		
       
  1424   	}
       
  1425 
       
  1426 
       
  1427 /**
       
  1428 Initialise the Persistence Layer collection class ready for iterative calls to
       
  1429 the FindAsyncL() method.  This form of initialisation is for an asynchronous
       
  1430 find which uses a text definition and an array of "find words".
       
  1431 
       
  1432 @param aWords "Find words" array.
       
  1433 @param aTextDef Text definition to use in find.
       
  1434 */
       
  1435 void CPlCollection::FindAsyncTextDefInitL(const CDesCArray& aWords,CContactTextDef* aTextDef)
       
  1436 	{
       
  1437 	// Persistence Layer CPlCollection is not deleted but Reset()'s the member
       
  1438 	// variables for iterative FindAsyncL() calls.
       
  1439 	Reset();
       
  1440     iRSqlstatementsWorking = ETrue;
       
  1441 	iFindWords = new(ELeave) CDesCArrayFlat(5);
       
  1442 	iFindWords2 = new(ELeave) CDesCArrayFlat(5);
       
  1443 	for(TInt loop = 0;loop < aWords.MdcaCount();++loop)
       
  1444 		{
       
  1445 		// Construct iFindWords2 which contains all the strings in the search
       
  1446 		// surrounded by a %.
       
  1447 		TPtrC findWord(aWords.MdcaPoint(loop));
       
  1448 		TKeyCmpTextLength key;
       
  1449 		HBufC* bufPtr = findWord.AllocLC();
       
  1450 		iFindWords->CArrayFixBase::InsertIsqAllowDuplicatesL(&bufPtr,key);
       
  1451 		CleanupStack::Pop(); // bufPtr
       
  1452 		HBufC *findText = CreateFindTextL(findWord);
       
  1453 		CleanupStack::PushL(findText);
       
  1454 		iFindWords2->AppendL(*findText);
       
  1455 		CleanupStack::PopAndDestroy(); // findText
       
  1456 		}
       
  1457 
       
  1458 	iTextDef = aTextDef;
       
  1459 	ConstructBitwiseFlagsFromTextDef(iFindFlags,iNoIdentitySearchColumns,iTextDef);
       
  1460 
       
  1461 	iSelectStatement->Reset();	
       
  1462 	iSelectStatement->SetParamL(KContactId, KSpace);
       
  1463 	iSelectStatement->SetParamL(KContactTypeFlags, KSpace);
       
  1464 	iSelectStatement->SetParamL(KContactFirstName, KSpace);
       
  1465 	iSelectStatement->SetParamL(KContactLastName, KSpace);
       
  1466 	iSelectStatement->SetParamL(KContactCompanyName, KSpace);
       
  1467 	iSelectStatement->SetParamL(KContactFirstNamePrn, KSpace);
       
  1468 	iSelectStatement->SetParamL(KContactLastNamePrn, KSpace);
       
  1469 	iSelectStatement->SetParamL(KContactCompanyNamePrn, KSpace);
       
  1470 		
       
  1471 	if(UsesIdentityFieldsOnly(iFindFlags))
       
  1472 		{
       
  1473 		TInt querySize = ApproximateSizeOfSearchString(); 
       
  1474 		HBufC* searchCond = HBufC::NewLC(querySize); 
       
  1475 		doAppendFieldsToSearchString(searchCond);
       
  1476 		iSelectStatement->SetConditionL(*searchCond);
       
  1477 		CleanupStack::PopAndDestroy(searchCond); 
       
  1478 		}
       
  1479 		
       
  1480 	User::LeaveIfError(selectIdFromIdentityStatement.Prepare(iContactsFile.NamedDatabase(), iSelectStatement->SqlStringL()));
       
  1481 	}
       
  1482 
       
  1483 
       
  1484 /**
       
  1485 This method does not do any searching.  It simply extracts the contact IDs from
       
  1486 the view and (ultimately) returns them to the CIdleFinder object on the client
       
  1487 side.
       
  1488 
       
  1489 The client can then call CIdleFinder::CheckFindL() to perform the actual search.
       
  1490 Searching cannot be performed server-side because of the need to call a client
       
  1491 supplied callback method (the "find words parser" callback).
       
  1492 
       
  1493 @param aIdArray Contact IDs extracted from the view.
       
  1494 @param aSessionId Session ID (only relevant for ICC contacts).
       
  1495 
       
  1496 @return ETrue if further iterations are required (i.e. view has not been fully
       
  1497 evaluated), EFalse otherwise.
       
  1498 */
       
  1499 TBool CPlCollection::GetContactIdsForTextDefFindL(CContactIdArray* aIdArray, TUint aSessionId)
       
  1500 	{
       
  1501 	TInt iterCount = 0;
       
  1502 	TInt err;
       
  1503 	
       
  1504 	const TInt idIndex = selectIdFromIdentityStatement.ColumnIndex(KContactId);
       
  1505 	User::LeaveIfError(idIndex);
       
  1506 	const TInt typeFlagsIndex = selectIdFromIdentityStatement.ColumnIndex(KContactTypeFlags);
       
  1507 	User::LeaveIfError(typeFlagsIndex);
       
  1508 	
       
  1509 	while(iterCount<KFindIterations)
       
  1510 		{
       
  1511 		err = selectIdFromIdentityStatement.Next();
       
  1512 		if(err != KSqlAtRow)
       
  1513 			{
       
  1514 			User::LeaveIfError(err);
       
  1515 			break;
       
  1516 			}
       
  1517 			
       
  1518 		TInt typeFlags = selectIdFromIdentityStatement.ColumnInt(typeFlagsIndex);
       
  1519 		TUid contactType = TCntPersistenceUtility::TypeFlagsToContactTypeUid(typeFlags);
       
  1520 		TContactItemId contactId = selectIdFromIdentityStatement.ColumnInt(idIndex);
       
  1521 		
       
  1522 		if (contactType == KUidContactICCEntry)
       
  1523 			{
       
  1524 			User::LeaveIfError(iContactsFile.ContactProperties().ContactSynchroniserL(aSessionId).ValidateContact(MContactSynchroniser::ESearch,contactId));
       
  1525 			User::LeaveIfError(iContactsFile.ContactProperties().ContactSynchroniserL(aSessionId).ValidateContact(MContactSynchroniser::ERead,contactId));
       
  1526 			}
       
  1527 		// Check that the contact is not already present in the given
       
  1528 		// contact IDs before adding to array.
       
  1529 		if(aIdArray->Find(contactId) == KErrNotFound)
       
  1530 			{
       
  1531 			aIdArray->AddL(contactId);		
       
  1532 			}
       
  1533 		}
       
  1534 	
       
  1535 	return(iterCount == KFindIterations);	
       
  1536 	}
       
  1537 
       
  1538 
       
  1539 /**
       
  1540 Perform an asynchronous find iteration.
       
  1541 
       
  1542 @param aMoreToGo On return ETrue if further iterations are required to complete
       
  1543 the asynchronous find, EFalse otherwise.
       
  1544 @param aSessionId Session ID (only relevant for ICC contacts).
       
  1545 
       
  1546 @return Array of contact ID found in this find iteration.
       
  1547 */
       
  1548 CContactIdArray* CPlCollection::FindAsyncL(TBool& aMoreToGo, TUint aSessionId)
       
  1549 	{
       
  1550 	CContactIdArray* idArray = CContactIdArray::NewLC();
       
  1551 	TBool moreToGo = EFalse;
       
  1552 
       
  1553 	if (iFindWords) // Text definition and "find words".
       
  1554 		{
       
  1555 		TRAPD(err, moreToGo=GetContactIdsForTextDefFindL(idArray, aSessionId));
       
  1556 
       
  1557 		if (err != KErrNone)
       
  1558 			{
       
  1559 			moreToGo = EFalse;
       
  1560 			Reset();
       
  1561 			User::Leave(err);			
       
  1562 			}
       
  1563 
       
  1564 		if(moreToGo == EFalse)
       
  1565 			{
       
  1566 			iFindState |= EFindInTextDefFinished;
       
  1567 			}
       
  1568 		}
       
  1569 	else // Search for a single string.
       
  1570 		{
       
  1571 		if(!(iFindState & EFindInBlobFinished) && (iFindFlags & EFindInAllFields))
       
  1572 			{
       
  1573 			// Search in searchable text (contents of BLOB).
       
  1574 			if(!FindL(idArray, *iText, iFieldDef, selectBlobStatement, aSessionId))
       
  1575 				{
       
  1576 				iFindState |= EFindInBlobFinished;
       
  1577 				}
       
  1578 			else
       
  1579 			    {
       
  1580         		moreToGo = ETrue;
       
  1581 			    }	
       
  1582 			}
       
  1583 
       
  1584 		if(!(iFindState & EFindInIdentityFinished))
       
  1585 			{
       
  1586 			if(SearchIdentityFieldsRequired(iFindFlags))
       
  1587 				{		
       
  1588 				// Search in identity fields.
       
  1589 				if(!PerformFindIterationL(idArray, *iOriginalText, selectIdentityStatement, iFindFlags, aSessionId))
       
  1590 					{
       
  1591 					iFindState |= EFindInIdentityFinished;
       
  1592 					}
       
  1593     			else
       
  1594     			    {
       
  1595             		moreToGo = ETrue;
       
  1596     			    }	
       
  1597 				}
       
  1598 			}
       
  1599 
       
  1600 		if(!(iFindState & EFindInEmailFinished))
       
  1601 			{
       
  1602 			if(iFindFlags & (EFindInAllFields | EFindInEmailField))
       
  1603 				{
       
  1604 				// Search in email fields.		
       
  1605 				if(!PerformIdFindIterationL(idArray, selectEmailStatement))
       
  1606 					{
       
  1607 					iFindState |= EFindInEmailFinished;
       
  1608 					}
       
  1609     			else
       
  1610     			    {
       
  1611             		moreToGo = ETrue;
       
  1612     			    }	
       
  1613 				}
       
  1614 			}
       
  1615 		
       
  1616 		if(!(iFindState & EFindInSIPFinished))
       
  1617 			{
       
  1618 			if(iFindFlags & (EFindInAllFields | EFindInSIPField))
       
  1619 				{
       
  1620 				// Search in email fields.		
       
  1621 				if(!PerformIdFindIterationL(idArray, selectSIPStatement))
       
  1622 					{
       
  1623 					iFindState |= EFindInSIPFinished;
       
  1624 					}
       
  1625     			else
       
  1626     			    {
       
  1627             		moreToGo = ETrue;
       
  1628     			    }	
       
  1629 				}
       
  1630 			}
       
  1631 		}
       
  1632 
       
  1633 
       
  1634     if(!moreToGo)
       
  1635         {
       
  1636 		Reset();
       
  1637         }
       
  1638 
       
  1639 /*        
       
  1640 	// Check if we have finished searching.
       
  1641 	if ((iFindState&(EFindInBlobFinished|EFindInIdentityFinished|EFindInEmailFinished)) == (EFindInBlobFinished|EFindInIdentityFinished|EFindInEmailFinished)
       
  1642 		 || iFindState&EFindInTextDefFinished)
       
  1643 		{
       
  1644 		moreToGo = EFalse;
       
  1645 		Reset();
       
  1646 		}
       
  1647 */
       
  1648 	aMoreToGo = moreToGo;
       
  1649 
       
  1650 	// Pop this off the cleanup stack, as we are passing on ownership to the calling method
       
  1651 	CleanupStack::Pop(idArray);
       
  1652 
       
  1653 	return idArray;
       
  1654 	}
       
  1655 
       
  1656 
       
  1657 /**
       
  1658 Perform a synchronous find for the given text and field definition.
       
  1659 
       
  1660 @param aIdsFound Contacts IDs found.
       
  1661 @param aText Text to search for.
       
  1662 @param aFieldDef Field definition to use.
       
  1663 @param aSessionId Session ID (only relevant for ICC contacts).
       
  1664 
       
  1665 @return ETrue if all iterations have been completed, EFalse otherwise.
       
  1666 */
       
  1667 TBool CPlCollection::FindL(CContactIdArray *aIdsFound, const TDesC& aText,const CContactItemFieldDef *aFieldDef, RSqlStatement aStatement, TUint aSessionId)
       
  1668 	{
       
  1669   	const CContactTemplate& systemTemplate = iContactsFile.ContactProperties().SystemTemplateManager().TemplateL();
       
  1670 
       
  1671 	CContactItemField* field = CContactItemField::NewLC();	// construct just once
       
  1672 
       
  1673 	TInt endOfQueryString = aText.Length()-2;
       
  1674 	TPtrC originalFindText = aText.Mid(1,endOfQueryString);
       
  1675 
       
  1676 	TInt iterCount = 0;
       
  1677 	TInt err;
       
  1678 	
       
  1679 	const TInt idIndex = aStatement.ColumnIndex(KContactId);
       
  1680 	User::LeaveIfError(idIndex);
       
  1681 	const TInt typeFlagsIndex = aStatement.ColumnIndex(KContactTypeFlags);
       
  1682 	User::LeaveIfError(typeFlagsIndex);
       
  1683 	const TInt textHeaderIndex = aStatement.ColumnIndex(KContactTextFieldHeader);
       
  1684 	User::LeaveIfError(textHeaderIndex);
       
  1685 	const TInt textFieldsIndex = aStatement.ColumnIndex(KContactTextFields);
       
  1686 	User::LeaveIfError(textFieldsIndex);
       
  1687 	
       
  1688 	while(iterCount<KFindIterations)
       
  1689 		{
       
  1690 		err = aStatement.Next();
       
  1691 		if(err != KSqlAtRow)
       
  1692 			{
       
  1693 			User::LeaveIfError(err);
       
  1694 			break;
       
  1695 			}
       
  1696 			
       
  1697 		TInt typeFlags = aStatement.ColumnInt(typeFlagsIndex);
       
  1698 		TUid contactType = TCntPersistenceUtility::TypeFlagsToContactTypeUid(typeFlags);
       
  1699 
       
  1700 		if (iContactsFile.ContactProperties().CheckType(contactType) )
       
  1701 			{
       
  1702 			TPtrC8 textHeader;
       
  1703 			aStatement.ColumnBinary(textHeaderIndex, textHeader);
       
  1704 			RDesReadStream textHeaderStream(textHeader);
       
  1705 			CleanupClosePushL(textHeaderStream);
       
  1706 
       
  1707 			CEmbeddedStore* store = CEmbeddedStore::FromLC(textHeaderStream);
       
  1708 			
       
  1709 			TPtrC textFieldPtrC = aStatement.ColumnTextL(textFieldsIndex);
       
  1710 			HBufC *textBuf = HBufC::NewLC(textFieldPtrC.Size());
       
  1711 			textBuf->Des().Copy(textFieldPtrC);
       
  1712 			
       
  1713 			RStoreReadStream rootStream;
       
  1714 			rootStream.OpenLC(*store ,store->Root());
       
  1715 			
       
  1716 			TCardinality  count;
       
  1717 			rootStream >> count;
       
  1718 
       
  1719 			for (TInt i = 0;i < count; ++i)
       
  1720 				{
       
  1721 				field->Reset();
       
  1722 				if (field->RestoreIfMatchL(rootStream,aFieldDef,&systemTemplate.CardFields(),textBuf,i))
       
  1723 					{
       
  1724 					if (field->StorageType() == KStorageTypeText && 
       
  1725 						field->TextStorage()->Text().FindC(originalFindText.Ptr(), 
       
  1726 						originalFindText.Length(), KCollationLevel) != KErrNotFound)
       
  1727 						{
       
  1728 						TContactItemId id = aStatement.ColumnInt(idIndex);
       
  1729 						if(aIdsFound->Find(id) == KErrNotFound)
       
  1730 							{
       
  1731 							if (contactType == KUidContactICCEntry)
       
  1732 								{
       
  1733 								TInt error(iContactsFile.ContactProperties().ContactSynchroniserL(aSessionId).ValidateContact(MContactSynchroniser::ESearch,id));
       
  1734 								User::LeaveIfError(error);
       
  1735 								}
       
  1736 							aIdsFound->AddL(id);
       
  1737 							}
       
  1738 						break;
       
  1739 						}
       
  1740 					}
       
  1741 				}
       
  1742 			CleanupStack::PopAndDestroy(4, &textHeaderStream); // rootStream, textBuf, textHeader, textHeaderStream
       
  1743 			}
       
  1744 		++iterCount;
       
  1745 		}
       
  1746 
       
  1747 	CleanupStack::PopAndDestroy(field); 
       
  1748 
       
  1749 	return(iterCount == KFindIterations);
       
  1750 	}
       
  1751 
       
  1752 /**
       
  1753 Return an over-estimated string size for the amount of syntax required per field
       
  1754 per search string for the Identity table.
       
  1755 
       
  1756 @return Maximum string size required for Identity table search syntax.
       
  1757 */
       
  1758 TInt CPlCollection::MaximumSizeOfIdentitySearchSyntax()
       
  1759 	{
       
  1760 	TInt sqlLitSize;
       
  1761 
       
  1762 	sqlLitSize = KLeftBracket().Length() + KLikeString().Length() +
       
  1763 		KLikeStringRight().Length() + KOR().Length();
       
  1764 
       
  1765 	sqlLitSize *= iNoIdentitySearchColumns;
       
  1766 
       
  1767 	sqlLitSize += KContactFirstName().Length() + KContactLastName().Length() +
       
  1768 		KContactCompanyName().Length();
       
  1769 
       
  1770 	sqlLitSize += KContactFirstNamePrn().Length() +
       
  1771 		KContactLastNamePrn().Length() +
       
  1772 		KContactCompanyNamePrn().Length();
       
  1773 
       
  1774 	return(sqlLitSize);
       
  1775 	}
       
  1776 	
       
  1777 /**
       
  1778 Determine the approximate size of the string required to construct the SQL query
       
  1779 on the Identity table when using the "find words".
       
  1780 
       
  1781 @return Approximate size of search string.
       
  1782 */
       
  1783 TInt CPlCollection::ApproximateSizeOfSearchString()
       
  1784 	{
       
  1785 	TInt sqlLitSize = MaximumSizeOfIdentitySearchSyntax();
       
  1786 
       
  1787 	TInt noOfFindWords=iFindWords2->Count();
       
  1788 	TInt size=0;
       
  1789 
       
  1790 	for(TInt searchWord=0;searchWord < noOfFindWords; ++searchWord)
       
  1791 		{
       
  1792 		size += (*iFindWords2)[searchWord].Length();
       
  1793 		}
       
  1794 	
       
  1795 	TInt totalSize = noOfFindWords*sqlLitSize + iNoIdentitySearchColumns*size + 256;
       
  1796 	
       
  1797 	return totalSize;
       
  1798 	}
       
  1799 	
       
  1800 /**
       
  1801 Utility method used to filter hint fields
       
  1802 */	
       
  1803 TBool CPlCollection::HintFieldMatchesFilter(TInt aHintField, TInt aFilter)
       
  1804 	{
       
  1805 	TBool match=EFalse;
       
  1806 
       
  1807 	if (aFilter==CContactDatabase::EUnfiltered)
       
  1808 		{
       
  1809 		return ETrue;
       
  1810 		}
       
  1811 
       
  1812 	if (aFilter & ~aHintField & (CContactDatabase::EWork | CContactDatabase::EHome))
       
  1813 		{
       
  1814 		return EFalse;
       
  1815 		}
       
  1816 
       
  1817 	match = aFilter & aHintField
       
  1818 		& (
       
  1819 			  CContactDatabase::ELandLine
       
  1820 			| CContactDatabase::ESmsable
       
  1821 			| CContactDatabase::EMailable
       
  1822 			| CContactDatabase::EFaxable
       
  1823 			| CContactDatabase::EPhonable
       
  1824 			| CContactDatabase::ERingTone
       
  1825 			| CContactDatabase::EVoiceDial
       
  1826 			| CContactDatabase::EIMAddress
       
  1827 			| CContactDatabase::EWirelessVillage
       
  1828 			| CContactDatabase::ECustomFilter1
       
  1829 			| CContactDatabase::ECustomFilter2
       
  1830 			| CContactDatabase::ECustomFilter3
       
  1831 			| CContactDatabase::ECustomFilter4
       
  1832 			);
       
  1833 
       
  1834 	return match;
       
  1835 	}