|
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 #include "pltables.h" |
|
17 #include "dbsqlconstants.h" |
|
18 #include "plplugins.h" |
|
19 #include <cntdb.h> |
|
20 #ifdef SYMBIAN_ENABLE_SPLIT_HEADERS |
|
21 #include <cntphonenumparser.h> |
|
22 #endif |
|
23 |
|
24 /// Unnamed namespace for local definitions |
|
25 namespace { |
|
26 |
|
27 TBool ComparePtr( const TPtrC* aLeft, const TPtrC& aRight ) |
|
28 { |
|
29 return ( aLeft->Compare( aRight )== 0 ); |
|
30 } |
|
31 |
|
32 } /// namespace |
|
33 |
|
34 /** |
|
35 @param aDatabase A handle to the database. |
|
36 @param aProperties A contact properties object. |
|
37 |
|
38 @return A pointer to a new CPplCommAddrTable object. |
|
39 */ |
|
40 CPplCommAddrTable* CPplCommAddrTable::NewL(RSqlDatabase& aDatabase, CLplContactProperties& aProperties) |
|
41 { |
|
42 CPplCommAddrTable* self = CPplCommAddrTable::NewLC(aDatabase, aProperties); |
|
43 CleanupStack::Pop(self); |
|
44 return self; |
|
45 } |
|
46 |
|
47 |
|
48 /** |
|
49 @param aDatabase A handle to the database. |
|
50 @param aProperties A contact properties object. |
|
51 |
|
52 @return A pointer to a new CPplCommAddrTable object. |
|
53 */ |
|
54 CPplCommAddrTable* CPplCommAddrTable::NewLC(RSqlDatabase& aDatabase, CLplContactProperties& aProperties) |
|
55 { |
|
56 CPplCommAddrTable* self = new (ELeave) CPplCommAddrTable(aDatabase, aProperties); |
|
57 CleanupStack::PushL(self); |
|
58 self->ConstructL(); |
|
59 return self; |
|
60 } |
|
61 |
|
62 /** |
|
63 Set up the CCntSqlStatement objects held by the class. |
|
64 */ |
|
65 void CPplCommAddrTable::ConstructL() |
|
66 { |
|
67 // Statement types |
|
68 TCntSqlStatementType insertType(EInsert, KSqlContactCommAddrTableName() ); |
|
69 TCntSqlStatementType selectType(ESelect, KSqlContactCommAddrTableName() ); |
|
70 TCntSqlStatementType updateType(EUpdate, KSqlContactCommAddrTableName() ); |
|
71 TCntSqlStatementType deleteType(EDelete, KSqlContactCommAddrTableName() ); |
|
72 |
|
73 // Where clauses |
|
74 |
|
75 // sizes of the clauses |
|
76 const TInt KWhereContactIdBufSize(KCommAddrContactId().Size() + |
|
77 KWhereStringEqualsStringFormatText().Size() + KCommAddrContactIdParam().Size() ); |
|
78 const TInt KWhereCommAddrIdBufSize(KCommAddrId().Size() + |
|
79 KWhereStringEqualsStringFormatText().Size() + KCommAddrIdParam().Size() ); |
|
80 const TInt KWhereAndClauseBufSize(KWhereCommAddrIdBufSize + KSqlAnd().Size() + KWhereCommAddrIdBufSize); |
|
81 |
|
82 HBufC* whereContactIdClause = HBufC::NewLC(KWhereContactIdBufSize); |
|
83 // for WHERE contact_id = [contact id value] |
|
84 whereContactIdClause->Des().AppendFormat(KWhereStringEqualsStringFormatText, |
|
85 &KCommAddrContactId, &KCommAddrContactIdParam ); |
|
86 |
|
87 // for WHERE comm_addr_id = [comm addr id value] |
|
88 HBufC* whereCommAddrIdClause = HBufC::NewLC(KWhereCommAddrIdBufSize); |
|
89 whereCommAddrIdClause->Des().AppendFormat(KWhereStringEqualsStringFormatText, |
|
90 &KCommAddrId, &KCommAddrIdParam ); |
|
91 |
|
92 // for WHERE value = [value string] AND type = [type value] |
|
93 HBufC* whereValueAndTypeClause = HBufC::NewLC(KWhereAndClauseBufSize); |
|
94 TPtr whereValueAndTypeClausePtr = whereValueAndTypeClause->Des(); |
|
95 whereValueAndTypeClausePtr.AppendFormat(KWhereStringEqualsStringFormatText, |
|
96 &KCommAddrValue, &KCommAddrValueParam ); |
|
97 whereValueAndTypeClausePtr.Append(KSqlAnd); |
|
98 whereValueAndTypeClausePtr.AppendFormat(KWhereStringEqualsStringFormatText, |
|
99 &KCommAddrType, &KCommAddrTypeParam ); |
|
100 |
|
101 // INSERT |
|
102 |
|
103 // insert new comm addr record |
|
104 // INSERT INTO comm_addr |
|
105 // (comm_addr_id, contact_id, type, value, extra_value) |
|
106 // VALUES (NULL, [contact id value], [type value], |
|
107 // [value string], [extra value string]); |
|
108 // |
|
109 iInsertStmnt = TSqlProvider::GetSqlStatementL(insertType); |
|
110 iInsertStmnt->SetParamL(KCommAddrId(), KCommAddrIdParam() ); |
|
111 iInsertStmnt->SetParamL(KCommAddrContactId(), KCommAddrContactIdParam() ); |
|
112 iInsertStmnt->SetParamL(KCommAddrValue(), KCommAddrValueParam() ); |
|
113 iInsertStmnt->SetParamL(KCommAddrExtraValue(), KCommAddrExtraValueParam() ); |
|
114 iInsertStmnt->SetParamL(KCommAddrType(), KCommAddrTypeParam() ); |
|
115 |
|
116 // SELECT |
|
117 |
|
118 // select all fields for all comm addrs for a particular item id |
|
119 // For a statement in the following format: |
|
120 // SELECT comm_addr_id, type, value, extra_value FROM comm_addr |
|
121 // WHERE contact_id = [contact id value]; |
|
122 // |
|
123 iWholeSelectStmnt = TSqlProvider::GetSqlStatementL(selectType); |
|
124 iWholeSelectStmnt->SetParamL(KCommAddrId(), KNullDesC() ); |
|
125 iWholeSelectStmnt->SetParamL(KCommAddrType(), KNullDesC() ); |
|
126 iWholeSelectStmnt->SetParamL(KCommAddrValue(), KNullDesC() ); |
|
127 iWholeSelectStmnt->SetParamL(KCommAddrExtraValue(), KNullDesC() ); |
|
128 iWholeSelectStmnt->SetConditionL(*whereContactIdClause); |
|
129 |
|
130 // select fields for contacts that match phone, email or SIP lookup |
|
131 // For a statement in the following format: |
|
132 // SELECT contact_id, extra_value FROM comm_addr |
|
133 // WHERE value = [value string] AND type = [type value]; |
|
134 // |
|
135 iMatchSelectStmnt = TSqlProvider::GetSqlStatementL(selectType); |
|
136 iMatchSelectStmnt->SetParamL(KCommAddrContactId(), KNullDesC() ); |
|
137 iMatchSelectStmnt->SetParamL(KCommAddrExtraValue(), KNullDesC() ); |
|
138 iMatchSelectStmnt->SetConditionL(*whereValueAndTypeClause); |
|
139 |
|
140 // UPDATE |
|
141 |
|
142 // update comm addr record |
|
143 // For a statement in the following format: |
|
144 // UPDATE comm_addr SET |
|
145 // contact_id = [contact id value], |
|
146 // type = [type value], |
|
147 // value = [value string], |
|
148 // extra_value = [extra value string] |
|
149 // WHERE comm_addr_id = [comm addr id value]; |
|
150 // |
|
151 iUpdateStmnt = TSqlProvider::GetSqlStatementL(updateType); |
|
152 iUpdateStmnt->SetParamL(KCommAddrContactId(), KCommAddrContactIdParam() ); |
|
153 iUpdateStmnt->SetParamL(KCommAddrValue(), KCommAddrValueParam() ); |
|
154 iUpdateStmnt->SetParamL(KCommAddrExtraValue(), KCommAddrExtraValueParam() ); |
|
155 iUpdateStmnt->SetParamL(KCommAddrType(), KCommAddrTypeParam() ); |
|
156 iUpdateStmnt->SetConditionL(*whereCommAddrIdClause); |
|
157 |
|
158 // DELETE |
|
159 |
|
160 // delete single comm addr record |
|
161 // For a statement in the following format: |
|
162 // DELETE FROM comm_addr WHERE comm_addr_id = [comm addr id value]; |
|
163 // |
|
164 iSingleDeleteStmnt = TSqlProvider::GetSqlStatementL(deleteType); |
|
165 iSingleDeleteStmnt->SetConditionL(*whereCommAddrIdClause); |
|
166 |
|
167 // delete all comm addrs for a particular contact item |
|
168 // For a statement in the following format: |
|
169 // DELETE FROM comm_addr WHERE contact_id = [contact id value]; |
|
170 // |
|
171 iAllForItemDeleteStmnt = TSqlProvider::GetSqlStatementL(deleteType); |
|
172 iAllForItemDeleteStmnt->SetConditionL(*whereContactIdClause); |
|
173 |
|
174 CleanupStack::PopAndDestroy(3, whereContactIdClause); // and whereCommAddrIdClause, whereValueAndTypeClause |
|
175 } |
|
176 |
|
177 |
|
178 /** |
|
179 Insert new communication addresses into the comm_addr table. |
|
180 @param aItem A contact item whose communication addresses are to be added to the contacts database. |
|
181 */ |
|
182 void CPplCommAddrTable::CreateInDbL(CContactItem& aItem) |
|
183 { |
|
184 // Check that the contact item is a card, own card or ICC entry. |
|
185 const TUid KType = aItem.Type(); |
|
186 if (KType != KUidContactCard && KType != KUidContactOwnCard && KType != KUidContactICCEntry) |
|
187 { |
|
188 return; |
|
189 } |
|
190 |
|
191 // create lists for comm_addrs to keep track of what we have already seen so as to avoid duplicates |
|
192 RArray<TMatch> newPhones; |
|
193 RArray<TPtrC> newEmails; |
|
194 RArray<TPtrC> newSips; |
|
195 CleanupClosePushL(newPhones); |
|
196 CleanupClosePushL(newEmails); |
|
197 CleanupClosePushL(newSips); |
|
198 |
|
199 for (TInt fieldNum = aItem.CardFields().Count() - 1; fieldNum >= 0; --fieldNum) |
|
200 { |
|
201 CContactItemField& currField = aItem.CardFields()[fieldNum]; |
|
202 const CContentType& contType = currField.ContentType(); |
|
203 TBool isPhone(contType.ContainsFieldType(KUidContactFieldPhoneNumber) || |
|
204 contType.ContainsFieldType(KUidContactFieldFax) || |
|
205 contType.ContainsFieldType(KUidContactFieldSms) ); |
|
206 TBool isEmail(contType.ContainsFieldType(KUidContactFieldEMail) ); |
|
207 TBool isSip(contType.ContainsFieldType(KUidContactFieldSIPID) ); |
|
208 |
|
209 // check it's a field we want and that it's not empty |
|
210 // insert a new address only if we haven't already seen it -- no point storing the same one twice. |
|
211 if ((isPhone || isEmail || isSip) && currField.StorageType() == KStorageTypeText |
|
212 && currField.TextStorage()->IsFull() ) |
|
213 { |
|
214 const TContactItemId KItemId(aItem.Id()); |
|
215 |
|
216 // get phone numbers |
|
217 if (isPhone) |
|
218 { |
|
219 TMatch phoneNumber; |
|
220 phoneNumber = CreatePaddedPhoneDigitsL(currField.TextStorage()->Text(), KLowerSevenDigits, |
|
221 KMaxPhoneMatchLength - KLowerSevenDigits); |
|
222 if (newPhones.Find(phoneNumber, TIdentityRelation<TMatch>(&TMatch::Equals) ) == KErrNotFound) |
|
223 { |
|
224 DoPhoneNumWriteOpL(phoneNumber, EInsert, KItemId); |
|
225 newPhones.AppendL(phoneNumber); |
|
226 } |
|
227 } |
|
228 // get email addresses |
|
229 else if (isEmail) |
|
230 { |
|
231 if (newEmails.Find( currField.TextStorage()->Text(), ComparePtr ) == KErrNotFound) |
|
232 { |
|
233 DoNonPhoneWriteOpL(currField.TextStorage()->Text(), EInsert, KItemId, EEmailAddress); |
|
234 newEmails.AppendL(currField.TextStorage()->Text() ); |
|
235 } |
|
236 } |
|
237 // get SIP addresses |
|
238 else if (newSips.Find(currField.TextStorage()->Text() ) == KErrNotFound) |
|
239 { |
|
240 DoNonPhoneWriteOpL(currField.TextStorage()->Text(), EInsert, KItemId, ESipAddress); |
|
241 newSips.AppendL(currField.TextStorage()->Text() ); |
|
242 } |
|
243 } |
|
244 } |
|
245 |
|
246 CleanupStack::PopAndDestroy(3, &newPhones); // and newSips, newEmails |
|
247 } |
|
248 |
|
249 |
|
250 /** |
|
251 Updates communication addresses in the database. |
|
252 |
|
253 If there are the same number of items to be updated as are already in the database, the |
|
254 existing records are overwritten using the update statement. However, if there is a |
|
255 different number of addresses to be updated, records in the database (if there are any) |
|
256 are deleted (using DeleteL() ) and the new data is inserted (using CreateInDbL() ). |
|
257 |
|
258 @param aItem A contact item whose communication addresses are to be updated in the contacts database. |
|
259 */ |
|
260 void CPplCommAddrTable::UpdateL(const CContactItem& aItem) |
|
261 { |
|
262 // Check that the contact item is a card, own card or ICC entry. |
|
263 const TUid type(aItem.Type() ); |
|
264 if (type != KUidContactCard && type != KUidContactOwnCard && type != KUidContactICCEntry) |
|
265 { |
|
266 return; |
|
267 } |
|
268 |
|
269 const TContactItemId KItemId(aItem.Id() ); |
|
270 |
|
271 // create lists for comm_addrs and go through contact item to populate them with any new ones we find |
|
272 RArray<TMatch> newPhones; |
|
273 RArray<TPtrC> newEmails; |
|
274 RArray<TPtrC> newSips; |
|
275 CleanupClosePushL(newPhones); |
|
276 CleanupClosePushL(newEmails); |
|
277 CleanupClosePushL(newSips); |
|
278 |
|
279 for (TInt fieldNum = aItem.CardFields().Count() - 1; fieldNum >= 0; --fieldNum) |
|
280 { |
|
281 CContactItemField& currField = aItem.CardFields()[fieldNum]; |
|
282 const CContentType& contType = currField.ContentType(); |
|
283 TBool isPhone(contType.ContainsFieldType(KUidContactFieldPhoneNumber) || |
|
284 contType.ContainsFieldType(KUidContactFieldFax) || |
|
285 contType.ContainsFieldType(KUidContactFieldSms) ); |
|
286 TBool isEmail(contType.ContainsFieldType(KUidContactFieldEMail) ); |
|
287 TBool isSip(contType.ContainsFieldType(KUidContactFieldSIPID) ); |
|
288 |
|
289 // check it's a field we want and that it's not empty |
|
290 // store a new address if we haven't already seen it -- no point storing the same one twice. |
|
291 if ((isPhone || isEmail || isSip) && currField.StorageType() == KStorageTypeText |
|
292 && currField.TextStorage()->IsFull() ) |
|
293 { |
|
294 // get phone numbers |
|
295 if (isPhone) |
|
296 { |
|
297 TMatch phoneNumber; |
|
298 phoneNumber = CreatePaddedPhoneDigitsL(currField.TextStorage()->Text(), KLowerSevenDigits, |
|
299 KMaxPhoneMatchLength - KLowerSevenDigits); |
|
300 if (newPhones.Find(phoneNumber, TIdentityRelation<TMatch>(&TMatch::Equals) ) == KErrNotFound) |
|
301 { |
|
302 newPhones.AppendL(phoneNumber); |
|
303 } |
|
304 } |
|
305 // get email addresses |
|
306 else if (isEmail) |
|
307 { |
|
308 if (newEmails.Find(currField.TextStorage()->Text(), ComparePtr ) == KErrNotFound) |
|
309 { |
|
310 newEmails.AppendL(currField.TextStorage()->Text() ); |
|
311 } |
|
312 } |
|
313 // get SIP addresses |
|
314 else if (newSips.Find(currField.TextStorage()->Text() ) == KErrNotFound) |
|
315 { |
|
316 newSips.AppendL(currField.TextStorage()->Text() ); |
|
317 } |
|
318 } |
|
319 } |
|
320 |
|
321 // if there are no comm addresses in the contact item, delete any from the database |
|
322 if (!(newPhones.Count() + newEmails.Count() + newSips.Count() ) ) |
|
323 { |
|
324 TBool lowDiskErr(EFalse); |
|
325 DeleteL(aItem, lowDiskErr); |
|
326 CleanupStack::PopAndDestroy(3, &newPhones); // and newSips, newEmails |
|
327 if (lowDiskErr) |
|
328 { |
|
329 User::Leave(KErrDiskFull); |
|
330 } |
|
331 return; |
|
332 } |
|
333 |
|
334 // create from the database a list of comm_addr_ids that can be recycled as their |
|
335 // comm_addrs are in the database but not in the new version of the contact item |
|
336 RArray<TInt> freeCommAddrIds; |
|
337 CleanupClosePushL(freeCommAddrIds); |
|
338 |
|
339 // weed out addresses from the list that are already in the db but haven't changed |
|
340 // and populate the freeCommAddrIds list |
|
341 RemoveNonUpdatedAddrsL(newPhones, newEmails, newSips, freeCommAddrIds, KItemId); |
|
342 |
|
343 // do the actual updating on an address-by-address basis |
|
344 DoUpdateCommAddrsL(newPhones, newEmails, newSips, freeCommAddrIds, KItemId); |
|
345 |
|
346 CleanupStack::PopAndDestroy(4, &newPhones); // and freeCommAddrIds, newSips, newEmails |
|
347 } |
|
348 |
|
349 |
|
350 /** |
|
351 Removes comm addresses from the 3 lists that are already in the database and have been updated. |
|
352 It takes the 3 lists in as parameters and modifies them accordingly. It also populates the list |
|
353 of comm address ids that are free to be recycled during updating. |
|
354 */ |
|
355 void CPplCommAddrTable::RemoveNonUpdatedAddrsL(RArray<TMatch>& aNewPhones, RArray<TPtrC>& aNewEmails, RArray<TPtrC>& aNewSips, |
|
356 RArray<TInt>& aFreeCommAddrIds, const TInt aItemId) |
|
357 { |
|
358 // build the RSqlStatement |
|
359 RSqlStatement stmnt; |
|
360 CleanupClosePushL(stmnt); |
|
361 stmnt.PrepareL(iDatabase, iWholeSelectStmnt->SqlStringL() ); |
|
362 const TInt KContactIdParamIndex(KFirstIndex); // first and only parameter in the query |
|
363 User::LeaveIfError(stmnt.BindInt(KContactIdParamIndex, aItemId) ) ; |
|
364 |
|
365 // fetch the results from the query and compare them with the new comm_addrs we have |
|
366 TInt err(KErrNone); |
|
367 while ((err = stmnt.Next() ) == KSqlAtRow) |
|
368 { |
|
369 const TInt KType(stmnt.ColumnInt(iWholeSelectStmnt->ParameterIndex(KCommAddrType() ) ) ); |
|
370 if (KType == EPhoneNumber) |
|
371 { |
|
372 TMatch phoneNumber; |
|
373 TPtrC valString = stmnt.ColumnTextL(iWholeSelectStmnt->ParameterIndex(KCommAddrValue() ) ); |
|
374 TPtrC extValString = stmnt.ColumnTextL(iWholeSelectStmnt->ParameterIndex(KCommAddrExtraValue() ) ); |
|
375 User::LeaveIfError(TLex(valString).Val(phoneNumber.iLowerSevenDigits) ); |
|
376 User::LeaveIfError(TLex(extValString).Val(phoneNumber.iUpperDigits) ); |
|
377 |
|
378 TInt matchIndex(aNewPhones.Find(phoneNumber, TIdentityRelation<TMatch>(&TMatch::Equals) ) ); |
|
379 // remove any phone numbers from the new list if we already |
|
380 // have them in the db and they haven't changed... |
|
381 if (matchIndex != KErrNotFound) |
|
382 { |
|
383 aNewPhones.Remove(matchIndex); |
|
384 } |
|
385 // ...and add any spare ids to the recycle list |
|
386 else |
|
387 { |
|
388 aFreeCommAddrIds.AppendL( |
|
389 stmnt.ColumnInt(iWholeSelectStmnt->ParameterIndex(KCommAddrId() ) ) ); |
|
390 } |
|
391 } |
|
392 else // is Email or SIP |
|
393 { |
|
394 TPtrC valString = stmnt.ColumnTextL(iWholeSelectStmnt->ParameterIndex(KCommAddrValue() ) ); |
|
395 TInt matchIndex(0); |
|
396 |
|
397 // remove any email and sip addresses from the new list if |
|
398 // we already have them in the db and they haven't changed... |
|
399 if (KType == EEmailAddress) |
|
400 { |
|
401 matchIndex = aNewEmails.Find( valString, ComparePtr ); |
|
402 if (matchIndex != KErrNotFound) |
|
403 { |
|
404 aNewEmails.Remove(matchIndex); |
|
405 } |
|
406 } |
|
407 else // SIP |
|
408 { |
|
409 matchIndex = aNewSips.Find(valString); |
|
410 if (matchIndex != KErrNotFound) |
|
411 { |
|
412 aNewSips.Remove(matchIndex); |
|
413 } |
|
414 } |
|
415 |
|
416 // ...and add any spare ids to the recycle list |
|
417 if (matchIndex == KErrNotFound) |
|
418 { |
|
419 aFreeCommAddrIds.AppendL( |
|
420 stmnt.ColumnInt(iWholeSelectStmnt->ParameterIndex(KCommAddrId() ) ) ); |
|
421 } |
|
422 } |
|
423 } |
|
424 // leave if we didn't complete going through the results properly |
|
425 if(err != KSqlAtEnd) |
|
426 { |
|
427 User::Leave(err); |
|
428 } |
|
429 CleanupStack::PopAndDestroy(&stmnt); |
|
430 } |
|
431 |
|
432 |
|
433 /** |
|
434 Does comm_addr updating on an address-by-address basis. |
|
435 Takes 3 lists of new addresses and a list of free comm_addr_ids. |
|
436 */ |
|
437 void CPplCommAddrTable::DoUpdateCommAddrsL(RArray<TMatch>& aNewPhones, RArray<TPtrC>& aNewEmails, RArray<TPtrC>& aNewSips, |
|
438 RArray<TInt>& aFreeCommAddrIds, const TInt aItemId) |
|
439 { |
|
440 // if we have free ids to recycle and new comm_addrs, insert them by UPDATE |
|
441 const TInt KFirstElementId(0); |
|
442 while (aFreeCommAddrIds.Count() && (aNewPhones.Count() || aNewEmails.Count() || aNewSips.Count() ) ) |
|
443 { |
|
444 if(aNewPhones.Count() ) |
|
445 { |
|
446 DoPhoneNumWriteOpL(aNewPhones[KFirstElementId], EUpdate, aItemId, aFreeCommAddrIds[KFirstElementId]); |
|
447 aNewPhones.Remove(KFirstElementId); |
|
448 aFreeCommAddrIds.Remove(KFirstElementId); |
|
449 } |
|
450 else if(aNewEmails.Count() ) |
|
451 { |
|
452 DoNonPhoneWriteOpL(aNewEmails[KFirstElementId], EUpdate, aItemId, EEmailAddress, |
|
453 aFreeCommAddrIds[KFirstElementId]); |
|
454 aNewEmails.Remove(KFirstElementId); |
|
455 aFreeCommAddrIds.Remove(KFirstElementId); |
|
456 } |
|
457 else if(aNewSips.Count() ) |
|
458 { |
|
459 DoNonPhoneWriteOpL(aNewSips[KFirstElementId], EUpdate, aItemId, ESipAddress, |
|
460 aFreeCommAddrIds[KFirstElementId]); |
|
461 aNewSips.Remove(KFirstElementId); |
|
462 aFreeCommAddrIds.Remove(KFirstElementId); |
|
463 } |
|
464 } |
|
465 |
|
466 // if we still have free ids to recycle but no new comm_addrs, |
|
467 // delete the existing comm_addrs for these ids |
|
468 const TInt KNumFreeIds(aFreeCommAddrIds.Count() ); |
|
469 for (TInt i = 0; i < KNumFreeIds; ++i) |
|
470 { |
|
471 TBool lowDiskErr(EFalse); |
|
472 DeleteSingleCommAddrL(aFreeCommAddrIds[i], lowDiskErr); |
|
473 if (lowDiskErr) |
|
474 { |
|
475 User::Leave(KErrDiskFull); |
|
476 } |
|
477 } |
|
478 |
|
479 // if we still have new comm_addrs but no free ids to recycle, |
|
480 // put them in the database using INSERT |
|
481 const TInt KNumNewPhones(aNewPhones.Count() ); |
|
482 const TInt KNumNewEmails(aNewEmails.Count() ); |
|
483 const TInt KNumNewSips(aNewSips.Count() ); |
|
484 for (TInt i = 0; i < KNumNewPhones; ++i) |
|
485 { |
|
486 DoPhoneNumWriteOpL(aNewPhones[i], EInsert, aItemId); |
|
487 } |
|
488 for (TInt i = 0; i < KNumNewEmails; ++i) |
|
489 { |
|
490 DoNonPhoneWriteOpL(aNewEmails[i], EInsert, aItemId, EEmailAddress); |
|
491 } |
|
492 for (TInt i = 0; i < KNumNewSips; ++i) |
|
493 { |
|
494 DoNonPhoneWriteOpL(aNewSips[i], EInsert, aItemId, ESipAddress); |
|
495 } |
|
496 } |
|
497 |
|
498 |
|
499 /** |
|
500 Deletes individual communication addresses from the database. In other words, deletes at |
|
501 the sub-contact item level rather than deleting everything with a specific contact item ID. |
|
502 */ |
|
503 void CPplCommAddrTable::DeleteSingleCommAddrL(TInt aCommAddrId, TBool& aLowDiskErrorOccurred) |
|
504 { |
|
505 RSqlStatement stmnt; |
|
506 CleanupClosePushL(stmnt); |
|
507 stmnt.PrepareL(iDatabase, iSingleDeleteStmnt->SqlStringL() ); |
|
508 const TInt KCommAddrIdParamIndex(KFirstIndex); // first and only parameter in the query |
|
509 User::LeaveIfError(stmnt.BindInt(KCommAddrIdParamIndex, aCommAddrId ) ); |
|
510 TInt err = stmnt.Exec(); |
|
511 CleanupStack::PopAndDestroy(&stmnt); |
|
512 |
|
513 if (err == KErrDiskFull) |
|
514 { |
|
515 aLowDiskErrorOccurred = ETrue; |
|
516 } |
|
517 else |
|
518 { |
|
519 User::LeaveIfError(err); |
|
520 } |
|
521 } |
|
522 |
|
523 /** |
|
524 Performs write operations for individual communication addresses of type "phone number". |
|
525 This version of the method does not require a CommAddrId argument. Therefore, this can only be used |
|
526 for insertion and not updating. |
|
527 */ |
|
528 void CPplCommAddrTable::DoPhoneNumWriteOpL(const CPplCommAddrTable::TMatch& aPhoneNum, TCntSqlStatement aType, |
|
529 TInt aCntId) |
|
530 { |
|
531 // provide a commaddr of 0 as a default argument |
|
532 DoPhoneNumWriteOpL(aPhoneNum, aType, aCntId, 0); |
|
533 } |
|
534 |
|
535 |
|
536 /** |
|
537 Performs write (Insert/Update) operations for indiviual communication addresses of type "phone number". |
|
538 */ |
|
539 void CPplCommAddrTable::DoPhoneNumWriteOpL(const CPplCommAddrTable::TMatch& aPhoneNum, TCntSqlStatement aType, |
|
540 TInt aCntId, TInt aCommAddrId) |
|
541 { |
|
542 // leave if the statement type is not insert or update. |
|
543 // also, we can't update if aCommAddrId is 0 as we don't know the record's id |
|
544 if ((aType != EUpdate && aType != EInsert) || (aType == EUpdate && aCommAddrId == 0) ) |
|
545 { |
|
546 User::Leave(KErrArgument); |
|
547 } |
|
548 |
|
549 RSqlStatement stmnt; |
|
550 CleanupClosePushL(stmnt); |
|
551 |
|
552 // temporary reference to the CCntSqlStatements member variables to take advantage |
|
553 // of the commonality between update and insert operations. |
|
554 CCntSqlStatement* tempCntStmnt = iUpdateStmnt; |
|
555 if (aType == EInsert) |
|
556 { |
|
557 tempCntStmnt = iInsertStmnt; |
|
558 } |
|
559 |
|
560 User::LeaveIfError(stmnt.Prepare(iDatabase, tempCntStmnt->SqlStringL() ) ); |
|
561 User::LeaveIfError(stmnt.BindInt(tempCntStmnt->ParameterIndex(KCommAddrContactId() ), aCntId) ); |
|
562 User::LeaveIfError(stmnt.BindInt(tempCntStmnt->ParameterIndex(KCommAddrExtraValue() ), aPhoneNum.iUpperDigits) ); |
|
563 User::LeaveIfError(stmnt.BindInt(tempCntStmnt->ParameterIndex(KCommAddrValue() ), aPhoneNum.iLowerSevenDigits) ); |
|
564 User::LeaveIfError(stmnt.BindInt(tempCntStmnt->ParameterIndex(KCommAddrType() ), EPhoneNumber) ); |
|
565 |
|
566 if (aType == EInsert) |
|
567 { |
|
568 User::LeaveIfError(stmnt.BindNull(tempCntStmnt->ParameterIndex(KCommAddrId() ) ) ); |
|
569 } |
|
570 else |
|
571 { |
|
572 // it's the fifth parameter in the query and is in the WHERE |
|
573 // clause so we can't get its index from the CCntSqlStatement |
|
574 const TInt KCommAddrIdParamIndex(KFirstIndex + 4); |
|
575 User::LeaveIfError(stmnt.BindInt(KCommAddrIdParamIndex, aCommAddrId) ); |
|
576 } |
|
577 |
|
578 User::LeaveIfError(stmnt.Exec() ); |
|
579 CleanupStack::PopAndDestroy(&stmnt); |
|
580 } |
|
581 |
|
582 |
|
583 /** |
|
584 Performs write operations for individual communication addresses of type "email" or "SIP" address. |
|
585 This version of the method does not require a CommAddrId argument. Therefore, this can only be used |
|
586 for insertion and not updating. |
|
587 */ |
|
588 void CPplCommAddrTable::DoNonPhoneWriteOpL(const TDesC& aAddress, const TCntSqlStatement aType, |
|
589 TInt aCntId, TCommAddrType aAddrType) |
|
590 { |
|
591 // provide a commaddr of 0 as a default argument |
|
592 DoNonPhoneWriteOpL(aAddress, aType, aCntId, aAddrType, 0); |
|
593 } |
|
594 |
|
595 |
|
596 /** |
|
597 Performs write (Insert/Update) operations for indiviual communication addresses of |
|
598 type "Email address" or "SIP Address". |
|
599 */ |
|
600 void CPplCommAddrTable::DoNonPhoneWriteOpL(const TDesC& aAddress, const TCntSqlStatement aType, |
|
601 TInt aCntId, TCommAddrType aAddrType, TInt aCommAddrId) |
|
602 { |
|
603 // leave if the statement type is not insert or update. |
|
604 // also, we can't update if aCommAddrId is 0 as we don't know the record's id |
|
605 if ((aType != EUpdate && aType != EInsert) || (aType == EUpdate && aCommAddrId == 0) ) |
|
606 { |
|
607 User::Leave(KErrNotFound); |
|
608 } |
|
609 |
|
610 RSqlStatement stmnt; |
|
611 CleanupClosePushL(stmnt); |
|
612 |
|
613 // temporary reference to the CCntSqlStatements member variables to take advantage |
|
614 // of the commonality between update and insert operations. |
|
615 CCntSqlStatement* tempCntStmnt = iUpdateStmnt; |
|
616 if (aType == EInsert) |
|
617 { |
|
618 tempCntStmnt = iInsertStmnt; |
|
619 } |
|
620 |
|
621 User::LeaveIfError(stmnt.Prepare(iDatabase, tempCntStmnt->SqlStringL() ) ); |
|
622 User::LeaveIfError(stmnt.BindInt(tempCntStmnt->ParameterIndex(KCommAddrContactId() ), aCntId) ); |
|
623 User::LeaveIfError(stmnt.BindText(tempCntStmnt->ParameterIndex(KCommAddrValue() ), aAddress) ); |
|
624 User::LeaveIfError(stmnt.BindNull(tempCntStmnt->ParameterIndex(KCommAddrExtraValue() ) ) ); |
|
625 User::LeaveIfError(stmnt.BindInt(tempCntStmnt->ParameterIndex(KCommAddrType() ), aAddrType) ); |
|
626 |
|
627 if (aType == EInsert) |
|
628 { |
|
629 User::LeaveIfError(stmnt.BindNull(tempCntStmnt->ParameterIndex(KCommAddrId() ) ) ); |
|
630 } |
|
631 else |
|
632 { |
|
633 // it's the fifth parameter in the query and is in the WHERE |
|
634 // clause so we can't get its index from the CCntSqlStatement |
|
635 const TInt KCommAddrIdParamIndex(KFirstIndex + 4); |
|
636 User::LeaveIfError(stmnt.BindInt(KCommAddrIdParamIndex, aCommAddrId) ); |
|
637 } |
|
638 |
|
639 User::LeaveIfError(stmnt.Exec() ); |
|
640 CleanupStack::PopAndDestroy(&stmnt); |
|
641 } |
|
642 |
|
643 |
|
644 /** |
|
645 Deletes all the communication addresses for a particular contact item. Should be used when |
|
646 deleting a contact item from the database altogether. |
|
647 |
|
648 @param aItem The contact item whose communcation addresses are to be deleted. |
|
649 */ |
|
650 void CPplCommAddrTable::DeleteL(const CContactItem& aItem, TBool& aLowDiskErrorOccurred) |
|
651 { |
|
652 const TUid KType = aItem.Type(); |
|
653 if (KType != KUidContactCard && KType != KUidContactOwnCard && KType != KUidContactICCEntry) |
|
654 { |
|
655 return; |
|
656 } |
|
657 |
|
658 RSqlStatement stmnt; |
|
659 CleanupClosePushL(stmnt); |
|
660 stmnt.PrepareL(iDatabase, iAllForItemDeleteStmnt->SqlStringL() ); |
|
661 const TInt KContactIdParamIndex(KFirstIndex); // first and only parameter in query |
|
662 User::LeaveIfError(stmnt.BindInt(KContactIdParamIndex, aItem.Id() ) ); |
|
663 TInt err = stmnt.Exec(); |
|
664 CleanupStack::PopAndDestroy(&stmnt); |
|
665 |
|
666 if (err == KErrDiskFull) |
|
667 { |
|
668 aLowDiskErrorOccurred = ETrue; |
|
669 } |
|
670 else |
|
671 { |
|
672 User::LeaveIfError(err); |
|
673 } |
|
674 } |
|
675 |
|
676 |
|
677 /** |
|
678 Creates the comm_addr table and its indexes in the database. |
|
679 */ |
|
680 void CPplCommAddrTable::CreateTableL() |
|
681 { |
|
682 User::LeaveIfError(iDatabase.Exec(KCommAddrCreateStmnt) ); |
|
683 } |
|
684 |
|
685 |
|
686 /** |
|
687 Returns an array of contact item IDs for all the contact items which may contain |
|
688 the specified telephone number in a telephone, fax or SMS type field. |
|
689 |
|
690 The comparison method used is not exact. The number is compared starting from |
|
691 the right side of the number and the method returns an array of candidate |
|
692 matches. Punctuation (e.g. spaces) and other alphabetic characters are ignored |
|
693 when comparing. |
|
694 |
|
695 Additionally, if the Contacts Model Phone Parser (CNTPHONE.DLL) is available, |
|
696 then any DTMF digits are also excluded from the comparision. |
|
697 |
|
698 Note that due to the way numbers are stored in the database, it is recommended |
|
699 that at least 7 match digits are specified even when matching a number |
|
700 containing fewer digits. Failure to follow this guideline may (depending on the |
|
701 database contents) mean that the function will not return the expected Contact |
|
702 IDs. |
|
703 |
|
704 @param aNumber Phone number string. |
|
705 @param aMatchLengthFromRight Number of digits from the right of the phone number |
|
706 to use. Up to 15 digits can be specified, and it is recommended that at least 7 |
|
707 match digits are specified. |
|
708 @param aDatabase The database. |
|
709 |
|
710 @return Array of contact IDs which are candidate matches. |
|
711 */ |
|
712 CContactIdArray* CPplCommAddrTable::MatchPhoneNumberL(const TDesC& aNumber, const TInt aMatchLengthFromRight) |
|
713 { |
|
714 CContactIdArray* phoneMatchArray = CContactIdArray::NewLC(); |
|
715 |
|
716 TInt numLowerDigits = aMatchLengthFromRight; |
|
717 TInt numUpperDigits = 0; |
|
718 |
|
719 if(numLowerDigits > KLowerSevenDigits) |
|
720 { |
|
721 // New style matching. |
|
722 numLowerDigits = KLowerSevenDigits; |
|
723 numUpperDigits = aMatchLengthFromRight - KLowerSevenDigits; |
|
724 } |
|
725 |
|
726 TMatch phoneDigits = CreatePaddedPhoneDigitsL(aNumber, numLowerDigits, numUpperDigits); |
|
727 |
|
728 if (phoneDigits.iNumLowerDigits + phoneDigits.iNumUpperDigits > 0) |
|
729 { |
|
730 // build statement |
|
731 RSqlStatement stmnt; |
|
732 CleanupClosePushL(stmnt); |
|
733 stmnt.PrepareL(iDatabase, iMatchSelectStmnt->SqlStringL() ); |
|
734 |
|
735 const TInt KValueParamIndex(KFirstParam); // first parameter in query... |
|
736 const TInt KTypeParamIndex(KValueParamIndex + 1); // ...and the second. |
|
737 |
|
738 User::LeaveIfError(stmnt.BindInt(KValueParamIndex, phoneDigits.iLowerSevenDigits )); |
|
739 User::LeaveIfError(stmnt.BindInt(KTypeParamIndex, EPhoneNumber )); |
|
740 |
|
741 // fetch the list of any matching contact ids |
|
742 TInt err(KErrNone); |
|
743 const TInt KContactIdIdx(iMatchSelectStmnt->ParameterIndex(KCommAddrContactId() ) ); |
|
744 const TInt KExtraValueIdx(iMatchSelectStmnt->ParameterIndex(KCommAddrExtraValue() ) ); |
|
745 while ((err = stmnt.Next() ) == KSqlAtRow) |
|
746 { |
|
747 if (aMatchLengthFromRight <= KLowerSevenDigits) |
|
748 { |
|
749 // Matching 7 or less digits...we've already matched. |
|
750 phoneMatchArray->AddL(stmnt.ColumnInt(KContactIdIdx) ); |
|
751 } |
|
752 else |
|
753 { |
|
754 // Check the upper digits... |
|
755 TInt32 storedUpperDigits(0); |
|
756 TPtrC extValString = stmnt.ColumnTextL(KExtraValueIdx); |
|
757 User::LeaveIfError(TLex(extValString).Val(storedUpperDigits) ); |
|
758 |
|
759 const TInt KDigitsToRemove = KMaxPhoneMatchLength - KLowerSevenDigits - phoneDigits.iNumUpperDigits; |
|
760 for(TInt i = 0; i < KDigitsToRemove; ++i) |
|
761 { |
|
762 // repeatedly divide by 10 to lop off the appropriate number of digits from the right |
|
763 storedUpperDigits /= 10; |
|
764 } |
|
765 |
|
766 storedUpperDigits = TMatch::PadOutPhoneMatchNumber(storedUpperDigits, KDigitsToRemove); |
|
767 |
|
768 if (phoneDigits.iUpperDigits == storedUpperDigits) |
|
769 { |
|
770 phoneMatchArray->AddL(stmnt.ColumnInt(KContactIdIdx) ); |
|
771 } |
|
772 } |
|
773 } |
|
774 |
|
775 // leave if we didn't complete going through the results properly |
|
776 if(err != KSqlAtEnd) |
|
777 { |
|
778 User::Leave(err); |
|
779 } |
|
780 CleanupStack::PopAndDestroy(&stmnt); |
|
781 } |
|
782 |
|
783 CleanupStack::Pop(phoneMatchArray); |
|
784 return phoneMatchArray; |
|
785 } |
|
786 |
|
787 /** |
|
788 Returns an array of contact item IDs for all the contact items which may contain |
|
789 the specified telephone number in a telephone, fax or SMS type field. |
|
790 |
|
791 This is improved version of MatchPhoneNumberL method. |
|
792 The number is compared starting from the right side of the number and |
|
793 the method returns an array of candidate matches. |
|
794 Punctuation (e.g. spaces) and other alphabetic characters are ignored |
|
795 when comparing. Leading zeros are removed. Digits are compared up to |
|
796 the lenght of shorter number. |
|
797 |
|
798 @param aNumber Phone number string. |
|
799 @return Array of contact IDs which are candidate matches. |
|
800 */ |
|
801 CContactIdArray* CPplCommAddrTable::BestMatchingPhoneNumberL(const TDesC& aNumber) |
|
802 { |
|
803 const TInt KUpperMaxLength = KMaxPhoneMatchLength - KLowerSevenDigits; |
|
804 |
|
805 CContactIdArray* phoneMatchArray = CContactIdArray::NewLC(); |
|
806 |
|
807 TMatch phoneDigits = CreatePaddedPhoneDigitsL(aNumber, KLowerSevenDigits, KUpperMaxLength); |
|
808 |
|
809 if (phoneDigits.iNumLowerDigits + phoneDigits.iNumUpperDigits > 0) |
|
810 { |
|
811 // build statement |
|
812 RSqlStatement stmnt; |
|
813 CleanupClosePushL(stmnt); |
|
814 stmnt.PrepareL(iDatabase, iMatchSelectStmnt->SqlStringL()); |
|
815 |
|
816 const TInt KValueParamIndex(KFirstParam); // first parameter in query... |
|
817 const TInt KTypeParamIndex(KValueParamIndex + 1); // ...and the second. |
|
818 |
|
819 User::LeaveIfError(stmnt.BindInt(KValueParamIndex, |
|
820 phoneDigits.iLowerSevenDigits)); |
|
821 User::LeaveIfError(stmnt.BindInt(KTypeParamIndex, EPhoneNumber)); |
|
822 |
|
823 // fetch the list of any matching contact ids |
|
824 TInt err(KErrNone); |
|
825 const TInt KContactIdIdx(iMatchSelectStmnt->ParameterIndex( KCommAddrContactId())); |
|
826 const TInt KExtraValueIdx(iMatchSelectStmnt->ParameterIndex(KCommAddrExtraValue())); |
|
827 while ((err = stmnt.Next()) == KSqlAtRow) |
|
828 { |
|
829 // Check the upper digits... |
|
830 TInt32 number = phoneDigits.iUpperDigits; |
|
831 TPtrC extValString = stmnt.ColumnTextL(KExtraValueIdx); |
|
832 TInt32 storedUpperDigits; |
|
833 User::LeaveIfError(TLex(extValString).Val(storedUpperDigits)); |
|
834 TInt32 stored = storedUpperDigits; |
|
835 |
|
836 TBool nonZeroInStoredFound = EFalse; |
|
837 TBool nonZeroInNumberFound = EFalse; |
|
838 while ((number != 0) && (stored != 0)) |
|
839 { |
|
840 nonZeroInNumberFound |= (number % 10 != 0); |
|
841 nonZeroInStoredFound |= (stored % 10 != 0); |
|
842 if (nonZeroInStoredFound && nonZeroInNumberFound) |
|
843 { |
|
844 break; |
|
845 } |
|
846 number /= 10; |
|
847 stored /= 10; |
|
848 } |
|
849 |
|
850 if ((phoneDigits.iUpperDigits == 0) || (storedUpperDigits == 0) || |
|
851 (number == stored)) |
|
852 { |
|
853 phoneMatchArray->AddL(stmnt.ColumnInt(KContactIdIdx)); |
|
854 } |
|
855 } |
|
856 |
|
857 // leave if we didn't complete going through the results properly |
|
858 if (err != KSqlAtEnd) |
|
859 { |
|
860 User::Leave(err); |
|
861 } |
|
862 CleanupStack::PopAndDestroy(&stmnt); |
|
863 } |
|
864 |
|
865 CleanupStack::Pop(phoneMatchArray); |
|
866 return phoneMatchArray; |
|
867 } |
|
868 |
|
869 |
|
870 /** |
|
871 Searches the contacts database to find any contact items with an exact match on the email address supplied. |
|
872 |
|
873 @param aEmailAddr A descriptor containing the email address to be found in the database. |
|
874 @return An array of contact IDs which match the supplied email address. |
|
875 */ |
|
876 CContactIdArray* CPplCommAddrTable::MatchEmailAddressL(const TDesC& aEmailAddr) |
|
877 { |
|
878 return MatchNonPhoneAddrL(aEmailAddr, EEmailAddress); |
|
879 } |
|
880 |
|
881 |
|
882 /** |
|
883 Searches the contacts database to find any contact items with an exact match on the SIP address supplied. |
|
884 |
|
885 @param aSipAddr A descriptor containing the SIP address to be found in the database. |
|
886 @return An array of contact IDs which match the supplied SIP address. |
|
887 */ |
|
888 CContactIdArray* CPplCommAddrTable::MatchSipAddressL(const TDesC& aSipAddr) |
|
889 { |
|
890 return MatchNonPhoneAddrL(aSipAddr, ESipAddress); |
|
891 } |
|
892 |
|
893 |
|
894 /** |
|
895 Searches the contacts database to find any contact items with an exact match on the address supplied. |
|
896 |
|
897 @param aCommAddr A descriptor containing the address to be found in the database. |
|
898 @param aAddrType The type of addresses that is being sought. |
|
899 @return An array of contact IDs which match the supplied address. |
|
900 */ |
|
901 CContactIdArray* CPplCommAddrTable::MatchNonPhoneAddrL(const TDesC& aCommAddr, TCommAddrType aAddrType) |
|
902 { |
|
903 |
|
904 // build statement |
|
905 RSqlStatement stmnt; |
|
906 CleanupClosePushL(stmnt); |
|
907 stmnt.PrepareL(iDatabase, iMatchSelectStmnt->SqlStringL() ); |
|
908 |
|
909 const TInt KValueParamIndex(KFirstParam); // first parameter in query... |
|
910 const TInt KTypeParamIndex(KValueParamIndex + 1); // ...and the second. |
|
911 User::LeaveIfError(stmnt.BindText(KValueParamIndex, aCommAddr) ); |
|
912 User::LeaveIfError(stmnt.BindInt(KTypeParamIndex, aAddrType) ); |
|
913 |
|
914 // fetch the list of any matching contact ids |
|
915 CContactIdArray* idArray = CContactIdArray::NewLC(); |
|
916 TInt err(KErrNone); |
|
917 const TInt KContactIdIdx(iMatchSelectStmnt->ParameterIndex(KCommAddrContactId() ) ); |
|
918 while ((err = stmnt.Next() ) == KSqlAtRow) |
|
919 { |
|
920 idArray->AddL(stmnt.ColumnInt(KContactIdIdx) ); |
|
921 } |
|
922 |
|
923 // leave if we didn't complete going through the results properly |
|
924 if(err != KSqlAtEnd) |
|
925 { |
|
926 User::Leave(err); |
|
927 } |
|
928 |
|
929 CleanupStack::Pop(idArray); |
|
930 CleanupStack::PopAndDestroy(&stmnt); |
|
931 |
|
932 return idArray; |
|
933 } |
|
934 |
|
935 |
|
936 /** |
|
937 CPplCommAddrTable constructor |
|
938 */ |
|
939 CPplCommAddrTable::CPplCommAddrTable(RSqlDatabase& aDatabase, CLplContactProperties& aProperties) |
|
940 : iProperties(aProperties), |
|
941 iDatabase(aDatabase) |
|
942 { |
|
943 } |
|
944 |
|
945 |
|
946 /** |
|
947 Destructor |
|
948 |
|
949 Tidy up CCntSqlStatement objects |
|
950 */ |
|
951 CPplCommAddrTable::~CPplCommAddrTable() |
|
952 { |
|
953 delete iInsertStmnt; |
|
954 delete iWholeSelectStmnt; |
|
955 delete iMatchSelectStmnt; |
|
956 delete iUpdateStmnt; |
|
957 delete iSingleDeleteStmnt; |
|
958 delete iAllForItemDeleteStmnt; |
|
959 } |
|
960 |
|
961 /** |
|
962 Convert the supplied string to a matchable phone number. |
|
963 |
|
964 @param aText Descriptor containing phone number. |
|
965 @param aLowerMatchlength Number of least significant phone digits to use. |
|
966 @param aUpperMatchLength Number of most significant phone digits to use. |
|
967 |
|
968 @return The hash code(s) to use when matching the supplied phone number. |
|
969 */ |
|
970 CPplCommAddrTable::TMatch CPplCommAddrTable::CreatePaddedPhoneDigitsL(const TDesC& aNumber, const TInt aNumLowerDigits, const TInt aNumUpperDigits) |
|
971 { |
|
972 CPplCommAddrTable::TMatch phoneNumber = CreatePhoneMatchNumberL(aNumber, aNumLowerDigits, aNumUpperDigits); |
|
973 |
|
974 if (phoneNumber.iNumLowerDigits + phoneNumber.iUpperDigits == 0) |
|
975 { |
|
976 // No digits, do nothing |
|
977 } |
|
978 else if(phoneNumber.iNumLowerDigits < KLowerSevenDigits) |
|
979 { |
|
980 // Only the lower-digits hash is used, pad out the number to |
|
981 // KLowerSevenDigits. |
|
982 TInt pad = KLowerSevenDigits - phoneNumber.iNumLowerDigits; |
|
983 phoneNumber.iLowerSevenDigits = TMatch::PadOutPhoneMatchNumber(phoneNumber.iLowerSevenDigits,pad); |
|
984 } |
|
985 else if(phoneNumber.iNumUpperDigits < (KMaxPhoneMatchLength - KLowerSevenDigits) ) |
|
986 { |
|
987 // The lower-digits hash is full, pad out the upper hash if less than 15 |
|
988 // digits total. |
|
989 TInt pad = KMaxPhoneMatchLength - KLowerSevenDigits - phoneNumber.iNumUpperDigits; |
|
990 phoneNumber.iUpperDigits = TMatch::PadOutPhoneMatchNumber(phoneNumber.iUpperDigits,pad); |
|
991 } |
|
992 |
|
993 return phoneNumber; |
|
994 } |
|
995 |
|
996 /** |
|
997 CPplCommAddrTable::TMatch constructor. |
|
998 */ |
|
999 CPplCommAddrTable::TMatch::TMatch() |
|
1000 : |
|
1001 iLowerSevenDigits(0), |
|
1002 iUpperDigits(0), |
|
1003 iNumLowerDigits(0), |
|
1004 iNumUpperDigits(0) |
|
1005 { |
|
1006 } |
|
1007 |
|
1008 |
|
1009 TBool CPplCommAddrTable::TMatch::operator==(const TMatch& aSecondMatch)const |
|
1010 { |
|
1011 return (iLowerSevenDigits == aSecondMatch.iLowerSevenDigits)&& (iUpperDigits == aSecondMatch.iUpperDigits); |
|
1012 } |
|
1013 |
|
1014 |
|
1015 TBool CPplCommAddrTable::TMatch::Equals(const TMatch& aRMatch, const TMatch& aLMatch) |
|
1016 { |
|
1017 return aRMatch == aLMatch; |
|
1018 } |
|
1019 |
|
1020 /** |
|
1021 Pad out the supplied phone digits with zeroes. |
|
1022 |
|
1023 @param aPhoneNumber The number to pad. |
|
1024 @param aPadOutLength The number of digits to pad out. |
|
1025 |
|
1026 @return The padded number. |
|
1027 */ |
|
1028 TInt32 CPplCommAddrTable::TMatch::PadOutPhoneMatchNumber(TInt32& aPhoneNumber, TInt aPadOutLength) |
|
1029 { |
|
1030 TInt32 result(aPhoneNumber); |
|
1031 const TInt KMult(10); |
|
1032 for(TInt i = 0; i < aPadOutLength; ++i) |
|
1033 { |
|
1034 result *= KMult; |
|
1035 } |
|
1036 aPhoneNumber = result; |
|
1037 return result; |
|
1038 } |
|
1039 |
|
1040 |
|
1041 /** |
|
1042 Returns the hash code(s) to use when matching the supplied phone number. If the |
|
1043 number supplied has more actual phone digits (i.e. not including spaces) than |
|
1044 KLowerSevenDigits, a second hash is generated to hold the remaining most |
|
1045 significant phone digits. Extracts DTMF digits from the phone number if a |
|
1046 parser is available, otherwise just removes the non-digit characters. |
|
1047 |
|
1048 @param aText Descriptor containing contacts phone number field. |
|
1049 @param aLowerMatchlength Number of least significant phone digits to use. |
|
1050 @param aUpperMatchLength Number of most significant phone digits to use. |
|
1051 |
|
1052 @return The hash code(s) to use when matching the supplied phone number. |
|
1053 */ |
|
1054 CPplCommAddrTable::TMatch CPplCommAddrTable::CreatePhoneMatchNumberL(const TDesC& aText, TInt aLowerMatchLength, TInt aUpperMatchLength) |
|
1055 { |
|
1056 __ASSERT_DEBUG( ((aLowerMatchLength == KLowerSevenDigits) && (aUpperMatchLength > 0) ) // upper 8 digits |
|
1057 || ((aLowerMatchLength <= KLowerSevenDigits) && (aUpperMatchLength == 0) ), // lower 7 digits |
|
1058 User::Leave(KErrNotSupported) ); |
|
1059 |
|
1060 const TInt KBufLength = KCntMaxTextFieldLength+1; |
|
1061 TBuf<KBufLength> buf; |
|
1062 |
|
1063 CContactPhoneNumberParser* parser = iProperties.ContactPhoneParserL().Parser(); |
|
1064 |
|
1065 if (parser) |
|
1066 { |
|
1067 parser->ExtractRawNumber(aText.Left(KCntMaxTextFieldLength),buf); |
|
1068 } |
|
1069 else |
|
1070 { |
|
1071 if(aText.Length() <= KBufLength) |
|
1072 { |
|
1073 buf = aText; |
|
1074 } |
|
1075 else |
|
1076 { |
|
1077 buf = aText.Right(KBufLength); |
|
1078 } |
|
1079 TMatch::StripOutNonDigitChars(buf); |
|
1080 } |
|
1081 |
|
1082 TMatch phoneNumber; |
|
1083 |
|
1084 if (buf.Length() == 0) |
|
1085 { |
|
1086 return phoneNumber; |
|
1087 } |
|
1088 |
|
1089 // Generate a hash for the upper digits only if the phone number string is |
|
1090 // large enough and more than 7 digits are to be matched. |
|
1091 TInt phoneNumberlength = buf.Length(); |
|
1092 if ( (phoneNumberlength > KLowerSevenDigits) && (aUpperMatchLength > 0) ) |
|
1093 { |
|
1094 TPtrC upperPart = buf.Left(phoneNumberlength - KLowerSevenDigits); |
|
1095 phoneNumber.iUpperDigits = TMatch::CreateHashL(upperPart, |
|
1096 aUpperMatchLength, phoneNumber.iNumUpperDigits); |
|
1097 } |
|
1098 |
|
1099 // Generate a hash of the lower digits. |
|
1100 phoneNumber.iLowerSevenDigits = TMatch::CreateHashL(buf, aLowerMatchLength, phoneNumber.iNumLowerDigits); |
|
1101 |
|
1102 return phoneNumber; |
|
1103 } |
|
1104 |
|
1105 |
|
1106 /** |
|
1107 Strip out any non-digit characters before we convert the phone number to an |
|
1108 integer. |
|
1109 |
|
1110 @param aText Phone number which on return will have any non-digit characters |
|
1111 removed. |
|
1112 */ |
|
1113 void CPplCommAddrTable::TMatch::StripOutNonDigitChars(TDes& aText) |
|
1114 { |
|
1115 for(TInt chrPos = 0; chrPos < aText.Length(); ++chrPos) |
|
1116 { |
|
1117 TChar chr = aText[chrPos]; |
|
1118 if (!chr.IsDigit() ) |
|
1119 { |
|
1120 aText.Delete(chrPos, 1); |
|
1121 --chrPos; |
|
1122 } |
|
1123 } |
|
1124 } |
|
1125 |
|
1126 |
|
1127 /** |
|
1128 Generates a hash value by reversing the aMatchLength least significant digits, |
|
1129 ignoring non-digits and zeroes at the end of the number. Asserts if no phone |
|
1130 digits are supplied. |
|
1131 |
|
1132 @param aPhoneNumberString A descriptor containing a phone number. |
|
1133 @param aMatchLength The number of digits from the right of the phone number to use. |
|
1134 @param aNumPhoneDigits The number of digits found in the phone number string. |
|
1135 |
|
1136 @return An integer representation of the phone number string in reverse. |
|
1137 */ |
|
1138 TInt32 CPplCommAddrTable::TMatch::CreateHashL(const TDesC& aPhoneNumberString, TInt aMatchLength, TInt& aNumPhoneDigits) |
|
1139 { |
|
1140 TInt phoneNumberLength = aPhoneNumberString.Length(); |
|
1141 __ASSERT_DEBUG(phoneNumberLength > 0, User::Leave(KErrNotSupported) ); |
|
1142 |
|
1143 TInt startIndex = 0; |
|
1144 |
|
1145 if (phoneNumberLength > aMatchLength) |
|
1146 { |
|
1147 startIndex = phoneNumberLength - aMatchLength; |
|
1148 } |
|
1149 |
|
1150 aNumPhoneDigits = 0; |
|
1151 TUint reversedDigits = 0; |
|
1152 TInt mult = 1; |
|
1153 |
|
1154 for (TInt chrIndex = startIndex; (aNumPhoneDigits < aMatchLength) && (chrIndex < phoneNumberLength); chrIndex++) |
|
1155 { |
|
1156 TChar chr = aPhoneNumberString[chrIndex]; |
|
1157 if (chr.IsDigit() ) |
|
1158 { |
|
1159 reversedDigits += (chr.GetNumericValue() ) * mult; |
|
1160 mult = mult * 10; |
|
1161 ++aNumPhoneDigits; |
|
1162 } |
|
1163 } |
|
1164 |
|
1165 return reversedDigits ; |
|
1166 } |