mobilemessaging/smum/src/smsdetailsplugin.cpp
changeset 0 72b543305e3a
child 17 caea42e26caa
equal deleted inserted replaced
-1:000000000000 0:72b543305e3a
       
     1 /*
       
     2 * Copyright (c) 2006-2009 Nokia Corporation and/or its subsidiary(-ies).
       
     3 * All rights reserved.
       
     4 * This component and the accompanying materials are made available
       
     5 * under the terms of "Eclipse Public License v1.0"
       
     6 * which accompanies this distribution, and is available
       
     7 * at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     8 *
       
     9 * Initial Contributors:
       
    10 * Nokia Corporation - initial contribution.
       
    11 *
       
    12 * Contributors:
       
    13 *
       
    14 * Description:  
       
    15 *       SMS Details Ecom Plugin implementation.
       
    16 *
       
    17 */
       
    18 
       
    19 
       
    20 
       
    21 
       
    22 // INCLUDE FILES
       
    23 
       
    24 #include <e32std.h>
       
    25 #include <implementationproxy.h>
       
    26 #include <data_caging_path_literals.hrh> 
       
    27 
       
    28 #include <gsmumsg.h>
       
    29 #include <gsmuieoperations.h>
       
    30 #include <gsmubuf.h>
       
    31 
       
    32 #include <txtetext.h>   // CEditableText
       
    33 
       
    34 #include <MVPbkContactStore.h>
       
    35 #include <MVPbkContactStoreProperties.h>
       
    36 #include <contactmatcher.h>
       
    37 #include <CVPbkContactStoreUriArray.h>
       
    38 #include <MVPbkContactLink.h>
       
    39 #include <CVPbkContactLinkArray.h>
       
    40 #include <MVPbkFieldType.h>
       
    41 #include <TVPbkFieldVersitProperty.h>
       
    42 #include <MVPbkStoreContact.h>
       
    43 #include <CVPbkPhoneNumberMatchStrategy.h>
       
    44 #include <VPbkContactStoreUris.h>
       
    45 #include <TVPbkContactStoreUriPtr.h>
       
    46 #include <CPbk2StoreConfiguration.h>   // Contact store configuration
       
    47 
       
    48 #include <StringLoader.h>               // StringLoader
       
    49 #include <stringresourcereader.h>
       
    50 #include <centralrepository.h>
       
    51 #include <telconfigcrkeys.h>    // KCRUidTelephonyConfiguration
       
    52 #include <commonphoneparser.h>      // Common phone number validity checker
       
    53 
       
    54 #include <smsdetailsplugindata.rsg>
       
    55 #include "smsdetailsplugin.h"
       
    56 
       
    57 //For logging
       
    58 #include "SmumLogging.h"
       
    59 
       
    60 // CONSTANTS
       
    61 
       
    62 const TInt KSmsDefaultGsmNumberMatchLength = 7;
       
    63 
       
    64 const TInt KErrMultipleMatchFound = KErrGeneral;
       
    65 
       
    66 _LIT( KSmsDetailsPluginResourceFile, "smsdetailsplugindata.rsc" );
       
    67 
       
    68 
       
    69 struct TCntMatchRequestData
       
    70     {
       
    71     TPtrC iFromAddress;
       
    72     TDes* iOutput;
       
    73     TInt iMaxLength;
       
    74     TInt iMatchDigitCount;
       
    75     };
       
    76 
       
    77 
       
    78 class CSmsDetailsPluginOneShotOperation : public CActive
       
    79     {
       
    80 public:
       
    81     CSmsDetailsPluginOneShotOperation( TCntMatchRequestData& aRequestData );
       
    82     ~CSmsDetailsPluginOneShotOperation();
       
    83 
       
    84 public: // API
       
    85     inline TInt CompletionCode() const { return iStatus.Int(); }
       
    86 
       
    87 private: // From CActive
       
    88     void RunL();
       
    89     void DoCancel();
       
    90 
       
    91 private: // Internal functions
       
    92     void MatchContactL();
       
    93     HBufC* GetContactNameL(const MVPbkContactLink& aContactLink);
       
    94     HBufC* GetContactNameInLowerCaseL(const MVPbkContactLink& aContactLink );
       
    95     TBool  ShowContactNameL(CVPbkContactLinkArray* aLinkArray, TInt &nameIndex);
       
    96     TInt GetCurrentStoreIndexL( CVPbkContactLinkArray& aLinkArray );
       
    97     
       
    98 private: // Data members
       
    99     TCntMatchRequestData& iRequestData;
       
   100     CContactMatcher* iContactMatcher;
       
   101     };
       
   102 
       
   103 
       
   104 // ==================== LOCAL FUNCTIONS ====================
       
   105 
       
   106 // -----------------------------------------------------------------------------
       
   107 // Define the implementation table for Ecom
       
   108 // -----------------------------------------------------------------------------
       
   109 //
       
   110 const TImplementationProxy ImplementationTable[] = 
       
   111 	{
       
   112 	IMPLEMENTATION_PROXY_ENTRY(0x102828A8, CSmsDetailsPlugin::NewL)
       
   113 	};
       
   114 
       
   115 // -----------------------------------------------------------------------------
       
   116 // Returns the implementation table
       
   117 // -----------------------------------------------------------------------------
       
   118 //
       
   119 EXPORT_C const TImplementationProxy* ImplementationGroupProxy(TInt& aTableCount)
       
   120 	{
       
   121 	aTableCount = sizeof(ImplementationTable) / sizeof(TImplementationProxy);
       
   122 
       
   123 	return ImplementationTable;
       
   124 	}
       
   125 
       
   126 
       
   127 // ============================ MEMBER FUNCTIONS ===============================
       
   128 
       
   129 // -----------------------------------------------------------------------------
       
   130 // CSmsDetailsPlugin::NewL
       
   131 // -----------------------------------------------------------------------------
       
   132 //
       
   133 CSmsDetailsPlugin* CSmsDetailsPlugin::NewL()
       
   134 	{
       
   135 	SMUMLOGGER_ENTERFN("CSmsDetailsPlugin::NewL");
       
   136 	CSmsDetailsPlugin* self = new (ELeave) CSmsDetailsPlugin();	
       
   137 	SMUMLOGGER_LEAVEFN("CSmsDetailsPlugin::NewL");
       
   138 	return self;
       
   139 	}
       
   140 
       
   141 // -----------------------------------------------------------------------------
       
   142 // CSmsDetailsPlugin::CreateResourceReaderL
       
   143 // -----------------------------------------------------------------------------
       
   144 //
       
   145 void CSmsDetailsPlugin::CreateResourceReaderL( RFs* aFs )
       
   146 	{
       
   147 	SMUMLOGGER_ENTERFN("CSmsDetailsPlugin::CreateResourceReaderL");
       
   148 	if ( !iResourceReader )
       
   149 	    {
       
   150         TParse fileParse;
       
   151         fileParse.Set( KSmsDetailsPluginResourceFile, &KDC_RESOURCE_FILES_DIR, NULL );
       
   152         TFileName resourceFile( fileParse.FullName() );
       
   153         if ( aFs )
       
   154             {
       
   155             iResourceReader = CStringResourceReader::NewL( resourceFile, *aFs );
       
   156             }
       
   157         else
       
   158             {
       
   159             iResourceReader = CStringResourceReader::NewL( resourceFile );
       
   160             }
       
   161 	    }
       
   162 	SMUMLOGGER_LEAVEFN("CSmsDetailsPlugin::CreateResourceReaderL");
       
   163 	}
       
   164 
       
   165 // -----------------------------------------------------------------------------
       
   166 // CSmsDetailsPlugin::CSmsDetailsPlugin
       
   167 // -----------------------------------------------------------------------------
       
   168 //
       
   169 CSmsDetailsPlugin::CSmsDetailsPlugin()
       
   170 	{
       
   171 	}
       
   172 
       
   173 // -----------------------------------------------------------------------------
       
   174 // CSmsDetailsPlugin::~CSmsDetailsPlugin
       
   175 // -----------------------------------------------------------------------------
       
   176 //
       
   177 CSmsDetailsPlugin::~CSmsDetailsPlugin()
       
   178 	{
       
   179 	SMUMLOGGER_ENTERFN("CSmsDetailsPlugin::~CSmsDetailsPlugin");
       
   180 	delete iResourceReader;
       
   181     SMUMLOGGER_LEAVEFN("CSmsDetailsPlugin::~CSmsDetailsPlugin");
       
   182 	}
       
   183 
       
   184 // -----------------------------------------------------------------------------
       
   185 // CSmsDetailsPlugin::GetDetails
       
   186 // -----------------------------------------------------------------------------
       
   187 //
       
   188 TInt CSmsDetailsPlugin::GetDetails(RFs& aFs, const CSmsMessage& aMessage, TDes& aDetails, TInt aMaxLength)
       
   189 	{
       
   190     SMUMLOGGER_ENTERFN("CSmsDetailsPlugin::GetDetails(aFs, aMessage, aDetails, aMaxLength");
       
   191 
       
   192 	__ASSERT_DEBUG( aMaxLength <= aDetails.MaxLength(), User::Invariant() );
       
   193 
       
   194 	if (aMaxLength > aDetails.MaxLength())
       
   195 		{
       
   196 		aMaxLength = aDetails.MaxLength();
       
   197 		}
       
   198 
       
   199 	aDetails.Zero();
       
   200 
       
   201 	TPtrC fromAddress;
       
   202 
       
   203 	switch (aMessage.SmsPDU().Type())
       
   204 		{
       
   205 		case CSmsPDU::ESmsSubmit:
       
   206 		case CSmsPDU::ESmsDeliver:
       
   207 		case CSmsPDU::ESmsStatusReport:
       
   208 			fromAddress.Set(aMessage.SmsPDU().ToFromAddress());
       
   209 			break;
       
   210 		default:
       
   211 			return KErrNotSupported;
       
   212 		}
       
   213 
       
   214 	SMUMLOGGER_LEAVEFN("CSmsDetailsPlugin::GetDetails(aFs, aMessage, aDetails, aMaxLength");
       
   215 	return GetDetails(aFs, fromAddress, aDetails, aMaxLength);
       
   216 	}
       
   217 
       
   218 // -----------------------------------------------------------------------------
       
   219 // CSmsDetailsPlugin::GetDetails
       
   220 // -----------------------------------------------------------------------------
       
   221 //
       
   222 TInt CSmsDetailsPlugin::GetDetails(RFs& aFs, const TDesC& aFromAddress, TDes& aDetails, TInt aMaxLength)
       
   223 	{
       
   224     SMUMLOGGER_ENTERFN("CSmsDetailsPlugin::GetDetails(aFs, aFromAddress, aDetails, aMaxLength");
       
   225 	__ASSERT_DEBUG( aMaxLength <= aDetails.MaxLength(), User::Invariant() );
       
   226 
       
   227 	if (aMaxLength > aDetails.MaxLength())
       
   228 		{
       
   229 		aMaxLength = aDetails.MaxLength();
       
   230 		}
       
   231 
       
   232     TInt ret = KErrNone;
       
   233 	TRAPD(err, DoGetDetailsL(aFs, aFromAddress, aDetails, aMaxLength));
       
   234 
       
   235 	if ( (err != KErrNone) || (aDetails.Length() == 0) )
       
   236 		{
       
   237 		if (aFromAddress.Length() <= aMaxLength)
       
   238 			{
       
   239 			aDetails = aFromAddress;
       
   240 			aDetails.Trim();
       
   241 			}
       
   242 		else
       
   243 			{
       
   244 			// Truncate aFromAddress so that it fits into aDetails.
       
   245 			aDetails = aFromAddress.Left(aMaxLength);
       
   246 			aDetails.Trim();
       
   247 			}
       
   248         // Propagate KErrCancel forwards
       
   249         if ( err == KErrCancel )
       
   250             {
       
   251             ret = err;
       
   252             }
       
   253 		}
       
   254     SMUMLOGGER_LEAVEFN("CSmsDetailsPlugin::GetDetails(aFs, aFromAddress, aDetails, aMaxLength");
       
   255 
       
   256 	return ret;
       
   257 	}
       
   258 
       
   259 // -----------------------------------------------------------------------------
       
   260 // CSmsDetailsPlugin::GetDescription
       
   261 // -----------------------------------------------------------------------------
       
   262 //
       
   263 TInt CSmsDetailsPlugin::GetDescription(const CSmsMessage& aMessage, TDes& aDescription, TInt aMaxLength)
       
   264 	{
       
   265     SMUMLOGGER_ENTERFN("CSmsDetailsPlugin::GetDescription(aMessage, aDescription, aMaxLength");
       
   266 
       
   267 	__ASSERT_DEBUG( aMaxLength <= aDescription.MaxLength(), User::Invariant() );
       
   268 
       
   269 	if (aMaxLength > aDescription.MaxLength())
       
   270 		{
       
   271 		aMaxLength = aDescription.MaxLength();
       
   272 		}
       
   273 
       
   274 	aDescription.Zero();
       
   275 
       
   276 	TBool gotDescription = EFalse;
       
   277 	TRAPD(err, gotDescription = DoGetDescriptionL(aMessage, aDescription, aMaxLength));
       
   278 	if(err != KErrNone || !gotDescription)
       
   279 	    {
       
   280 		ExtractDescriptionFromMessage(aMessage, aDescription, aMaxLength);
       
   281 	    }
       
   282     SMUMLOGGER_LEAVEFN("CSmsDetailsPlugin::GetDescription(aMessage, aDescription, aMaxLength");
       
   283 	return KErrNone;
       
   284 	}
       
   285 
       
   286 // -----------------------------------------------------------------------------
       
   287 // CSmsDetailsPlugin::DoGetDetailsL
       
   288 //
       
   289 // For clarity the whole function is flagged
       
   290 // -----------------------------------------------------------------------------
       
   291 //
       
   292 
       
   293 void CSmsDetailsPlugin::DoGetDetailsL(RFs& aFs, const TDesC& aFromAddress, TDes& aDetails, TInt aMaxLength)
       
   294 	{
       
   295 	__UHEAP_MARK;
       
   296     SMUMLOGGER_ENTERFN("CSmsDetailsPlugin::DoGetDetailsL(aFs, aFromAddress, aDetails, aMaxLength");
       
   297 	// Check that aFromAddress is a valid GSM telephone number
       
   298     if ( !CommonPhoneParser::IsValidPhoneNumber( aFromAddress, CommonPhoneParser::ESMSNumber ) )
       
   299         {
       
   300 		User::Leave( KErrArgument );
       
   301         }
       
   302 
       
   303 	aDetails.Zero();
       
   304 
       
   305     TInt matchDigitCount = KSmsDefaultGsmNumberMatchLength;
       
   306 
       
   307     // Read the amount of digits to be used in contact matching
       
   308     // The key is owned by PhoneApp
       
   309     CRepository* repository = CRepository::NewLC(KCRUidTelConfiguration);
       
   310     if (KErrNone == repository->Get(KTelMatchDigits, matchDigitCount))
       
   311         {
       
   312         // Min is 7
       
   313         matchDigitCount =
       
   314             Max(matchDigitCount, KSmsDefaultGsmNumberMatchLength);
       
   315         }
       
   316     CleanupStack::PopAndDestroy(); // repository
       
   317 
       
   318     // Match contacts to the from address
       
   319     // Prepare worker thread arguments
       
   320     TCntMatchRequestData requestData;
       
   321     requestData.iFromAddress.Set( aFromAddress );
       
   322     requestData.iOutput = &aDetails;
       
   323     requestData.iMaxLength = aMaxLength;
       
   324     requestData.iMatchDigitCount = matchDigitCount;
       
   325 
       
   326     // Prepare thread name
       
   327     _LIT( KSmsDetailsPluginCntMatcherWorkerThreadName, "S60SmsDetailsPluginWorkerThread_%08x" );
       
   328     TName threadName;
       
   329     threadName.AppendFormat( KSmsDetailsPluginCntMatcherWorkerThreadName, &requestData );
       
   330 
       
   331     // Create worker thread 
       
   332     RThread workerThread;
       
   333     CleanupClosePushL( workerThread );
       
   334     /*
       
   335      * LSAN-7HUB6B:: Contact matcher thread was using watcher process stack and hence running
       
   336      * out of memory as the inbox was growing. At some point, when inbox has arnd 1700 msgs, it fails to allocate memory
       
   337      * and hence there was no matching. 
       
   338      * changed the thread creation to use seperate stack of 1MB max size.
       
   339      */
       
   340     const TInt threadCreationError = workerThread.Create( threadName, CntMatchThreadFunction, 8 * 1024, 0x1000, 0x100000, &requestData  );
       
   341     User::LeaveIfError( threadCreationError );
       
   342 
       
   343     // Wait for thread to finish work
       
   344     TRequestStatus workerThreadStatus;
       
   345     workerThread.Rendezvous( workerThreadStatus );
       
   346     workerThread.Resume();
       
   347     User::WaitForRequest( workerThreadStatus );
       
   348 
       
   349     // Propagate error
       
   350     User::LeaveIfError( workerThreadStatus.Int() );
       
   351 
       
   352     // Tidy up
       
   353     CleanupStack::PopAndDestroy( &workerThread );
       
   354     SMUMLOGGER_LEAVEFN("CSmsDetailsPlugin::DoGetDetailsL(aFs, aFromAddress, aDetails, aMaxLength");
       
   355        
       
   356     __UHEAP_MARKEND;
       
   357     }
       
   358 
       
   359 
       
   360 // -----------------------------------------------------------------------------
       
   361 // CSmsDetailsPlugin::DoGetDescriptionL
       
   362 // -----------------------------------------------------------------------------
       
   363 //
       
   364 TBool CSmsDetailsPlugin::DoGetDescriptionL(const CSmsMessage& aMessage,
       
   365     TDes& aDescription, TInt aMaxLength)
       
   366 // this function returns EFalse if aMessage has no special message indication data and is not an SMS_STATUS_REPORT,
       
   367 // i.e. more needs to be done to extract the description from the message
       
   368 // otherwise returns ETrue
       
   369 	{
       
   370     SMUMLOGGER_ENTERFN("CSmsDetailsPlugin::DoGetDescriptionL(aMessage, aDescription, aMaxLength");
       
   371 
       
   372     TInt resourceId = 0;
       
   373 	TBuf<KSmsDescriptionLength> format;
       
   374 	TSmsMessageIndicationType messageIndicationType;
       
   375 	TExtendedSmsIndicationType extendedType;
       
   376 	TSmsMessageProfileType messageProfileType;
       
   377 	TBool toStore=EFalse;
       
   378 	TUint totalIndicationCount=0;
       
   379 	TUint totalMessageCount=0;	
       
   380 	
       
   381 	//check if the messae contains an enhanced voice mail indication
       
   382 	CSmsEnhancedVoiceMailOperations& enhancedVoiceMailOperations = STATIC_CAST(CSmsEnhancedVoiceMailOperations&,aMessage.GetOperationsForIEL(CSmsInformationElement::ESmsEnhanceVoiceMailInformation));
       
   383 	
       
   384 	if(enhancedVoiceMailOperations.ContainsEnhancedVoiceMailIEL())
       
   385 		{
       
   386 		//get a copy of the indication
       
   387 		CEnhancedVoiceMailBoxInformation* retrievedNotification=enhancedVoiceMailOperations.CopyEnhancedVoiceMailIEL();
       
   388 		TVoiceMailInfoType typeInfo=retrievedNotification->Type();
       
   389 		//check its type
       
   390 		if(typeInfo==EGsmSmsVoiceMailNotification)
       
   391 			{
       
   392 			//increment the indication count
       
   393 			++totalIndicationCount;
       
   394 			resourceId = R_MSG_INDICATION_ENHANCED_VOICEMAIL_ONE;	
       
   395 			}
       
   396 		
       
   397 		TUint8 messageCount=retrievedNotification->NumberOfVoiceMessages();
       
   398 		//add the message count to the running total
       
   399 		totalMessageCount+=messageCount;
       
   400 		//if there is more that one message of this type then set the resouce id to 'many'
       
   401 		if(messageCount!=1)
       
   402 			{
       
   403 			++resourceId;	
       
   404 			}
       
   405 		
       
   406 		delete retrievedNotification;
       
   407 		}  
       
   408 		
       
   409 	//check for special message waiting indications
       
   410 	CSmsSpecialSMSMessageOperations& operations = STATIC_CAST(CSmsSpecialSMSMessageOperations&,aMessage.GetOperationsForIEL(CSmsInformationElement::ESmsIEISpecialSMSMessageIndication));
       
   411 	TUint specialMessageIndicationCount=operations.GetCountOfSpecialMessageIndicationsL();	
       
   412 	
       
   413 	if(specialMessageIndicationCount!=0)
       
   414 		{
       
   415 		//add special message indications to out indication count
       
   416 		totalIndicationCount+=specialMessageIndicationCount;	
       
   417 		
       
   418 		if(totalIndicationCount>1) 
       
   419 			{
       
   420 			//set the resource id to R_MSG_INDICATION_OTHER_ONE
       
   421 			resourceId = R_MSG_INDICATION_OTHER_ONE;
       
   422 			//get the total number of messages from the indicatations
       
   423 			TUint8 messageCount=0;
       
   424 			for(TInt loopCount=0;loopCount<specialMessageIndicationCount;loopCount++)
       
   425 				{
       
   426 				operations.GetMessageIndicationIEL(loopCount,toStore,messageIndicationType,extendedType,messageProfileType,messageCount);
       
   427 				totalMessageCount+=messageCount;						
       
   428 				}
       
   429 			}
       
   430 		else
       
   431 			{
       
   432 			//there is only one indication, get it's type and the number of messages it holds.
       
   433 			TUint8 messageCount=0;
       
   434 			operations.GetMessageIndicationIEL(0,toStore,messageIndicationType,
       
   435 											extendedType,messageProfileType,messageCount);	
       
   436 		
       
   437 			//add the message count to the running total
       
   438 			totalMessageCount+=messageCount;
       
   439 		
       
   440 			switch (messageIndicationType)
       
   441 				{
       
   442 				case EGsmSmsVoiceMessageWaiting:
       
   443 					resourceId = R_MSG_INDICATION_VOICEMAIL_ONE;
       
   444 					break;
       
   445 				
       
   446 				case EGsmSmsFaxMessageWaiting:
       
   447 					resourceId = R_MSG_INDICATION_FAX_ONE;
       
   448 					break;
       
   449 				
       
   450 				case EGsmSmsElectronicMailMessageWaiting:
       
   451 					resourceId = R_MSG_INDICATION_EMAIL_ONE;
       
   452 					break;
       
   453 					
       
   454 				case EGsmSmsExtendedMessageTypeWaiting:
       
   455 					//get the extended indications type
       
   456 					if(extendedType==EGsmSmsVideoMessageWaiting)
       
   457 						{
       
   458 						resourceId = R_MSG_INDICATION_VIDEOMESSAGE_ONE;	
       
   459 						}
       
   460 					else
       
   461 						{
       
   462 						resourceId = R_MSG_INDICATION_OTHER_ONE;	
       
   463 						}
       
   464 					break;
       
   465 					
       
   466 				default:
       
   467 					resourceId = R_MSG_INDICATION_OTHER_ONE;
       
   468 					break;
       
   469 				}	
       
   470 			}
       
   471 		//if there is more that one message waiting append 'many' to the id.
       
   472 		if(totalMessageCount!=1)
       
   473 			{
       
   474 			resourceId++;	
       
   475 			}
       
   476 		}
       
   477 
       
   478 	const CSmsPDU& smsPDU= aMessage.SmsPDU();
       
   479 	// If no Special Msg Indication found in the User Data,
       
   480 	// then check the DataCodingScheme.
       
   481 	if (totalIndicationCount==0 && smsPDU.DataCodingSchemePresent())
       
   482 		{
       
   483 		TInt bits7to4 = smsPDU.Bits7To4();
       
   484 
       
   485 		switch (bits7to4)
       
   486 			{
       
   487 			case TSmsDataCodingScheme::ESmsDCSMessageWaitingIndication7Bit:
       
   488 			case TSmsDataCodingScheme::ESmsDCSMessageWaitingIndicationUCS2:
       
   489 				{
       
   490 				if (smsPDU.IndicationState() == TSmsDataCodingScheme::ESmsIndicationActive)
       
   491 					{
       
   492 					totalIndicationCount = 1;
       
   493 
       
   494 					switch (smsPDU.IndicationType())
       
   495 						{
       
   496 						case TSmsDataCodingScheme::ESmsVoicemailMessageWaiting:
       
   497 							resourceId = R_MSG_INDICATION_VOICEMAIL_ONE;
       
   498 							break;
       
   499 						case TSmsDataCodingScheme::ESmsFaxMessageWaiting:
       
   500 							resourceId = R_MSG_INDICATION_FAX_ONE;
       
   501 							break;
       
   502 						case TSmsDataCodingScheme::ESmsElectronicMailMessageWaiting:
       
   503 							resourceId = R_MSG_INDICATION_EMAIL_ONE;
       
   504 							break;
       
   505 						case TSmsDataCodingScheme::ESmsFaxOtherMessageWaiting:
       
   506 						default:
       
   507 							resourceId = R_MSG_INDICATION_OTHER_ONE;
       
   508 							break;
       
   509 						} //end switch
       
   510 					} //end if
       
   511 				} //end case
       
   512 			default:
       
   513 				{
       
   514 				break; //do nothing
       
   515 				}
       
   516 			}
       
   517 		}
       
   518 	
       
   519 	if (totalIndicationCount!=0)
       
   520 		{
       
   521 		//Special message found.
       
   522 		CreateResourceReaderL( NULL );
       
   523         format = iResourceReader->ReadResourceString( resourceId );
       
   524         
       
   525         if (totalMessageCount == 1)
       
   526             {
       
   527             if (format.Length() <= aMaxLength)
       
   528                 {
       
   529                 aDescription = format;
       
   530                 }
       
   531             else
       
   532                 {
       
   533                 // Truncate format so that it fits into aDescription.
       
   534                 aDescription = format.Left(aMaxLength);
       
   535                 }
       
   536             }
       
   537         else if (format.Length() < aMaxLength)
       
   538             {
       
   539             StringLoader::Format( aDescription, format, -1, totalMessageCount );
       
   540             }
       
   541         
       
   542         SMUMLOGGER_LEAVEFN("CSmsDetailsPlugin::DoGetDescriptionL(aMessage, aDescription, aMaxLength) - 1- true");
       
   543         return ETrue;
       
   544 		}
       
   545 	else
       
   546 		{
       
   547 		if(aMessage.Type() == CSmsPDU::ESmsStatusReport)
       
   548 			{
       
   549 			// for SMS_STATUS_REPORT messages, if we cannot read the string in, then
       
   550 			// we do not attempt to extract the description from the message: return EFalse
       
   551     		CreateResourceReaderL( NULL );
       
   552 			aDescription.Copy( iResourceReader->ReadResourceString( R_MSG_TYPE_STATUS_REPORT ) );
       
   553 	        SMUMLOGGER_LEAVEFN("CSmsDetailsPlugin::DoGetDescriptionL(aMessage, aDescription, aMaxLength) - 2- true");
       
   554 			return ETrue;
       
   555 			}
       
   556 		else
       
   557 			{
       
   558 	        SMUMLOGGER_LEAVEFN("CSmsDetailsPlugin::DoGetDescriptionL(aMessage, aDescription, aMaxLength) - 3- false");
       
   559 			return EFalse;
       
   560 			}
       
   561 		}
       
   562 	}
       
   563 
       
   564 // -----------------------------------------------------------------------------
       
   565 // CSmsDetailsPlugin::ExtractDescriptionFromMessage
       
   566 // -----------------------------------------------------------------------------
       
   567 //
       
   568 void CSmsDetailsPlugin::ExtractDescriptionFromMessage(const CSmsMessage& aMessage, TDes& aDescription, TInt aMaxLength)
       
   569 	{
       
   570     SMUMLOGGER_ENTERFN("CSmsDetailsPlugin::ExtractDescriptionFromMessage(aMessage, aDescription, aMaxLength)");
       
   571 	if(aMessage.Type() != CSmsPDU::ESmsStatusReport)
       
   572 		{
       
   573 		aMessage.Buffer().Extract(aDescription, 0, Min(aMaxLength, aMessage.Buffer().Length()));
       
   574 
       
   575 		TInt length = aDescription.Length();
       
   576 
       
   577 		//replace paragraphs with spaces.
       
   578 		while(length--)
       
   579 			{
       
   580 			TText& text = aDescription[length];
       
   581 			const TChar ch(text);
       
   582 			if (ch.IsSpace() || text == CEditableText::EParagraphDelimiter)
       
   583 				text = ' ';
       
   584 			}
       
   585 
       
   586 		aDescription.TrimAll(); //removes leading trailing and multiple internal whitespace (spaces, line feeds etc)
       
   587 		}
       
   588     SMUMLOGGER_LEAVEFN("CSmsDetailsPlugin::ExtractDescriptionFromMessage(aMessage, aDescription, aMaxLength)");
       
   589 	}
       
   590 
       
   591 TInt CSmsDetailsPlugin::CntMatchThreadFunction( TAny* aRequestData )
       
   592     {
       
   593     SMUMLOGGER_ENTERFN("CSmsDetailsPlugin::CntMatchThreadFunction");
       
   594     TInt error = KErrNone;
       
   595     //
       
   596     CTrapCleanup* cleanupStack = CTrapCleanup::New();
       
   597     if ( !cleanupStack )
       
   598         {
       
   599         error = KErrNoMemory;
       
   600         }
       
   601     else
       
   602         {
       
   603         // Carry out operation in this thread, but via an active scheduler
       
   604         TRAP( error, CntMatchThreadFunctionL( aRequestData ) );
       
   605         delete cleanupStack;
       
   606         }
       
   607 
       
   608     // Rendezvous with MsvServer thread to report completion
       
   609     RThread::Rendezvous( error );
       
   610     SMUMLOGGER_LEAVEFN("CSmsDetailsPlugin::CntMatchThreadFunction");
       
   611 
       
   612     return error;
       
   613     }
       
   614 
       
   615 
       
   616 void CSmsDetailsPlugin::CntMatchThreadFunctionL( TAny* aRequestData )
       
   617     {
       
   618     SMUMLOGGER_ENTERFN("CSmsDetailsPlugin::CntMatchThreadFunctionL");
       
   619     TCntMatchRequestData* requestData = reinterpret_cast< TCntMatchRequestData* >( aRequestData );
       
   620 
       
   621     CActiveScheduler* scheduler = new(ELeave) CActiveScheduler();
       
   622     CleanupStack::PushL( scheduler );
       
   623     CActiveScheduler::Install( scheduler );
       
   624 
       
   625     // Create one-shot object to do the match operation
       
   626     CSmsDetailsPluginOneShotOperation* operation = new(ELeave) CSmsDetailsPluginOneShotOperation( *requestData );
       
   627     CleanupStack::PushL( operation );
       
   628     
       
   629     // Now start the scheduler to carry out the op
       
   630     CActiveScheduler::Start();
       
   631 
       
   632     // Control returns here after the operation is complete. Propagate error codes to
       
   633     // thread function.
       
   634     User::LeaveIfError( operation->CompletionCode() );
       
   635     
       
   636     CleanupStack::PopAndDestroy( 2, scheduler ); // operation, scheduler
       
   637     SMUMLOGGER_LEAVEFN("CSmsDetailsPlugin::CntMatchThreadFunctionL");
       
   638     }
       
   639 
       
   640 
       
   641 
       
   642 
       
   643 
       
   644 CSmsDetailsPluginOneShotOperation::CSmsDetailsPluginOneShotOperation( TCntMatchRequestData& aRequestData )
       
   645 : CActive( EPriorityNormal ), iRequestData( aRequestData )
       
   646     {
       
   647     SMUMLOGGER_ENTERFN("CSmsDetailsPluginOneShotOperation::CSmsDetailsPluginOneShotOperation");
       
   648     CActiveScheduler::Add( this );
       
   649     //
       
   650     TRequestStatus* status = &iStatus;
       
   651     User::RequestComplete( status, KErrNone );
       
   652     SetActive();
       
   653     SMUMLOGGER_LEAVEFN("CSmsDetailsPluginOneShotOperation::CSmsDetailsPluginOneShotOperation");
       
   654     }
       
   655 
       
   656 
       
   657 CSmsDetailsPluginOneShotOperation::~CSmsDetailsPluginOneShotOperation()
       
   658     {
       
   659     SMUMLOGGER_ENTERFN("CSmsDetailsPluginOneShotOperation::~CSmsDetailsPluginOneShotOperation");
       
   660     if( iContactMatcher )
       
   661         delete iContactMatcher;
       
   662     Cancel();
       
   663     SMUMLOGGER_LEAVEFN("CSmsDetailsPluginOneShotOperation::~CSmsDetailsPluginOneShotOperation");
       
   664     }
       
   665 
       
   666 
       
   667 void CSmsDetailsPluginOneShotOperation::RunL()
       
   668     {
       
   669     SMUMLOGGER_ENTERFN("CSmsDetailsPluginOneShotOperation::RunL");
       
   670     TRAPD( err, MatchContactL() );
       
   671 
       
   672     // Preserver error code so that the thread function can report it to the main MsvServer thread.
       
   673     iStatus = err;
       
   674 
       
   675     // Stop scheduler which will return control to the thread function
       
   676     CActiveScheduler::Stop();
       
   677     SMUMLOGGER_LEAVEFN("CSmsDetailsPluginOneShotOperation::RunL");
       
   678     }
       
   679 
       
   680 
       
   681 void CSmsDetailsPluginOneShotOperation::DoCancel()
       
   682     {
       
   683     // Nothing to do here - we already completed our request in the ctor
       
   684     }
       
   685 
       
   686 
       
   687 void CSmsDetailsPluginOneShotOperation::MatchContactL()
       
   688     {
       
   689     SMUMLOGGER_ENTERFN("CSmsDetailsPluginOneShotOperation::MatchContactL");
       
   690     RFs fsSession;
       
   691     User::LeaveIfError( fsSession.Connect() );
       
   692     CleanupClosePushL( fsSession );
       
   693 
       
   694     if( !iContactMatcher )
       
   695         {
       
   696         iContactMatcher = CContactMatcher::NewL( &fsSession );
       
   697         iContactMatcher->OpenAllStoresL();
       
   698         }
       
   699  
       
   700     CVPbkContactLinkArray* linkArray = CVPbkContactLinkArray::NewLC();
       
   701     
       
   702     iContactMatcher->MatchPhoneNumberL(
       
   703         iRequestData.iFromAddress,
       
   704         iRequestData.iMatchDigitCount,
       
   705         CVPbkPhoneNumberMatchStrategy::EVPbkMatchFlagsNone,
       
   706         *linkArray );
       
   707     
       
   708     TInt nameIndex = 0; //correct index if only one match is found
       
   709     if( linkArray->Count() == 0 )
       
   710         {
       
   711         SMUMLOGGER_WRITE("No match found");
       
   712         User::Leave( KErrNotFound );        
       
   713         }
       
   714     else if( linkArray->Count() > 1 )
       
   715         {
       
   716         //Multiple matches found. Get the current store single match index if any.
       
   717         nameIndex = GetCurrentStoreIndexL( *linkArray );
       
   718         if( nameIndex == KErrMultipleMatchFound )
       
   719             {
       
   720             /* No unique match in current store, Hence show the name only if all the matches have 
       
   721              * identical names
       
   722              */
       
   723             if( ShowContactNameL( linkArray, nameIndex) == EFalse)
       
   724                 {
       
   725                 SMUMLOGGER_WRITE("No (Perfect) match found");
       
   726                 User::Leave( KErrMultipleMatchFound );
       
   727                 }
       
   728             }
       
   729         }
       
   730 
       
   731     // There should be only one match or multiple identical matches in this case.
       
   732     // Use the same and read contact from the store.
       
   733 
       
   734     HBufC* alias = GetContactNameL( linkArray->At(nameIndex) );
       
   735     if ( alias )
       
   736         {
       
   737         iRequestData.iOutput->Copy( alias->Left( iRequestData.iMaxLength ) );
       
   738         delete alias;
       
   739         alias = NULL;        
       
   740         }
       
   741 
       
   742     CleanupStack::PopAndDestroy( 2, &fsSession ); // linkArray, fsSession
       
   743     SMUMLOGGER_LEAVEFN("CSmsDetailsPluginOneShotOperation::MatchContactL");
       
   744     }
       
   745 
       
   746 
       
   747 // -----------------------------------------------------------------------------
       
   748 // CSmsDetailsPluginOneShotOperation::GetContactNameL
       
   749 // -----------------------------------------------------------------------------
       
   750 //
       
   751 HBufC* CSmsDetailsPluginOneShotOperation::GetContactNameL(const MVPbkContactLink& aContactLink )
       
   752     {
       
   753     //SMUMLOGGER_ENTERFN("CSmsDetailsPluginOneShotOperation::GetContactNameL");
       
   754     MVPbkStoreContact* tempContact;
       
   755     iContactMatcher->GetStoreContactL(aContactLink, &tempContact);
       
   756     tempContact->PushL();
       
   757     
       
   758     MVPbkStoreContactFieldCollection& coll = tempContact->Fields();
       
   759     HBufC* nameBuff = iContactMatcher->GetNameL( coll );
       
   760     
       
   761     CleanupStack::PopAndDestroy(tempContact); // tempContact
       
   762     //SMUMLOGGER_LEAVEFN("CSmsDetailsPluginOneShotOperation::GetContactNameL");
       
   763     return nameBuff;
       
   764     }
       
   765 
       
   766 // -----------------------------------------------------------------------------
       
   767 // CSmsDetailsPluginOneShotOperation::GetContactNameInLowerCaseL
       
   768 // -----------------------------------------------------------------------------
       
   769 //
       
   770 HBufC* CSmsDetailsPluginOneShotOperation::GetContactNameInLowerCaseL(const MVPbkContactLink& aContactLink )
       
   771     {
       
   772     //SMUMLOGGER_ENTERFN("CSmsDetailsPluginOneShotOperation::GetContactNameInLowerCaseL");
       
   773     //get the name 
       
   774     HBufC* nameBuff =  GetContactNameL(aContactLink);
       
   775     CleanupStack::PushL( nameBuff );
       
   776     
       
   777     //SMUMLOGGER_WRITE_FORMAT( "length: %d", nameBuff->Length() );
       
   778     //SMUMLOGGER_WRITE_FORMAT( "size: %d", nameBuff->Size() );
       
   779     
       
   780     //Convert to lower case , since this name buffer is used to compare names.    
       
   781     HBufC* nameInLowerCase = HBufC::NewL( nameBuff->Length() + 2 );
       
   782     nameInLowerCase->Des().CopyLC( *nameBuff );
       
   783     
       
   784     CleanupStack::PopAndDestroy( nameBuff ); // nameBuff
       
   785     //SMUMLOGGER_LEAVEFN("CSmsDetailsPluginOneShotOperation::GetContactNameInLowerCaseL");
       
   786     return nameInLowerCase;
       
   787     }
       
   788 
       
   789 // -----------------------------------------------------------------------------
       
   790 // CSmsDetailsPluginOneShotOperation::ShowContactNameL
       
   791 // -----------------------------------------------------------------------------
       
   792 //
       
   793 TBool CSmsDetailsPluginOneShotOperation::ShowContactNameL(CVPbkContactLinkArray* aLinkArray, TInt &nameIndex)
       
   794     {
       
   795     SMUMLOGGER_ENTERFN("CSmsDetailsPluginOneShotOperation::ShowContactName");
       
   796     /* TODO:: see the NOTE: below
       
   797      * compare the names upto standard
       
   798      * 1. if all the names are same - display the name 
       
   799      *    eg: "abcdef xyz" && "abcdef xyz"
       
   800      * 2. find min name legth among all,
       
   801      *    if this length is > standard length and matches upto standard length - display the larger name.
       
   802      *    eg: abcdef xyz123,  abcdef xyz12, abcdef xyz and std length is 10,
       
   803      *        since match upto 10 chars is fine, display abcdef xyz123
       
   804      * 3. in any other case do not show name
       
   805      *    eg: abcdef xyz , abcde xyz
       
   806      *        abcdef xyz , abcdef xy
       
   807      *        abcdef xyz , abcde
       
   808      */
       
   809     TInt i, minLength = 999, maxLength = 0, length = 0, maxLengthIndex = 0, stdLength = 14;
       
   810     TBool retVal = ETrue ;
       
   811     SMUMLOGGER_WRITE( "Contact Match statistics to follow..." );
       
   812     SMUMLOGGER_WRITE_FORMAT( "CSmsDetailsPluginOneShotOperation::MatchContactL Match count: %d", aLinkArray->Count() );
       
   813     
       
   814     for( i = 0 ; i < aLinkArray->Count(); i++ )
       
   815         {
       
   816         HBufC* alias = GetContactNameL( aLinkArray->At(i) );
       
   817         SMUMLOGGER_WRITE_FORMAT( ":-> %s", alias->Des().PtrZ() );
       
   818         length = alias->Des().Length();
       
   819         if(minLength > length)
       
   820             {
       
   821             minLength = length;
       
   822             }
       
   823         if(maxLength < length)
       
   824             {
       
   825             maxLength = length;
       
   826             maxLengthIndex = i;
       
   827             }
       
   828         delete alias;
       
   829         alias = NULL;
       
   830         }
       
   831     
       
   832     SMUMLOGGER_WRITE_FORMAT( "Cotact Lengths: Std Length  : %d", stdLength);
       
   833     SMUMLOGGER_WRITE_FORMAT( "                MinLength   : %d", minLength);
       
   834     SMUMLOGGER_WRITE_FORMAT( "                MaxLength   : %d", maxLength); 
       
   835     SMUMLOGGER_WRITE_FORMAT( "                MaxLen index: %d", maxLengthIndex);
       
   836     
       
   837     if(minLength != maxLength)
       
   838         {
       
   839         //complete length match not possible
       
   840         retVal = EFalse;
       
   841         
       
   842         /* NOTE:
       
   843          * Uncomment below code if partial length(upto stdLength) match is sufficient, 
       
   844          * ensure stdLength is correct
       
   845          */
       
   846         /*
       
   847         if(minLength < stdLength)
       
   848             {
       
   849             SMUMLOGGER_WRITE( "minLength < stdLength" );
       
   850             retVal = EFalse;
       
   851             }
       
   852         */
       
   853         }
       
   854     
       
   855     if( retVal )
       
   856         {
       
   857         TInt ret;
       
   858         HBufC* longestName = GetContactNameInLowerCaseL( aLinkArray->At(maxLengthIndex) );        
       
   859         SMUMLOGGER_WRITE_FORMAT( "Longest name:-> %s", longestName->Des().PtrZ() );
       
   860         for ( i = 0; i < aLinkArray->Count() && retVal; i++ )
       
   861             {
       
   862             HBufC* nameI = GetContactNameInLowerCaseL( aLinkArray->At(i) );
       
   863             SMUMLOGGER_WRITE_FORMAT( "compared with -> %s", nameI->Des().PtrZ() );
       
   864             ret = longestName->Find(nameI->Des());
       
   865             if(ret == KErrNotFound || ret != 0)
       
   866                 {
       
   867                 SMUMLOGGER_WRITE_FORMAT( "Part/Full Match error/offset: %d", ret );
       
   868                 retVal = EFalse;
       
   869                 }
       
   870             delete nameI;
       
   871             nameI = NULL;
       
   872            }
       
   873         delete longestName;
       
   874         longestName = NULL;
       
   875         }
       
   876 
       
   877     //If no match OR more than one match, then to avoid ambiguity, display the number
       
   878     SMUMLOGGER_WRITE_FORMAT( "Final Match result : %d", retVal );
       
   879     SMUMLOGGER_WRITE_FORMAT( "Final Match index  : %d", maxLengthIndex );
       
   880     SMUMLOGGER_WRITE( "Contact Match statistics End here..." );
       
   881 
       
   882     SMUMLOGGER_LEAVEFN("CSmsDetailsPluginOneShotOperation::ShowContactName");
       
   883     nameIndex = maxLengthIndex;
       
   884     return retVal;
       
   885     }
       
   886 
       
   887 // -----------------------------------------------------------------------------
       
   888 // CSmsDetailsPluginOneShotOperation::GetCurrentStoreIndexL
       
   889 // -----------------------------------------------------------------------------
       
   890 //
       
   891 TInt CSmsDetailsPluginOneShotOperation::GetCurrentStoreIndexL( CVPbkContactLinkArray& aLinkArray )
       
   892     {
       
   893     TInt curStoreIndex( KErrMultipleMatchFound );
       
   894     TInt curStoreMatchCount = 0;
       
   895     RArray<TInt> otherStoreMatchIndices;
       
   896     CleanupClosePushL( otherStoreMatchIndices );
       
   897     
       
   898     //Get the current configured contact store array(s)
       
   899     CPbk2StoreConfiguration* storeConfiguration = CPbk2StoreConfiguration::NewL();
       
   900     CleanupStack::PushL( storeConfiguration );
       
   901     CVPbkContactStoreUriArray* currStoreArray = storeConfiguration->CurrentConfigurationL();
       
   902     CleanupStack::PopAndDestroy(storeConfiguration);
       
   903 
       
   904     if ( currStoreArray )
       
   905         {
       
   906         /* Contact's store is compared against user selected stores.
       
   907          * If contact is from such store, found index is incremented
       
   908          * else, other store contact indices are populated into array for further use
       
   909          */
       
   910         for ( TInt i = 0; i < aLinkArray.Count(); i++ )
       
   911             {
       
   912             TVPbkContactStoreUriPtr uri = aLinkArray.At(i).ContactStore().StoreProperties().Uri();
       
   913             if ( currStoreArray->IsIncluded( uri ) )
       
   914                 {
       
   915                 // Set index to found contact and increment the count.
       
   916                 curStoreIndex = i;
       
   917                 curStoreMatchCount++;
       
   918                 }
       
   919             else
       
   920                 {
       
   921                 otherStoreMatchIndices.AppendL(i);
       
   922                 }
       
   923             }
       
   924         
       
   925         delete currStoreArray;    
       
   926         if ( curStoreMatchCount > 1)
       
   927             {
       
   928             /* Multiple matches found from current user selected store(s) 
       
   929              * Delete match from other stores in aLinkArray. New aLinkArray should only contain 
       
   930              * current store contact matches, so that next level pruning can be done(e.g, names can be 
       
   931              * compared and displayed if they are identical).
       
   932              */
       
   933             for(TInt i = otherStoreMatchIndices.Count() - 1; i >= 0; i--)
       
   934                 {
       
   935                 aLinkArray.Delete( otherStoreMatchIndices[i] );
       
   936                 }
       
   937             curStoreIndex = KErrMultipleMatchFound;
       
   938             }
       
   939         }
       
   940     CleanupStack::PopAndDestroy( &otherStoreMatchIndices );
       
   941     return curStoreIndex;
       
   942     }
       
   943 
       
   944 //  End of File