messagingappbase/smsmtm/clientmtm/src/smut.cpp
changeset 25 84d9eb65b26f
parent 23 238255e8b033
child 27 e4592d119491
child 37 518b245aa84c
child 79 2981cb3aa489
equal deleted inserted replaced
23:238255e8b033 25:84d9eb65b26f
     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 	}