mobilemessaging/smsmtm/clientmtm/src/smut.cpp
changeset 0 72b543305e3a
child 34 84197e66a4bd
equal deleted inserted replaced
-1:000000000000 0:72b543305e3a
       
     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 
       
   646 	CleanupStack::PopAndDestroy(5, db);
       
   647 
       
   648 	__UHEAP_MARKEND;
       
   649 	}
       
   650 
       
   651 TBool TSmsUtilities::ValidGsmNumber(const TDesC& aTelephone)
       
   652 	{
       
   653 	// Returns ETrue if
       
   654 	//	aTelephone is not zero length; and
       
   655 	//	aTelephone[0] is a digit or "+"; and
       
   656 	//	aTelephone[1..] is a digit or "*" or "#".
       
   657 	//	aTelephone has at least 2 valid characters
       
   658 
       
   659 	//Note: Returns EFalse if aTelephone contains any alpha character
       
   660 	//      All spaces are ignored
       
   661 
       
   662 	const TInt length = aTelephone.Length();
       
   663 
       
   664 	if (length < KSmsValidGsmNumberMinLength)
       
   665 		return EFalse;
       
   666 
       
   667 	TPtrC KFirstChar(KSmsValidGsmNumberFirstChar);
       
   668 	TPtrC KOtherChar(KSmsValidGsmNumberOtherChar);
       
   669 	TBool validTel = ETrue;
       
   670 	TInt validCharsFound = 0; //must be >= KSmsValidGsmNumberMinLength by the end
       
   671 
       
   672 	const TText* first = aTelephone.Ptr(); //Points to the first character in aTelephone
       
   673 	const TText* last = first + length - 1; //Points to the last character in aTelephone
       
   674 
       
   675 	//Check each character in the telephone number
       
   676 	while (validTel && first <= last)
       
   677 		{
       
   678 		TChar ch(*first);
       
   679 
       
   680 		if (!ch.IsSpace()) //ignore whitespace
       
   681 			{
       
   682 			if (!ch.IsDigit())
       
   683 				{
       
   684 				//Need to create TPtrC because TDesC::Find() does not take a TChar
       
   685 				TPtrC telCharacter(first, 1);
       
   686 
       
   687 				if (validCharsFound)
       
   688 					{
       
   689 					//Check the remaining characters of the telephone number
       
   690 					validTel = (KOtherChar.Find(telCharacter) != KErrNotFound);
       
   691 					}
       
   692 				else //validCharsFound == 0
       
   693 					{
       
   694 					//Check the first character of the telephone number
       
   695 					validTel = (KFirstChar.Find(telCharacter) != KErrNotFound);
       
   696 					}
       
   697 				}
       
   698 
       
   699 			validCharsFound++;
       
   700 			}
       
   701 
       
   702 		first++; //move to the next character
       
   703 		}
       
   704 
       
   705 	return validTel && validCharsFound >= KSmsValidGsmNumberMinLength;
       
   706 	}
       
   707 
       
   708 void TSmsUtilities::GetName(CContactItemField& aField, TUid aFieldType, TDes& aName)
       
   709 	{
       
   710 	__UHEAP_MARK;
       
   711 	if (aField.ContentType().ContainsFieldType(aFieldType))
       
   712 		{
       
   713 		TPtrC name = aField.TextStorage()->Text();
       
   714 		aName = name.Left(Min(aName.MaxLength(), name.Length()));
       
   715 		}
       
   716 	__UHEAP_MARKEND;
       
   717 	}
       
   718 
       
   719 TBool TSmsUtilities::DoGetDescriptionL(const CSmsMessage& aMessage, TDes& aDescription, TInt aMaxLength)
       
   720 // this function returns EFalse if aMessage has no special message indication data and is not an SMS_STATUS_REPORT,
       
   721 // i.e. more needs to be done to extract the description from the message
       
   722 // otherwise returns ETrue
       
   723 	{
       
   724 	TInt resourceId = 0;
       
   725 	TBuf<KSmsDescriptionLength> format;
       
   726 	TSmsMessageIndicationType messageIndicationType;
       
   727 	TExtendedSmsIndicationType extendedType;
       
   728 	TSmsMessageProfileType messageProfileType;
       
   729 	TBool toStore=EFalse;
       
   730 	TUint totalIndicationCount=0;
       
   731 	TUint totalMessageCount=0;	
       
   732 	
       
   733 	//check if the messae contains an enhanced voice mail indication
       
   734 	CSmsEnhancedVoiceMailOperations& enhancedVoiceMailOperations = STATIC_CAST(CSmsEnhancedVoiceMailOperations&,aMessage.GetOperationsForIEL(CSmsInformationElement::ESmsEnhanceVoiceMailInformation));
       
   735 	
       
   736 	if(enhancedVoiceMailOperations.ContainsEnhancedVoiceMailIEL())
       
   737 		{
       
   738 		//get a copy of the indication
       
   739 		CEnhancedVoiceMailBoxInformation* retrievedNotification=enhancedVoiceMailOperations.CopyEnhancedVoiceMailIEL();
       
   740 		TVoiceMailInfoType typeInfo=retrievedNotification->Type();
       
   741 		//check its type
       
   742 		if(typeInfo==EGsmSmsVoiceMailNotification)
       
   743 			{
       
   744 			//increment the indication count
       
   745 			++totalIndicationCount;
       
   746 			resourceId = R_MESSAGE_INDICATION_ENHANCED_VOICEMAIL_ONE;	
       
   747 			}
       
   748 		
       
   749 		TUint8 messageCount=retrievedNotification->NumberOfVoiceMessages();
       
   750 		//add the message count to the running total
       
   751 		totalMessageCount+=messageCount;
       
   752 		//if there is more that one message of this type then set the resouce id to 'many'
       
   753 		if(messageCount!=1)
       
   754 			{
       
   755 			++resourceId;	
       
   756 			}
       
   757 		
       
   758 		delete retrievedNotification;
       
   759 		}  
       
   760 		
       
   761 	//check for special message waiting indications
       
   762 	CSmsSpecialSMSMessageOperations& operations = STATIC_CAST(CSmsSpecialSMSMessageOperations&,aMessage.GetOperationsForIEL(CSmsInformationElement::ESmsIEISpecialSMSMessageIndication));
       
   763 	TUint specialMessageIndicationCount=operations.GetCountOfSpecialMessageIndicationsL();	
       
   764 	
       
   765 	if(specialMessageIndicationCount!=0)
       
   766 		{
       
   767 		//add special message indications to out indication count
       
   768 		totalIndicationCount+=specialMessageIndicationCount;	
       
   769 		
       
   770 		if(totalIndicationCount>1) 
       
   771 			{
       
   772 			//set the resource id to R_MESSAGE_INDICATION_OTHER_ONE
       
   773 			resourceId = R_MESSAGE_INDICATION_OTHER_ONE;
       
   774 			//get the total number of messages from the indicatations
       
   775 			TUint8 messageCount=0;
       
   776 			for(TInt loopCount=0;loopCount<specialMessageIndicationCount;loopCount++)
       
   777 				{
       
   778 				operations.GetMessageIndicationIEL(loopCount,toStore,messageIndicationType,extendedType,messageProfileType,messageCount);
       
   779 				totalMessageCount+=messageCount;						
       
   780 				}
       
   781 			}
       
   782 		else
       
   783 			{
       
   784 			//there is only one indication, get it's type and the number of messages it holds.
       
   785 			TUint8 messageCount=0;
       
   786 			operations.GetMessageIndicationIEL(0,toStore,messageIndicationType,
       
   787 											extendedType,messageProfileType,messageCount);	
       
   788 		
       
   789 			//add the message count to the running total
       
   790 			totalMessageCount+=messageCount;
       
   791 		
       
   792 			switch (messageIndicationType)
       
   793 				{
       
   794 				case EGsmSmsVoiceMessageWaiting:
       
   795 					resourceId = R_MESSAGE_INDICATION_VOICEMAIL_ONE;
       
   796 					break;
       
   797 				
       
   798 				case EGsmSmsFaxMessageWaiting:
       
   799 					resourceId = R_MESSAGE_INDICATION_FAX_ONE;
       
   800 					break;
       
   801 				
       
   802 				case EGsmSmsElectronicMailMessageWaiting:
       
   803 					resourceId = R_MESSAGE_INDICATION_EMAIL_ONE;
       
   804 					break;
       
   805 					
       
   806 				case EGsmSmsExtendedMessageTypeWaiting:
       
   807 					//get the extended indications type
       
   808 					if(extendedType==EGsmSmsVideoMessageWaiting)
       
   809 						{
       
   810 						resourceId = R_MESSAGE_INDICATION_VIDEOMESSAGE_ONE;	
       
   811 						}
       
   812 					else
       
   813 						{
       
   814 						resourceId = R_MESSAGE_INDICATION_OTHER_ONE;	
       
   815 						}
       
   816 					break;
       
   817 					
       
   818 				default:
       
   819 					resourceId = R_MESSAGE_INDICATION_OTHER_ONE;
       
   820 					break;
       
   821 				}	
       
   822 			}
       
   823 		//if there is more that one message waiting append 'many' to the id.
       
   824 		if(totalMessageCount!=1)
       
   825 			{
       
   826 			resourceId++;	
       
   827 			}
       
   828 		}
       
   829 
       
   830 	const CSmsPDU& smsPDU= aMessage.SmsPDU();
       
   831 	// If no Special Msg Indication found in the User Data,
       
   832 	// then check the DataCodingScheme.
       
   833 	if (totalIndicationCount==0 && smsPDU.DataCodingSchemePresent())
       
   834 		{
       
   835 		TInt bits7to4 = smsPDU.Bits7To4();
       
   836 
       
   837 		switch (bits7to4)
       
   838 			{
       
   839 			case TSmsDataCodingScheme::ESmsDCSMessageWaitingIndication7Bit:
       
   840 			case TSmsDataCodingScheme::ESmsDCSMessageWaitingIndicationUCS2:
       
   841 				{
       
   842 				if (smsPDU.IndicationState() == TSmsDataCodingScheme::ESmsIndicationActive)
       
   843 					{
       
   844 					totalIndicationCount = 1;
       
   845 
       
   846 					switch (smsPDU.IndicationType())
       
   847 						{
       
   848 						case TSmsDataCodingScheme::ESmsVoicemailMessageWaiting:
       
   849 							resourceId = R_MESSAGE_INDICATION_VOICEMAIL_ONE;
       
   850 							break;
       
   851 						case TSmsDataCodingScheme::ESmsFaxMessageWaiting:
       
   852 							resourceId = R_MESSAGE_INDICATION_FAX_ONE;
       
   853 							break;
       
   854 						case TSmsDataCodingScheme::ESmsElectronicMailMessageWaiting:
       
   855 							resourceId = R_MESSAGE_INDICATION_EMAIL_ONE;
       
   856 							break;
       
   857 						case TSmsDataCodingScheme::ESmsFaxOtherMessageWaiting:
       
   858 						default:
       
   859 							resourceId = R_MESSAGE_INDICATION_OTHER_ONE;
       
   860 							break;
       
   861 						} //end switch
       
   862 					} //end if
       
   863 				} //end case
       
   864 			default:
       
   865 				{
       
   866 				break; //do nothing
       
   867 				}
       
   868 			}
       
   869 		}
       
   870 	
       
   871 	if (totalIndicationCount!=0)
       
   872 		{
       
   873 		//Special message found.
       
   874 		//Look up the resourceID in the SMSS resource file
       
   875 
       
   876 		RFs fs;
       
   877 		User::LeaveIfError(fs.Connect());
       
   878 		CleanupClosePushL(fs);
       
   879 		RResourceFile resFile = OpenResourceFileL(fs);
       
   880 		CleanupClosePushL(resFile);
       
   881 		ReadResourceStringL(resFile, resourceId, format);
       
   882 		CleanupStack::PopAndDestroy(2, &fs);
       
   883 
       
   884 		if (totalMessageCount == 1)
       
   885 			{
       
   886 			if (format.Length() <= aMaxLength)
       
   887 				{
       
   888 				aDescription = format;
       
   889 				}
       
   890 			else
       
   891 				{
       
   892 				// Truncate format so that it fits into aDescription.
       
   893 				aDescription = format.Left(aMaxLength);
       
   894 				}
       
   895 			}
       
   896 		else if (format.Length() < aMaxLength)
       
   897 			{
       
   898 			aDescription.Zero();
       
   899 			aDescription.AppendFormat(format, totalMessageCount);
       
   900 			}
       
   901 		return ETrue;
       
   902 		}
       
   903 	else
       
   904 		{
       
   905 		if(aMessage.Type() == CSmsPDU::ESmsStatusReport)
       
   906 			{
       
   907 			// for SMS_STATUS_REPORT messages, if we cannot read the string in, then
       
   908 			// we do not attempt to extract the description from the message: return EFalse
       
   909 			RFs fs;
       
   910 			User::LeaveIfError(fs.Connect());
       
   911 			CleanupClosePushL(fs);
       
   912 			RResourceFile resFile = OpenResourceFileL(fs);
       
   913 			CleanupClosePushL(resFile);
       
   914 			ReadResourceStringL(resFile, R_TYPE_STATUS_REPORT, aDescription);
       
   915 			CleanupStack::PopAndDestroy(2, &fs);
       
   916 			return ETrue;
       
   917 			}
       
   918 		else
       
   919 			{
       
   920 			return EFalse;
       
   921 			}
       
   922 		}
       
   923 	}
       
   924 
       
   925 
       
   926 void TSmsUtilities::ExtractDescriptionFromMessage(const CSmsMessage& aMessage, TDes& aDescription, TInt aMaxLength)
       
   927 	{
       
   928 	if(aMessage.Type() != CSmsPDU::ESmsStatusReport)
       
   929 		{
       
   930 		aMessage.Buffer().Extract(aDescription, 0, Min(aMaxLength, aMessage.Buffer().Length()));
       
   931 
       
   932 		TInt length = aDescription.Length();
       
   933 
       
   934 		//replace paragraphs with spaces.
       
   935 		while(length--)
       
   936 			{
       
   937 			TText& text = aDescription[length];
       
   938 			const TChar ch(text);
       
   939 			if (ch.IsSpace() || text == CEditableText::EParagraphDelimiter)
       
   940 				text = ' ';
       
   941 			}
       
   942 
       
   943 		aDescription.TrimAll(); //removes leading trailing and multiple internal whitespace (spaces, line feeds etc)
       
   944 		}
       
   945 	}
       
   946 
       
   947 void TSmsUtilities::Replace(const TDesC& aOld, const TDesC& aNew, TDes& aString)
       
   948 	{
       
   949 	TInt find = aString.Find(aOld);
       
   950 
       
   951 	if (find != KErrNotFound)
       
   952 		{
       
   953 		aString.Replace(find, aOld.Length(), aNew);
       
   954 		}
       
   955 	}