1 // Copyright (c) 1999-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 // smut.cpp |
|
15 // |
|
16 #include <smut.h> |
|
17 #include <gsmuieoperations.h> |
|
18 |
|
19 #include <e32std.h> |
|
20 #include <gsmumsg.h> |
|
21 #include <msvstd.h> |
|
22 #include <cntdb.h> |
|
23 #include <cntfield.h> |
|
24 #include <cntitem.h> |
|
25 #include <cntfldst.h> |
|
26 #include <msventry.h> |
|
27 #include <msvuids.h> |
|
28 #include <msvapi.h> |
|
29 #include <txtetext.h> |
|
30 #include <gsmubuf.h> |
|
31 #include <bautils.h> |
|
32 #include <barsc.h> |
|
33 #include <SMSS.rsg> |
|
34 #include <smss.hrh> |
|
35 #include <msvutils.h> |
|
36 #include "SMCMMAIN.H" |
|
37 #include "SMUTSET.H" |
|
38 |
|
39 // Used by ValidGsmNumber(). The characters that may appear at the start of a |
|
40 // valid GSM number |
|
41 _LIT(KSmsValidGsmNumberFirstChar, "+"); |
|
42 |
|
43 // Used by ValidGsmNumber(). The characters that may appear after the first |
|
44 // character of a valid GSM number |
|
45 _LIT(KSmsValidGsmNumberOtherChar, "#*"); |
|
46 |
|
47 const TInt KSmsValidGsmNumberMinLength = 2; |
|
48 |
|
49 /** |
|
50 Finds and returns all the Service IDs for the specified MTM. |
|
51 |
|
52 A Service ID is the entry ID for an service-type entry. The first Service ID |
|
53 for the specified MTM is returned. |
|
54 |
|
55 If the complete set of Service IDs for the MTM is required then the caller |
|
56 should provide a valid CMsvEntrySelection object in aServiceIds. The Service |
|
57 Ids are appended to this object. If the complete set is not required then the |
|
58 input/output argument aServiceIds should be set to NULL. |
|
59 |
|
60 @param aEntry |
|
61 A server message entry that can be used by this function. |
|
62 |
|
63 @param aFirstId |
|
64 An output argument with the first Service ID. |
|
65 |
|
66 @param aMtm |
|
67 The specified MTM. This has a default value of KUidMsgTypeSMS. |
|
68 |
|
69 @param aServiceIds |
|
70 An input/output argument with the complete selection of Service IDs. This has |
|
71 a default value of NULL. |
|
72 |
|
73 @leave KErrNotFound |
|
74 A service entry could not be found for the specified MTM. |
|
75 */ |
|
76 EXPORT_C void TSmsUtilities::ServiceIdL(CMsvServerEntry& aEntry, TMsvId& aFirstId, TUid aMtm, CMsvEntrySelection* aServiceIds) |
|
77 { |
|
78 aFirstId = KMsvNullIndexEntryId; |
|
79 |
|
80 CMsvEntrySelection* selection = new (ELeave) CMsvEntrySelection(); |
|
81 CleanupStack::PushL(selection); |
|
82 |
|
83 User::LeaveIfError(aEntry.SetEntry(KMsvRootIndexEntryId)); |
|
84 |
|
85 TMsvSelectionOrdering order; |
|
86 order.SetShowInvisibleEntries(ETrue); |
|
87 aEntry.SetSort(order); |
|
88 |
|
89 // Get the children on the Root Index Entry |
|
90 User::LeaveIfError(aEntry.GetChildrenWithType(KUidMsvServiceEntry, *selection)); |
|
91 |
|
92 TInt count = selection->Count(); |
|
93 |
|
94 // Find an entry for MTM aMtm |
|
95 for (TInt curChild = 0; curChild < count && (aFirstId == KMsvNullIndexEntryId || aServiceIds); ++curChild) |
|
96 { |
|
97 User::LeaveIfError(aEntry.SetEntry(selection->At(curChild))); |
|
98 CompareEntryL(aEntry.Entry(), aMtm, aFirstId, aServiceIds); |
|
99 } |
|
100 |
|
101 // Leave if no Service Entry found for MTM aMtm |
|
102 if (aFirstId == KMsvNullIndexEntryId) |
|
103 User::Leave(KErrNotFound); |
|
104 |
|
105 CleanupStack::PopAndDestroy(selection); |
|
106 } |
|
107 |
|
108 /** |
|
109 Finds and returns all the Service IDs for the specified MTM. |
|
110 |
|
111 A Service ID is the entry ID for an service-type entry. The first Service ID |
|
112 for the specified MTM is returned. |
|
113 |
|
114 If the complete set of Service IDs for the MTM is required then the caller |
|
115 should provide a valid CMsvEntrySelection object in aServiceIds. The Service |
|
116 Ids are appended to this object. If the complete set is not required then the |
|
117 input/output argument aServiceIds should be set to NULL. |
|
118 |
|
119 @param aSession |
|
120 A message server session. |
|
121 |
|
122 @param aFirstId |
|
123 An output argument with the first Service ID. |
|
124 |
|
125 @param aMtm |
|
126 The specified MTM. This has a default value of KUidMsgTypeSMS. |
|
127 |
|
128 @param aServiceIds |
|
129 An input/output argument with the complete selection of Service IDs. This has |
|
130 a default value of NULL. |
|
131 |
|
132 @leave KErrNotFound |
|
133 A service entry could not be found for the specified MTM. |
|
134 */ |
|
135 EXPORT_C void TSmsUtilities::ServiceIdL(CMsvSession& aSession, TMsvId& aFirstId, TUid aMtm, CMsvEntrySelection* aServiceIds) |
|
136 { |
|
137 TMsvSelectionOrdering order; |
|
138 order.SetShowInvisibleEntries(ETrue); |
|
139 |
|
140 CMsvEntry* root = CMsvEntry::NewL(aSession, KMsvRootIndexEntryId, order); |
|
141 CleanupStack::PushL(root); |
|
142 |
|
143 ServiceIdL(*root, aFirstId, aMtm, aServiceIds); |
|
144 |
|
145 CleanupStack::PopAndDestroy(root); |
|
146 } |
|
147 |
|
148 /** |
|
149 Finds and returns all the Service IDs for the specified MTM. |
|
150 |
|
151 A Service ID is the entry ID for an service-type entry. The first Service ID |
|
152 for the specified MTM is returned. |
|
153 |
|
154 If the complete set of Service IDs for the MTM is required then the caller |
|
155 should provide a valid CMsvEntrySelection object in aServiceIds. The Service |
|
156 Ids are appended to this object. If the complete set is not required then the |
|
157 input/output argument aServiceIds should be set to NULL. |
|
158 |
|
159 @param aEntry |
|
160 A message entry that can be used by this function. |
|
161 |
|
162 @param aFirstId |
|
163 An output argument with the first Service ID. |
|
164 |
|
165 @param aMtm |
|
166 The specified MTM. This has a default value of KUidMsgTypeSMS. |
|
167 |
|
168 @param aServiceIds |
|
169 An input/output argument with the complete selection of Service IDs. This has |
|
170 a default value of NULL. |
|
171 |
|
172 @leave KErrNotFound |
|
173 A service entry could not be found for the specified MTM. |
|
174 */ |
|
175 EXPORT_C void TSmsUtilities::ServiceIdL(CMsvEntry& aEntry, TMsvId& aFirstId, TUid aMtm, CMsvEntrySelection* aServiceIds) |
|
176 { |
|
177 aFirstId = KMsvNullIndexEntryId; |
|
178 |
|
179 TMsvSelectionOrdering order(aEntry.SortType()); |
|
180 if (!order.ShowInvisibleEntries()) |
|
181 { |
|
182 order.SetShowInvisibleEntries(ETrue); |
|
183 aEntry.SetSortTypeL(order); |
|
184 } |
|
185 |
|
186 aEntry.SetEntryL(KMsvRootIndexEntryId); |
|
187 const TInt count = aEntry.Count(); |
|
188 |
|
189 // Find an entry for MTM aMtm |
|
190 for (TInt curChild = 0; curChild < count && (aFirstId == KMsvNullIndexEntryId || aServiceIds != NULL); ++curChild) |
|
191 { |
|
192 CompareEntryL(aEntry[curChild], aMtm, aFirstId, aServiceIds); |
|
193 } |
|
194 |
|
195 // Leave if no Service Entry found for MTM aMtm |
|
196 if (aFirstId == KMsvNullIndexEntryId) |
|
197 User::Leave(KErrNotFound); |
|
198 } |
|
199 |
|
200 /** |
|
201 Populates a message index. |
|
202 |
|
203 The input data is used to set the fields in supplied message index. The affected |
|
204 fields are the entry type, MTM, entry date, Service ID and error fields. The |
|
205 date field is set from the time information in the aMessage argument. |
|
206 |
|
207 This function can be used as part of the process when creating SMS messages in |
|
208 the message store. |
|
209 |
|
210 @param aEntry |
|
211 An input/output argument with the index entry to populate. |
|
212 |
|
213 @param aMessage |
|
214 The SMS message object for the index entry. |
|
215 |
|
216 @param aServiceId |
|
217 The Service ID for the message. |
|
218 |
|
219 @param aMtm |
|
220 The specified MTM. This has a default value of KUidMsgTypeSMS. |
|
221 */ |
|
222 EXPORT_C void TSmsUtilities::PopulateMsgEntry(TMsvEntry& aEntry, const CSmsMessage& aMessage, TMsvId aServiceId, TUid aMtm) |
|
223 { |
|
224 aEntry.iType = KUidMsvMessageEntry; |
|
225 aEntry.iMtm = aMtm; |
|
226 aEntry.iDate = aMessage.Time(); |
|
227 aEntry.iServiceId = aServiceId; |
|
228 aEntry.iError = KErrNone; |
|
229 } |
|
230 |
|
231 /** |
|
232 Populates a message index. |
|
233 |
|
234 The input data is used to set the fields in supplied message index. The affected |
|
235 fields are the entry type, MTM, entry date, Service ID and error fields. The |
|
236 date field is either set from the time information in the aMessage argument or from |
|
237 the service center timestamp in the PDU depending on the associated SMS setting. |
|
238 |
|
239 This function can be used as part of the process when creating SMS messages in |
|
240 the message store. |
|
241 |
|
242 @param aEntry |
|
243 An input/output argument with the index entry to populate. |
|
244 |
|
245 @param aMessage |
|
246 The SMS message object for the index entry. |
|
247 |
|
248 @param aServiceId |
|
249 The Service ID for the message. |
|
250 |
|
251 @param aSettings |
|
252 The settings for the SMS account. |
|
253 |
|
254 @param aMtm |
|
255 The specified MTM. This has a default value of KUidMsgTypeSMS. |
|
256 */ |
|
257 EXPORT_C void TSmsUtilities::PopulateMsgEntry(TMsvEntry& aEntry, const CSmsMessage& aMessage, TMsvId aServiceId, const CSmsSettings& aSettings, TUid aMtm) |
|
258 { |
|
259 TSmsUtilities::PopulateMsgEntry(aEntry, aMessage, aServiceId, aMtm); |
|
260 |
|
261 if (aSettings.UseServiceCenterTimeStampForDate()) |
|
262 { |
|
263 const CSmsPDU& pdu = aMessage.SmsPDU(); |
|
264 |
|
265 TTime time = 0; |
|
266 TInt gmtOffset = 0; |
|
267 |
|
268 if (pdu.Type() == CSmsPDU::ESmsDeliver) |
|
269 { |
|
270 CSmsDeliver& smsDeliver = |
|
271 const_cast<CSmsDeliver&>(static_cast<const CSmsDeliver&>(pdu)); |
|
272 smsDeliver.ServiceCenterTimeStamp(time, gmtOffset); |
|
273 } |
|
274 else if (pdu.Type() == CSmsPDU::ESmsStatusReport) |
|
275 { |
|
276 CSmsStatusReport& smsStatusReport = |
|
277 const_cast<CSmsStatusReport&>(static_cast<const CSmsStatusReport&>(pdu)); |
|
278 smsStatusReport.ServiceCenterTimeStamp(time, gmtOffset); |
|
279 } |
|
280 |
|
281 if (time > 0) |
|
282 { |
|
283 aEntry.iDate = time; |
|
284 } |
|
285 } |
|
286 } |
|
287 |
|
288 /** |
|
289 Get the SMS message recipient/sender details. |
|
290 |
|
291 The recipient/sender telephone number is extracted from the supplied message |
|
292 object. If the recipient/sender telephone number appears uniquely in the contacts |
|
293 database then the family name and given name contact details are set into the |
|
294 output argument aDetails in the format specified by the resource item |
|
295 R_SENDER_NAME_FORMAT. The buffer limit specified by aMaxLength is observed. |
|
296 |
|
297 If there is not a unique contact entry for the recipient/sender telephone number |
|
298 then aDetails will contain the orginally telephone number. |
|
299 |
|
300 @param aFs |
|
301 A connected file server session. |
|
302 |
|
303 @param aMessage |
|
304 The message object with the recipient/sender telephone number. |
|
305 |
|
306 @param aDetails |
|
307 The output argument to contain the message details. |
|
308 |
|
309 @param aMaxLength |
|
310 The maximum length of the supplied buffer in aDetails. |
|
311 |
|
312 @return |
|
313 KErrNotSupported if the message is not of type SMS-SUBMIT, SMS-DELIVER or SMS-STATUS-REPORT. |
|
314 KErrArgument if the telephone number is invalid. |
|
315 KErrNotFound if a contact could not be found. |
|
316 KErrAlreadyExists if more than one contact entry found. |
|
317 KErrNone if details is obtained successfully. |
|
318 */ |
|
319 EXPORT_C TInt TSmsUtilities::GetDetails(RFs& aFs, const CSmsMessage& aMessage, TDes& aDetails, TInt aMaxLength) |
|
320 { |
|
321 __ASSERT_DEBUG( aMaxLength <= aDetails.MaxLength(), User::Invariant() ); |
|
322 |
|
323 if (aMaxLength > aDetails.MaxLength()) |
|
324 { |
|
325 aMaxLength = aDetails.MaxLength(); |
|
326 } |
|
327 |
|
328 aDetails.Zero(); |
|
329 |
|
330 TPtrC fromAddress; |
|
331 |
|
332 switch (aMessage.SmsPDU().Type()) |
|
333 { |
|
334 case CSmsPDU::ESmsSubmit: |
|
335 case CSmsPDU::ESmsDeliver: |
|
336 case CSmsPDU::ESmsStatusReport: |
|
337 fromAddress.Set(aMessage.SmsPDU().ToFromAddress()); |
|
338 break; |
|
339 default: |
|
340 return KErrNotSupported; |
|
341 } |
|
342 |
|
343 return GetDetails(aFs, fromAddress, aDetails, aMaxLength); |
|
344 } |
|
345 |
|
346 /** |
|
347 Get the SMS message recipient/sender details. |
|
348 |
|
349 The recipient/sender telephone number is searched for in the contacts database. |
|
350 If a unique match is found then the family name and given name contact details |
|
351 are set into the output argument aDetails in the format specified by the |
|
352 resource item R_SENDER_NAME_FORMAT. The buffer limit specified by aMaxLength is |
|
353 observed. |
|
354 |
|
355 If a unique match is not found or the supplied telephone number is invalid, then |
|
356 aDetails will contain the orginally telephone number. |
|
357 |
|
358 @param aFs |
|
359 A connected file server session. |
|
360 |
|
361 @param aFromAddress |
|
362 The recipient/sender telephone number. |
|
363 |
|
364 @param aDetails |
|
365 The output argument to contain the message details. |
|
366 |
|
367 @param aMaxLength |
|
368 The maximum length of the supplied buffer in aDetails. |
|
369 |
|
370 @return |
|
371 KErrArgument if aFromAddress is not a valid GSM number. |
|
372 KErrNotFound if a contact could not be found. |
|
373 KErrAlreadyExists if more than one contact entry found. |
|
374 KErrNone if details is obtained successfully. |
|
375 */ |
|
376 EXPORT_C TInt TSmsUtilities::GetDetails(RFs& aFs, const TDesC& aFromAddress, TDes& aDetails, TInt aMaxLength) |
|
377 { |
|
378 __ASSERT_DEBUG( aMaxLength <= aDetails.MaxLength(), User::Invariant() ); |
|
379 |
|
380 if (aMaxLength > aDetails.MaxLength()) |
|
381 { |
|
382 aMaxLength = aDetails.MaxLength(); |
|
383 } |
|
384 |
|
385 TRAPD(err, DoGetDetailsL(aFs, aFromAddress, aDetails, aMaxLength)); |
|
386 |
|
387 if ( (err != KErrNone) || (aDetails.Length() == 0) ) |
|
388 { |
|
389 if (aFromAddress.Length() <= aMaxLength) |
|
390 { |
|
391 aDetails = aFromAddress; |
|
392 aDetails.Trim(); |
|
393 } |
|
394 else |
|
395 { |
|
396 // Truncate aFromAddress so that it fits into aDetails. |
|
397 aDetails = aFromAddress.Left(aMaxLength); |
|
398 aDetails.Trim(); |
|
399 } |
|
400 } |
|
401 |
|
402 return KErrNone; |
|
403 } |
|
404 |
|
405 /** |
|
406 Get the SMS message description. |
|
407 |
|
408 If the message is Special Message Indication SMS then the description will |
|
409 contain the appropriate localised text for the indication. |
|
410 |
|
411 If the message is a Status Report then the description will contain the |
|
412 appropriate localised text for a Status Report. |
|
413 |
|
414 If the message is a standard text message the description will contain the |
|
415 beginning section of the SMS message text itself. |
|
416 |
|
417 In all cases the buffer limit specified by aMaxLength is observered. |
|
418 |
|
419 @param aMessage |
|
420 The SMS message object. |
|
421 |
|
422 @param aDescription |
|
423 The output argument for the description. |
|
424 |
|
425 @param aMaxLength |
|
426 The maximum length of the supplied buffer in aDescription. |
|
427 |
|
428 @return |
|
429 An error code if the localised text for a SMS-STATUS-REPORT message could not be |
|
430 obtained. Otherwise KErrNone is returned. |
|
431 */ |
|
432 EXPORT_C TInt TSmsUtilities::GetDescription(const CSmsMessage& aMessage, TDes& aDescription, TInt aMaxLength) |
|
433 { |
|
434 __ASSERT_DEBUG( aMaxLength <= aDescription.MaxLength(), User::Invariant() ); |
|
435 |
|
436 if (aMaxLength > aDescription.MaxLength()) |
|
437 { |
|
438 aMaxLength = aDescription.MaxLength(); |
|
439 } |
|
440 |
|
441 aDescription.Zero(); |
|
442 |
|
443 TBool gotDescription = EFalse; |
|
444 TRAPD(err, gotDescription = DoGetDescriptionL(aMessage, aDescription, aMaxLength)); |
|
445 if(err != KErrNone || !gotDescription) |
|
446 ExtractDescriptionFromMessage(aMessage, aDescription, aMaxLength); |
|
447 |
|
448 return KErrNone; |
|
449 } |
|
450 |
|
451 /** |
|
452 Opens and returns the SMS client MTM resource file. |
|
453 |
|
454 It is the responsibility of the caller to ensure that the resource file is |
|
455 closed once it is no longer required. |
|
456 |
|
457 @param aFs |
|
458 A connected file server session. |
|
459 |
|
460 @return |
|
461 The opened resource file. |
|
462 */ |
|
463 EXPORT_C RResourceFile TSmsUtilities::OpenResourceFileL(RFs& aFs) |
|
464 { |
|
465 TFileName fileName(KSmsResourceFile); |
|
466 MsvUtils::AddPathAndExtensionToResFileL(fileName); |
|
467 BaflUtils::NearestLanguageFile(aFs, fileName); |
|
468 |
|
469 RResourceFile resFile; |
|
470 resFile.OpenL(aFs, fileName); |
|
471 return resFile; |
|
472 } |
|
473 |
|
474 /** |
|
475 Reads the resource specified by aResourceId from the supplied resource file. |
|
476 |
|
477 The resource is returned in the output argument aString. The supplied resource |
|
478 file must be open or this function will leave. |
|
479 |
|
480 @param aResourceFile |
|
481 The opened resource file to read the resource from. |
|
482 |
|
483 @param aResourceId |
|
484 The ID of the resource that is required. |
|
485 |
|
486 @param aString |
|
487 An output buffer into which the read resource is placed. |
|
488 |
|
489 @leave KErrOverflow |
|
490 The length of the resource string is greater than the maximum allowed. |
|
491 */ |
|
492 EXPORT_C void TSmsUtilities::ReadResourceStringL(RResourceFile aResourceFile, TInt aResourceId, TDes& aString) |
|
493 |
|
494 { |
|
495 HBufC8* buf = aResourceFile.AllocReadLC(aResourceId); |
|
496 TResourceReader reader; |
|
497 reader.SetBuffer(buf); |
|
498 |
|
499 TPtrC resString = reader.ReadTPtrC(); |
|
500 |
|
501 if (resString.Length() <= aString.MaxLength()) |
|
502 { |
|
503 aString.Copy(resString); |
|
504 } |
|
505 else |
|
506 { |
|
507 User::Leave(KErrOverflow); |
|
508 } |
|
509 |
|
510 CleanupStack::PopAndDestroy(buf); |
|
511 } |
|
512 |
|
513 void TSmsUtilities::CompareEntryL(const TMsvEntry& aEntry, TUid aMtm, TMsvId& aFirstId, CMsvEntrySelection* aServiceIds) |
|
514 { |
|
515 if (aEntry.iType == KUidMsvServiceEntry && aEntry.iMtm == aMtm) |
|
516 { |
|
517 const TMsvId id = aEntry.Id(); |
|
518 |
|
519 if (aFirstId == KMsvNullIndexEntryId) |
|
520 aFirstId = id; |
|
521 |
|
522 if (aServiceIds) |
|
523 aServiceIds->AppendL(id); |
|
524 } |
|
525 } |
|
526 |
|
527 void TSmsUtilities::DoGetDetailsL(RFs& aFs, const TDesC& aFromAddress, TDes& aDetails, TInt aMaxLength) |
|
528 { |
|
529 __UHEAP_MARK; |
|
530 |
|
531 // Check that aFromAddress is a valid GSM telephone number |
|
532 if (!ValidGsmNumber(aFromAddress)) |
|
533 User::Leave(KErrArgument); |
|
534 |
|
535 aDetails.Zero(); |
|
536 |
|
537 CContactDatabase* db = CContactDatabase::OpenL(); |
|
538 CleanupStack::PushL(db); |
|
539 |
|
540 // Lookup the telephone number (aFromAddress) in the contact database |
|
541 CContactIdArray* contactId = db->MatchPhoneNumberL(aFromAddress, KLowerSevenDigits); |
|
542 CleanupStack::PushL(contactId); |
|
543 |
|
544 // Add the name if there is one and only one match in contacts. If there's more than |
|
545 // one then wouldn't know which one to choose |
|
546 if (contactId->Count() <= 0) |
|
547 { |
|
548 //The telephone number (aFromAddress) was not found in the contact database. |
|
549 User::Leave(KErrNotFound); |
|
550 } |
|
551 else if (contactId->Count() > 1) |
|
552 { |
|
553 //There's more than one telephone number match in contacts. |
|
554 User::Leave(KErrAlreadyExists); |
|
555 } |
|
556 |
|
557 CContactItem* newContact = db->ReadMinimalContactL((*contactId)[0]); |
|
558 CleanupStack::PushL(newContact); |
|
559 |
|
560 CContactItemFieldSet& fieldSet = newContact->CardFields(); |
|
561 |
|
562 TInt count = fieldSet.Count(); |
|
563 |
|
564 HBufC* family = HBufC::NewLC(aMaxLength); |
|
565 HBufC* given = HBufC::NewLC(aMaxLength); |
|
566 TPtr familyPtr(family->Des()); |
|
567 TPtr givenPtr(given->Des()); |
|
568 |
|
569 // Find the Given and First Name of the contact |
|
570 // Order important |
|
571 for (TInt curField = 0; curField < count && !(familyPtr.Length() && givenPtr.Length()); curField++) |
|
572 { |
|
573 CContactItemField& field = fieldSet[curField]; |
|
574 |
|
575 if (!familyPtr.Length()) |
|
576 GetName(field, KUidContactFieldFamilyName, familyPtr); |
|
577 |
|
578 if (!givenPtr.Length()) |
|
579 GetName(field, KUidContactFieldGivenName, givenPtr); |
|
580 } |
|
581 |
|
582 familyPtr.Trim(); |
|
583 givenPtr.Trim(); |
|
584 |
|
585 TInt familyLen = familyPtr.Length(); |
|
586 TInt givenLen = givenPtr.Length(); |
|
587 |
|
588 if (!familyLen && !givenLen) |
|
589 { |
|
590 //Leave if no family nor given name found |
|
591 User::Leave(KErrNotFound); |
|
592 } |
|
593 else if (givenLen == 0) |
|
594 { |
|
595 // The maximum length of familyPtr may be greater than |
|
596 // aMaxLength, so need to check its length before copying. |
|
597 if (familyPtr.Length() > aMaxLength) |
|
598 { |
|
599 familyPtr.Set(familyPtr.LeftTPtr(aMaxLength)); |
|
600 } |
|
601 |
|
602 aDetails = familyPtr; |
|
603 } |
|
604 else if (familyLen == 0) |
|
605 { |
|
606 // The maximum length of givenPtr may be greater than |
|
607 // aMaxLength, so need to check its length before copying. |
|
608 if (givenPtr.Length() > aMaxLength) |
|
609 { |
|
610 givenPtr.Set(givenPtr.LeftTPtr(aMaxLength)); |
|
611 } |
|
612 |
|
613 aDetails = givenPtr; |
|
614 } |
|
615 else |
|
616 { |
|
617 RResourceFile resFile = OpenResourceFileL(aFs); |
|
618 CleanupClosePushL(resFile); |
|
619 ReadResourceStringL(resFile, R_SENDER_NAME_FORMAT, aDetails); |
|
620 CleanupStack::PopAndDestroy(&resFile); |
|
621 |
|
622 TBuf<8> givenPlaceHolder = L_SMS_GIVEN_NAME; |
|
623 TBuf<8> familyPlaceHolder = L_SMS_FAMILY_NAME; |
|
624 TInt minLength = aDetails.Length() - givenPlaceHolder.Length() - familyPlaceHolder.Length(); |
|
625 |
|
626 if ((familyLen + givenLen + minLength) > aMaxLength) |
|
627 { |
|
628 // The maximum length of familyPtr may be greater than |
|
629 // aMaxLength, so need to check its length before copying. |
|
630 if (familyPtr.Length() > aMaxLength) |
|
631 { |
|
632 familyPtr.Set(familyPtr.LeftTPtr(aMaxLength)); |
|
633 } |
|
634 aDetails = familyPtr; |
|
635 } |
|
636 else |
|
637 { |
|
638 Replace(givenPlaceHolder, givenPtr, aDetails); |
|
639 Replace(familyPlaceHolder, familyPtr, aDetails); |
|
640 } |
|
641 } |
|
642 |
|
643 //Remove leading and trailing spaces |
|
644 aDetails.Trim(); |
|
645 CleanupStack::PopAndDestroy(5, db); |
|
646 |
|
647 __UHEAP_MARKEND; |
|
648 } |
|
649 |
|
650 TBool TSmsUtilities::ValidGsmNumber(const TDesC& aTelephone) |
|
651 { |
|
652 // Returns ETrue if |
|
653 // aTelephone is not zero length; and |
|
654 // aTelephone[0] is a digit or "+"; and |
|
655 // aTelephone[1..] is a digit or "*" or "#". |
|
656 // aTelephone has at least 2 valid characters |
|
657 //Note: Returns EFalse if aTelephone contains any alpha character |
|
658 // All spaces are ignored |
|
659 const TInt length = aTelephone.Length(); |
|
660 |
|
661 if (length < KSmsValidGsmNumberMinLength) |
|
662 return EFalse; |
|
663 |
|
664 TPtrC KFirstChar(KSmsValidGsmNumberFirstChar); |
|
665 TPtrC KOtherChar(KSmsValidGsmNumberOtherChar); |
|
666 TBool validTel = ETrue; |
|
667 TInt validCharsFound = 0; //must be >= KSmsValidGsmNumberMinLength by the end |
|
668 |
|
669 const TText* first = aTelephone.Ptr(); //Points to the first character in aTelephone |
|
670 const TText* last = first + length - 1; //Points to the last character in aTelephone |
|
671 |
|
672 //Check each character in the telephone number |
|
673 while (validTel && first <= last) |
|
674 { |
|
675 TChar ch(*first); |
|
676 if (!ch.IsSpace()) //ignore whitespace |
|
677 { |
|
678 if (!ch.IsDigit()) |
|
679 { |
|
680 //Need to create TPtrC because TDesC::Find() does not take a TChar |
|
681 TPtrC telCharacter(first, 1); |
|
682 |
|
683 if (validCharsFound) |
|
684 { |
|
685 //Check the remaining characters of the telephone number |
|
686 validTel = (KOtherChar.Find(telCharacter) != KErrNotFound); |
|
687 } |
|
688 else //validCharsFound == 0 |
|
689 { |
|
690 //Check the first character of the telephone number |
|
691 validTel = (KFirstChar.Find(telCharacter) != KErrNotFound); |
|
692 } |
|
693 } |
|
694 validCharsFound++; |
|
695 } |
|
696 |
|
697 first++; //move to the next character |
|
698 } |
|
699 |
|
700 return validTel && validCharsFound >= KSmsValidGsmNumberMinLength; |
|
701 } |
|
702 |
|
703 void TSmsUtilities::GetName(CContactItemField& aField, TUid aFieldType, TDes& aName) |
|
704 { |
|
705 __UHEAP_MARK; |
|
706 if (aField.ContentType().ContainsFieldType(aFieldType)) |
|
707 { |
|
708 TPtrC name = aField.TextStorage()->Text(); |
|
709 aName = name.Left(Min(aName.MaxLength(), name.Length())); |
|
710 } |
|
711 __UHEAP_MARKEND; |
|
712 |
|
713 } |
|
714 |
|
715 TBool TSmsUtilities::DoGetDescriptionL(const CSmsMessage& aMessage, TDes& aDescription, TInt aMaxLength) |
|
716 // this function returns EFalse if aMessage has no special message indication data and is not an SMS_STATUS_REPORT, |
|
717 // i.e. more needs to be done to extract the description from the message |
|
718 // otherwise returns ETrue |
|
719 { |
|
720 TInt resourceId = 0; |
|
721 TBuf<KSmsDescriptionLength> format; |
|
722 TSmsMessageIndicationType messageIndicationType; |
|
723 TExtendedSmsIndicationType extendedType; |
|
724 TSmsMessageProfileType messageProfileType; |
|
725 TBool toStore=EFalse; |
|
726 TUint totalIndicationCount=0; |
|
727 TUint totalMessageCount=0; |
|
728 |
|
729 //check if the messae contains an enhanced voice mail indication |
|
730 CSmsEnhancedVoiceMailOperations& enhancedVoiceMailOperations = STATIC_CAST(CSmsEnhancedVoiceMailOperations&,aMessage.GetOperationsForIEL(CSmsInformationElement::ESmsEnhanceVoiceMailInformation)); |
|
731 |
|
732 if(enhancedVoiceMailOperations.ContainsEnhancedVoiceMailIEL()) |
|
733 { |
|
734 //get a copy of the indication |
|
735 CEnhancedVoiceMailBoxInformation* retrievedNotification=enhancedVoiceMailOperations.CopyEnhancedVoiceMailIEL(); |
|
736 TVoiceMailInfoType typeInfo=retrievedNotification->Type(); |
|
737 //check its type |
|
738 if(typeInfo==EGsmSmsVoiceMailNotification) |
|
739 { |
|
740 //increment the indication count |
|
741 ++totalIndicationCount; |
|
742 resourceId = R_MESSAGE_INDICATION_ENHANCED_VOICEMAIL_ONE; |
|
743 } |
|
744 |
|
745 TUint8 messageCount=retrievedNotification->NumberOfVoiceMessages(); |
|
746 //add the message count to the running total |
|
747 totalMessageCount+=messageCount; |
|
748 //if there is more that one message of this type then set the resouce id to 'many' |
|
749 if(messageCount!=1) |
|
750 { |
|
751 ++resourceId; |
|
752 } |
|
753 |
|
754 delete retrievedNotification; |
|
755 } |
|
756 |
|
757 //check for special message waiting indications |
|
758 CSmsSpecialSMSMessageOperations& operations = STATIC_CAST(CSmsSpecialSMSMessageOperations&,aMessage.GetOperationsForIEL(CSmsInformationElement::ESmsIEISpecialSMSMessageIndication)); |
|
759 TUint specialMessageIndicationCount=operations.GetCountOfSpecialMessageIndicationsL(); |
|
760 |
|
761 if(specialMessageIndicationCount!=0) |
|
762 { |
|
763 //add special message indications to out indication count |
|
764 totalIndicationCount+=specialMessageIndicationCount; |
|
765 |
|
766 if(totalIndicationCount>1) |
|
767 { |
|
768 //set the resource id to R_MESSAGE_INDICATION_OTHER_ONE |
|
769 resourceId = R_MESSAGE_INDICATION_OTHER_ONE; |
|
770 //get the total number of messages from the indicatations |
|
771 TUint8 messageCount=0; |
|
772 for(TInt loopCount=0;loopCount<specialMessageIndicationCount;loopCount++) |
|
773 { |
|
774 operations.GetMessageIndicationIEL(loopCount,toStore,messageIndicationType,extendedType,messageProfileType,messageCount); |
|
775 totalMessageCount+=messageCount; |
|
776 } |
|
777 } |
|
778 else |
|
779 { |
|
780 //there is only one indication, get it's type and the number of messages it holds. |
|
781 TUint8 messageCount=0; |
|
782 operations.GetMessageIndicationIEL(0,toStore,messageIndicationType, |
|
783 extendedType,messageProfileType,messageCount); |
|
784 |
|
785 //add the message count to the running total |
|
786 totalMessageCount+=messageCount; |
|
787 |
|
788 switch (messageIndicationType) |
|
789 { |
|
790 case EGsmSmsVoiceMessageWaiting: |
|
791 resourceId = R_MESSAGE_INDICATION_VOICEMAIL_ONE; |
|
792 break; |
|
793 |
|
794 case EGsmSmsFaxMessageWaiting: |
|
795 resourceId = R_MESSAGE_INDICATION_FAX_ONE; |
|
796 break; |
|
797 |
|
798 case EGsmSmsElectronicMailMessageWaiting: |
|
799 resourceId = R_MESSAGE_INDICATION_EMAIL_ONE; |
|
800 break; |
|
801 |
|
802 case EGsmSmsExtendedMessageTypeWaiting: |
|
803 //get the extended indications type |
|
804 if(extendedType==EGsmSmsVideoMessageWaiting) |
|
805 { |
|
806 resourceId = R_MESSAGE_INDICATION_VIDEOMESSAGE_ONE; |
|
807 } |
|
808 else |
|
809 { |
|
810 resourceId = R_MESSAGE_INDICATION_OTHER_ONE; |
|
811 } |
|
812 break; |
|
813 |
|
814 default: |
|
815 resourceId = R_MESSAGE_INDICATION_OTHER_ONE; |
|
816 break; |
|
817 } |
|
818 } |
|
819 //if there is more that one message waiting append 'many' to the id. |
|
820 if(totalMessageCount!=1) |
|
821 { |
|
822 resourceId++; |
|
823 } |
|
824 } |
|
825 |
|
826 const CSmsPDU& smsPDU= aMessage.SmsPDU(); |
|
827 // If no Special Msg Indication found in the User Data, |
|
828 // then check the DataCodingScheme. |
|
829 if (totalIndicationCount==0 && smsPDU.DataCodingSchemePresent()) |
|
830 { |
|
831 TInt bits7to4 = smsPDU.Bits7To4(); |
|
832 |
|
833 switch (bits7to4) |
|
834 { |
|
835 case TSmsDataCodingScheme::ESmsDCSMessageWaitingIndication7Bit: |
|
836 case TSmsDataCodingScheme::ESmsDCSMessageWaitingIndicationUCS2: |
|
837 { |
|
838 if (smsPDU.IndicationState() == TSmsDataCodingScheme::ESmsIndicationActive) |
|
839 { |
|
840 totalIndicationCount = 1; |
|
841 |
|
842 switch (smsPDU.IndicationType()) |
|
843 { |
|
844 case TSmsDataCodingScheme::ESmsVoicemailMessageWaiting: |
|
845 resourceId = R_MESSAGE_INDICATION_VOICEMAIL_ONE; |
|
846 break; |
|
847 case TSmsDataCodingScheme::ESmsFaxMessageWaiting: |
|
848 resourceId = R_MESSAGE_INDICATION_FAX_ONE; |
|
849 break; |
|
850 case TSmsDataCodingScheme::ESmsElectronicMailMessageWaiting: |
|
851 resourceId = R_MESSAGE_INDICATION_EMAIL_ONE; |
|
852 break; |
|
853 case TSmsDataCodingScheme::ESmsFaxOtherMessageWaiting: |
|
854 default: |
|
855 resourceId = R_MESSAGE_INDICATION_OTHER_ONE; |
|
856 break; |
|
857 } //end switch |
|
858 } //end if |
|
859 } //end case |
|
860 default: |
|
861 { |
|
862 break; //do nothing |
|
863 } |
|
864 } |
|
865 } |
|
866 |
|
867 if (totalIndicationCount!=0) |
|
868 { |
|
869 //Special message found. |
|
870 //Look up the resourceID in the SMSS resource file |
|
871 |
|
872 RFs fs; |
|
873 User::LeaveIfError(fs.Connect()); |
|
874 CleanupClosePushL(fs); |
|
875 RResourceFile resFile = OpenResourceFileL(fs); |
|
876 CleanupClosePushL(resFile); |
|
877 ReadResourceStringL(resFile, resourceId, format); |
|
878 CleanupStack::PopAndDestroy(2, &fs); |
|
879 |
|
880 if (totalMessageCount == 1) |
|
881 { |
|
882 if (format.Length() <= aMaxLength) |
|
883 { |
|
884 aDescription = format; |
|
885 } |
|
886 else |
|
887 { |
|
888 // Truncate format so that it fits into aDescription. |
|
889 aDescription = format.Left(aMaxLength); |
|
890 } |
|
891 } |
|
892 else if (format.Length() < aMaxLength) |
|
893 { |
|
894 aDescription.Zero(); |
|
895 aDescription.AppendFormat(format, totalMessageCount); |
|
896 } |
|
897 return ETrue; |
|
898 } |
|
899 else |
|
900 { |
|
901 if(aMessage.Type() == CSmsPDU::ESmsStatusReport) |
|
902 { |
|
903 // for SMS_STATUS_REPORT messages, if we cannot read the string in, then |
|
904 // we do not attempt to extract the description from the message: return EFalse |
|
905 RFs fs; |
|
906 User::LeaveIfError(fs.Connect()); |
|
907 CleanupClosePushL(fs); |
|
908 RResourceFile resFile = OpenResourceFileL(fs); |
|
909 CleanupClosePushL(resFile); |
|
910 ReadResourceStringL(resFile, R_TYPE_STATUS_REPORT, aDescription); |
|
911 CleanupStack::PopAndDestroy(2, &fs); |
|
912 return ETrue; |
|
913 } |
|
914 else |
|
915 { |
|
916 return EFalse; |
|
917 } |
|
918 } |
|
919 } |
|
920 |
|
921 |
|
922 void TSmsUtilities::ExtractDescriptionFromMessage(const CSmsMessage& aMessage, TDes& aDescription, TInt aMaxLength) |
|
923 { |
|
924 if(aMessage.Type() != CSmsPDU::ESmsStatusReport) |
|
925 { |
|
926 aMessage.Buffer().Extract(aDescription, 0, Min(aMaxLength, aMessage.Buffer().Length())); |
|
927 |
|
928 TInt length = aDescription.Length(); |
|
929 |
|
930 //replace paragraphs with spaces. |
|
931 while(length--) |
|
932 { |
|
933 TText& text = aDescription[length]; |
|
934 const TChar ch(text); |
|
935 if (ch.IsSpace() || text == CEditableText::EParagraphDelimiter) |
|
936 text = ' '; |
|
937 } |
|
938 |
|
939 aDescription.TrimAll(); //removes leading trailing and multiple internal whitespace (spaces, line feeds etc) |
|
940 } |
|
941 } |
|
942 |
|
943 void TSmsUtilities::Replace(const TDesC& aOld, const TDesC& aNew, TDes& aString) |
|
944 { |
|
945 TInt find = aString.Find(aOld); |
|
946 |
|
947 if (find != KErrNotFound) |
|
948 { |
|
949 aString.Replace(find, aOld.Length(), aNew); |
|
950 } |
|
951 } |
|