harvesterplugins/messaging/src/cmessagedatahandler.cpp
changeset 2 208a4ba3894c
parent 0 ccd0fd43f247
child 3 6832643895f7
equal deleted inserted replaced
0:ccd0fd43f247 2:208a4ba3894c
     1 /*
       
     2 * Copyright (c) 2010 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:  Harvester message plugin
       
    15  *
       
    16 */
       
    17 
       
    18 
       
    19 //  INCLUDES 
       
    20 
       
    21 #include <e32base.h>
       
    22 
       
    23 #include <mtclreg.h>
       
    24 #include <smsclnt.h> // SMS Headers
       
    25 #include <mmsclient.h> // MMS Headers
       
    26 #include <mmsvattachmentmanager.h>
       
    27 #include <impcmtm.h> // IMAP Headers
       
    28 #include <smtcmtm.h> // SMTP
       
    29 #include <popcmtm.h> // POP
       
    30 
       
    31 #include "harvesterserverlogger.h"
       
    32 #include "cmessagedatahandler.h"
       
    33 #include "cmessageplugin.h"
       
    34 #include <csearchdocument.h>
       
    35 #include <common.h>
       
    36 
       
    37 #include <ccpixindexer.h>
       
    38 
       
    39 /** Number of symbols from MsgBody taken to excerpt */
       
    40 const TInt KMsgBodyExcerptSymbols = 90;
       
    41 
       
    42 // For Ucs2 detection
       
    43 const TInt KUtf8BomLength = 3;
       
    44 const TUint8 KUtf8Bom[KUtf8BomLength] = {0xEF, 0xBB, 0xBF};
       
    45 
       
    46 // CSearchDocument ID max length
       
    47 const TUint KMaxDocId = 20;
       
    48 // Hardcoded limit for the body size to index (and store)
       
    49 const TInt KMaxDocumentSize = 1024;
       
    50 
       
    51 _LIT8(KMimeTypeText, "text/plain" );
       
    52 
       
    53 _LIT(KMimeTypeField, CPIX_MIMETYPE_FIELD);
       
    54 _LIT(KMimeTypeMessaging, MESSAGING_MIMETYPE);
       
    55 
       
    56 /** Field names */
       
    57 _LIT(KToField, TO_FIELD);
       
    58 _LIT(KCcField, CC_FIELD);
       
    59 _LIT(KBccField, BCC_FIELD);
       
    60 _LIT(KFromField, FROM_FIELD);
       
    61 _LIT(KFolderField, FOLDER_FIELD);
       
    62 _LIT(KBodyField, BODY_FIELD);
       
    63 _LIT(KSubjectField, SUBJECT_FIELD);
       
    64 
       
    65 // ============================ MEMBER FUNCTIONS ===============================
       
    66 
       
    67 // ---------------------------------------------------------------------------
       
    68 // CMessageDataHandler::NewL
       
    69 // ---------------------------------------------------------------------------
       
    70 //
       
    71 CMessageDataHandler* CMessageDataHandler::NewL(CMessagePlugin& aMessagePlugin,
       
    72 		CMsvSession& aSession)
       
    73 	{
       
    74 		CPIXLOGSTRING( "CMessageDataHandler::NewL() - enter" );
       
    75 
       
    76 	CMessageDataHandler* self = new (ELeave) CMessageDataHandler(
       
    77 			aMessagePlugin, aSession);
       
    78 	CleanupStack::PushL(self);
       
    79 	self->ConstructL();
       
    80 	CleanupStack::Pop(self);
       
    81 
       
    82 		CPIXLOGSTRING( "CMessageDataHandler::NewL() - return" );
       
    83 	return self;
       
    84 	}
       
    85 
       
    86 // ---------------------------------------------------------------------------
       
    87 // CMessageDataHandler::~CMessageDataHandler
       
    88 // ---------------------------------------------------------------------------
       
    89 //
       
    90 CMessageDataHandler::~CMessageDataHandler()
       
    91 	{
       
    92 	Cancel();
       
    93 	iFs.Close();
       
    94 	delete iMmsMtm;
       
    95 	delete iSmsMtm;
       
    96 	delete iSmtpMtm;
       
    97 	delete iPop3Mtm;
       
    98 	delete iImap4Mtm;
       
    99 	delete iMtmReg;
       
   100 	}
       
   101 
       
   102 // ---------------------------------------------------------------------------
       
   103 // CMessageDataHandler::CMessageDataHandler
       
   104 // ---------------------------------------------------------------------------
       
   105 //
       
   106 CMessageDataHandler::CMessageDataHandler(CMessagePlugin& aMessagePlugin, CMsvSession& aSession)
       
   107 	: CActive(EPriorityLow), iMessagePlugin(aMessagePlugin), iMsvSession(aSession)
       
   108 	{
       
   109 	CActiveScheduler::Add(this);
       
   110 	}
       
   111 
       
   112 // ---------------------------------------------------------------------------
       
   113 // CMessageDataHandler::ConstructL
       
   114 // ---------------------------------------------------------------------------
       
   115 //
       
   116 void CMessageDataHandler::ConstructL()
       
   117 	{
       
   118 	// TODO iFs only used in MMS attachment logic, 
       
   119 	// from a performance perspective, is it worthwhile connecting here?
       
   120 	User::LeaveIfError(iFs.Connect());
       
   121 	iMtmReg = CClientMtmRegistry::NewL(iMsvSession);
       
   122 	TRAPD(err,iSmsMtm = static_cast<CSmsClientMtm*> (iMtmReg->NewMtmL(KUidMsgTypeSMS)));
       
   123 	CPIXLOGSTRING2( "CMessageDataHandler::ConstructL() iSmsMtm err = %d",err);
       
   124 	TRAP(err,iMmsMtm = static_cast<CMmsClientMtm*> (iMtmReg->NewMtmL(KUidMsgTypeMultimedia)));
       
   125 	CPIXLOGSTRING2( "CMessageDataHandler::ConstructL() iMmsMtm err = %d",err);
       
   126 	/*
       
   127 	TRAP(err,iSmtpMtm = static_cast<CSmtpClientMtm*> (iMtmReg->NewMtmL(KUidMsgTypeSMTP)));
       
   128 	CPIXLOGSTRING2( "CMessageDataHandler::ConstructL() iSmtpMtm err = %d",err);
       
   129 	TRAP(err, iPop3Mtm = static_cast<CPop3ClientMtm*> (iMtmReg->NewMtmL(KUidMsgTypePOP3)));
       
   130 	CPIXLOGSTRING2( "CMessageDataHandler::ConstructL() iPop3Mtm err = %d",err);
       
   131 	TRAP(err,iImap4Mtm = static_cast<CImap4ClientMtm*> (iMtmReg->NewMtmL(KUidMsgTypeIMAP4)));
       
   132 	CPIXLOGSTRING2( "CMessageDataHandler::ConstructL() iImap4Mtm err = %d",err);
       
   133 	*/
       
   134 	}
       
   135 
       
   136 // ---------------------------------------------------------------------------
       
   137 // CMessageDataHandler::GatherData
       
   138 // ---------------------------------------------------------------------------
       
   139 //
       
   140 void CMessageDataHandler::GatherDataL(TMsvId& aMessageId,
       
   141 		TCPixActionType aActionType, TMsvId& aFolderId)
       
   142 	{
       
   143 	TMessageItem item(aMessageId, aActionType, aFolderId);
       
   144 	iMessageArray.AppendL(item);
       
   145 	HandleNextRequest();
       
   146 	}
       
   147 
       
   148 // ---------------------------------------------------------------------------
       
   149 // CMessageDataHandler::IsValidMessageTypeL
       
   150 // ---------------------------------------------------------------------------
       
   151 //	    
       
   152 TInt CMessageDataHandler::IsValidMessageType(TMsvId aIdToCheck,
       
   153 		TMsgType& aMessageType)
       
   154 	{
       
   155 		CPIXLOGSTRING("ENTER CMessageDataHandler::IsValidMessageType");
       
   156 	TMsvEntry entry;
       
   157 	TMsvId service = 0;
       
   158 	TInt err = iMsvSession.GetEntry(aIdToCheck, service, entry);
       
   159 		CPIXLOGSTRING2("CMessageDataHandler::IsValidMessageType GetEntry: %d", err);
       
   160 	if (!err)
       
   161 		{
       
   162 		aMessageType = iMessagePlugin.CalculateMessageType(entry);
       
   163 			CPIXLOGSTRING2("CMessageDataHandler::IsValidMessageType type: %d", aMessageType );
       
   164 		}
       
   165 		CPIXLOGSTRING("END CMessageDataHandler::IsValidMessageType");
       
   166 	return err;
       
   167 	}
       
   168 
       
   169 // ---------------------------------------------------------------------------
       
   170 // CMessageDataHandler::CreateSmsIndexItemLC
       
   171 // ---------------------------------------------------------------------------
       
   172 //	    
       
   173 void CMessageDataHandler::CreateMessageIndexItemL(const TMsvId& aMsvId,
       
   174 		TCPixActionType aActionType, const TMsvId& aFolderId)
       
   175 	{
       
   176 	CPIXLOGSTRING2("CMessageDataHandler::CreateMessageIndexItemL(): aMsvId = %d ", aMsvId );
       
   177 
       
   178 	// Index an empty item if removal action
       
   179 	if (aActionType == ECPixRemoveAction)
       
   180 		{
       
   181 		TBuf<20> docid_str;
       
   182 		docid_str.AppendNum(aMsvId);
       
   183 		if (iMessagePlugin.GetIndexer())
       
   184 			{
       
   185 			TRAPD(err, iMessagePlugin.GetIndexer()->DeleteL(docid_str));
       
   186 			if (err == KErrNone)
       
   187 				{
       
   188 				CPIXLOGSTRING("CMessageDataHandler::CreateMessageIndexItemL(): Document deleted.");
       
   189 				}
       
   190 			else
       
   191 				{
       
   192 				CPIXLOGSTRING2("CMessageDataHandler::CreateMessageIndexItemL(): Error %d in deleting the document.", err);				
       
   193 				}
       
   194 			}
       
   195 		return;
       
   196 		}
       
   197 
       
   198 	// Check message type
       
   199 	TMsgType messageType = EMsgTypeInvalid; // initialisation
       
   200 	TInt error = IsValidMessageType(aMsvId, messageType);
       
   201 
       
   202 	// creating CSearchDocument object with unique ID for this application
       
   203 	CSearchDocument* index_item = NULL;
       
   204 
       
   205 	switch (messageType)
       
   206 		{
       
   207 		case EMsgTypeSms:
       
   208 			{
       
   209 			TRAPD(err, index_item = CreateSmsDocumentL(aMsvId, aFolderId));
       
   210 			if (err == KErrNone)
       
   211 				{
       
   212 				CPIXLOGSTRING("CMessageDataHandler::CreateMessageIndexItemL(): SMS document created.");
       
   213 				}
       
   214 			else
       
   215 				{
       
   216 				CPIXLOGSTRING2("CMessageDataHandler::CreateMessageIndexItemL(): Error %d in creating SMS document.", err);
       
   217 				}
       
   218 			break;
       
   219 			}
       
   220 		case EMsgTypeMms:
       
   221 			{
       
   222 			TRAPD(err, index_item = CreateMmsDocumentL(aMsvId, aFolderId));
       
   223 			if (err == KErrNone)
       
   224 				{
       
   225 				CPIXLOGSTRING("CMessageDataHandler::CreateMessageIndexItemL(): MMS document created.");
       
   226 				}
       
   227 			else
       
   228 				{
       
   229 				CPIXLOGSTRING2("CMessageDataHandler::CreateMessageIndexItemL(): Error %d in creating MMS document.", err);
       
   230 				}
       
   231 			break;
       
   232 			}
       
   233 		case EMsgTypeEmailPop3:
       
   234 		case EMsgTypeEmailImap4:
       
   235 		case EMsgTypeEmailSmtp:
       
   236 			{
       
   237 			TRAPD(err, index_item = CreateEmailDocumentL(aMsvId, aFolderId));
       
   238 			if (err == KErrNone)
       
   239 				{
       
   240 				CPIXLOGSTRING("CMessageDataHandler::CreateMessageIndexItemL(): E-mail document created.");
       
   241 				}
       
   242 			else
       
   243 				{
       
   244 				CPIXLOGSTRING2("CMessageDataHandler::CreateMessageIndexItemL(): Error %d in creating e-mail document.", err);
       
   245 				}
       
   246 			break;
       
   247 			}
       
   248 		case EMsgTypeInvalid:
       
   249 		// For EMsgTypeDraft there is no way to tell if it was a SMS, MMS or email,
       
   250 		// so don't create index_item.
       
   251 		case EMsgTypeDraft:
       
   252 		default:
       
   253 			// Error occurred
       
   254 			break;
       
   255 		}
       
   256 
       
   257 	// Exit if wrong message type
       
   258 	if (index_item == NULL)
       
   259 		{
       
   260 		CPIXLOGSTRING("CMessageDataHandler::CreateMessageIndexItemL(): Document was not created.");
       
   261 		return;
       
   262 		}
       
   263 	CleanupStack::PushL(index_item);
       
   264 		
       
   265 	// Folder field
       
   266 	TMsvEntry entry;
       
   267 	TMsvId service = 0;
       
   268 	iMsvSession.GetEntry(aFolderId, service, entry);
       
   269 	HBufC *folder_str = entry.iDetails.AllocLC();
       
   270 	index_item->AddFieldL(KFolderField, *folder_str, CDocumentField::EStoreYes | CDocumentField::EIndexNo);
       
   271 
       
   272 	// Mime type field
       
   273 	index_item->AddFieldL(KMimeTypeField, KMimeTypeMessaging, CDocumentField::EStoreYes | CDocumentField::EIndexUnTokenized);		
       
   274 	
       
   275 		// Send for indexing
       
   276 	if (iMessagePlugin.GetIndexer())
       
   277 		{
       
   278 		if (aActionType == ECPixAddAction)
       
   279 			{
       
   280 			TRAPD(err, iMessagePlugin.GetIndexer()->AddL(*index_item));
       
   281 			if (err == KErrNone)
       
   282 				{
       
   283 				CPIXLOGSTRING("CMessageDataHandler::CreateMessageIndexItemL(): Added.");
       
   284 				}
       
   285 			else
       
   286 				{
       
   287 				CPIXLOGSTRING2("CMessageDataHandler::CreateMessageIndexItemL(): Error %d in adding.", err);
       
   288 				}
       
   289 			}
       
   290 		else if (aActionType == ECPixUpdateAction)
       
   291 			{
       
   292 			TRAPD(err, iMessagePlugin.GetIndexer()->UpdateL(*index_item));
       
   293 			if (err == KErrNone)
       
   294 				{
       
   295 				CPIXLOGSTRING("CMessageDataHandler::CreateMessageIndexItemL(): Updated.");
       
   296 				}
       
   297 			else
       
   298 				{
       
   299 				CPIXLOGSTRING2("CMessageDataHandler::CreateMessageIndexItemL(): Error %d in updating.", err);
       
   300 				}
       
   301 			}
       
   302 		}
       
   303 	else
       
   304 		{
       
   305 		CPIXLOGSTRING("END CMessageDataHandler::CreateMessageIndexItemL(): No indexer present.");
       
   306 		}
       
   307 		
       
   308 	CleanupStack::PopAndDestroy(folder_str);
       
   309 	CleanupStack::PopAndDestroy(index_item);
       
   310 	}
       
   311 
       
   312 // ---------------------------------------------------------------------------
       
   313 // CMessageDataHandler::CreateSmsDocumentL
       
   314 // ---------------------------------------------------------------------------
       
   315 //
       
   316 CSearchDocument* CMessageDataHandler::CreateSmsDocumentL(const TMsvId& aMsvId, const TMsvId& aFolderId)
       
   317 	{
       
   318 	// Select mtm for this type
       
   319 	iSmsMtm->SwitchCurrentEntryL(aMsvId);
       
   320 	iSmsMtm->LoadMessageL();
       
   321 
       
   322 	// creating CSearchDocument object with unique ID for this application
       
   323 	TBuf<KMaxDocId> docid_str;
       
   324 	docid_str.AppendNum(aMsvId);
       
   325 	CSearchDocument* index_item = CSearchDocument::NewLC(docid_str, _L(SMSAPPCLASS));
       
   326 
       
   327 	// Add from field use the name instead of number if in the contacts db.
       
   328 	// (iSmsMtm->SmsHeader().FromAddress() - only returns the number)
       
   329 	TMsvEntry entry;
       
   330 	TMsvId service = 0;
       
   331 	iMsvSession.GetEntry(aMsvId, service, entry);
       
   332 	HBufC *fromNameOrNumberBuf = entry.iDetails.AllocLC();
       
   333 	index_item->AddFieldL(KFromField, *fromNameOrNumberBuf);
       
   334 
       
   335 	// Add the recipients as content items
       
   336 	TBuf<64> to_field;
       
   337 	const CDesCArray
       
   338 			& recipientArray =
       
   339 					static_cast<const CDesCArray&> (iSmsMtm->AddresseeList().RecipientList());
       
   340 	for (TInt i = 0; i < recipientArray.MdcaCount(); i++)
       
   341 		{
       
   342 		to_field = KToField;
       
   343 		if (i>0)
       
   344 			to_field.AppendNum(i);
       
   345 		index_item->AddFieldL(to_field, recipientArray.MdcaPoint(i));
       
   346 		}
       
   347 
       
   348 	// Add the body text as a content item
       
   349 	TInt msgLength = iSmsMtm->Body().DocumentLength();
       
   350 	HBufC* bodyText = HBufC::NewLC(msgLength);
       
   351 	TPtr body_ptr = bodyText->Des();
       
   352 	iSmsMtm->Body().Extract(body_ptr);
       
   353 	index_item->AddFieldL(KBodyField, *bodyText);
       
   354 	
       
   355 	// Add excerpt
       
   356 	// Note SMS does not have a subject field.
       
   357 	HBufC* excerpt = CreateExcerptLC(*fromNameOrNumberBuf, recipientArray, KNullDesC(), body_ptr, aFolderId);
       
   358 	index_item->AddExcerptL(*excerpt);
       
   359 	CleanupStack::PopAndDestroy(excerpt);	
       
   360 	CleanupStack::PopAndDestroy(bodyText);
       
   361 
       
   362 	CleanupStack::PopAndDestroy(fromNameOrNumberBuf);
       
   363 
       
   364 	// Pop the item
       
   365 	CleanupStack::Pop(index_item);
       
   366 	return index_item;
       
   367 	}
       
   368 
       
   369 // ---------------------------------------------------------------------------
       
   370 // CMessageDataHandler::CreateMmsDocumentL
       
   371 // ---------------------------------------------------------------------------
       
   372 //
       
   373 CSearchDocument* CMessageDataHandler::CreateMmsDocumentL(const TMsvId& aMsvId, const TMsvId& aFolderId)
       
   374 	{
       
   375 	// Select mtm for this type
       
   376  	iMmsMtm->SwitchCurrentEntryL(aMsvId);
       
   377 	iMmsMtm->LoadMessageL();
       
   378 
       
   379 	// creating CSearchDocument object with unique ID for this application
       
   380 	TBuf<KMaxDocId> docid_str;
       
   381 	docid_str.AppendNum(aMsvId);
       
   382 	CSearchDocument* index_item = CSearchDocument::NewLC(docid_str, _L(MMSAPPCLASS));
       
   383 	
       
   384 	// Add from field
       
   385 	index_item->AddFieldL(KFromField, iMmsMtm->Sender());
       
   386 
       
   387 	// Add the recipients as content items
       
   388 	TBuf<64> to_field;
       
   389 	const CDesCArray
       
   390 			& recipientArray =
       
   391 					static_cast<const CDesCArray&> (iMmsMtm->AddresseeList().RecipientList());
       
   392 	for (TInt i = 0; i < recipientArray.MdcaCount(); i++)
       
   393 		{
       
   394 		to_field = KToField;
       
   395 		if (i>0)
       
   396 			to_field.AppendNum(i);
       
   397 		index_item->AddFieldL(to_field, recipientArray.MdcaPoint(i));
       
   398 		}
       
   399 
       
   400 	// Add subject
       
   401 	TPtrC subject(iMmsMtm->SubjectL());
       
   402 	index_item->AddFieldL(KSubjectField, subject);
       
   403 
       
   404 	// Add the body parts as a content items
       
   405     // See if the MMS contains a text file attachment
       
   406     TBool excerptFieldAdded(EFalse);
       
   407     TInt bodycount = 0;
       
   408     CMsvStore* msvStore = iMmsMtm->Entry().ReadStoreL();
       
   409 	CleanupStack::PushL( msvStore );
       
   410 	MMsvAttachmentManager& attManager = msvStore->AttachmentManagerL();
       
   411 	for ( TInt i = 0; i < attManager.AttachmentCount(); i++ )
       
   412 	    {
       
   413 		CMsvAttachment* attInfo = attManager.GetAttachmentInfoL(i);
       
   414 		CleanupStack::PushL( attInfo );
       
   415 		
       
   416         if (attInfo->MimeType() == KMimeTypeText())
       
   417             {
       
   418             // Mime type
       
   419             RFile attFile = attManager.GetAttachmentFileL(i);
       
   420             CleanupClosePushL( attFile );
       
   421             TInt charsetMIB = TextFileCharsetL(iFs, attFile);
       
   422             
       
   423             // Get the file size
       
   424             TInt fileSize = 0;
       
   425             User::LeaveIfError(attFile.Size(fileSize));
       
   426             
       
   427             // Read the file
       
   428             HBufC8* textSource = HBufC8::NewLC(fileSize);
       
   429             TPtr8 ptr8 = textSource->Des();
       
   430             attFile.Read(ptr8);
       
   431   
       
   432   			// Convert character set
       
   433             HBufC* text = HBufC::NewLC( fileSize );
       
   434             TPtr buf = text->Des();
       
   435             if ( KMmsIso10646Ucs2 != charsetMIB )
       
   436                 {
       
   437                 if ( KMmsUsAscii == charsetMIB )
       
   438                     buf.Copy(*textSource);
       
   439                 else
       
   440                     ConvertToUcs2FromUtfL(iFs, buf, *textSource, charsetMIB);
       
   441                 }
       
   442             else
       
   443                 {
       
   444                 TPtrC ptr(reinterpret_cast<const TUint16*>(textSource->Des().Ptr()), 
       
   445                                   textSource->Length() / sizeof(TText));
       
   446         
       
   447                 // Ignore the first unicode charcter FFFE
       
   448                 ptr.Set( ptr.Mid( 1 ) );
       
   449                 buf = ptr;
       
   450                 }
       
   451 
       
   452         
       
   453             // Add the text of the file as a content item
       
   454             // MMS message body is in attachment
       
   455 			TBuf<64> body_field;
       
   456 			body_field = KBodyField;
       
   457 			if (bodycount>0)
       
   458 			{
       
   459 				// Add additional body fields
       
   460 				body_field.AppendNum(bodycount);
       
   461 			}
       
   462 			else
       
   463 			{
       
   464 				// Add excerpt for the first body field
       
   465 				HBufC* excerpt = CreateExcerptLC(iMmsMtm->Sender(), recipientArray, subject, *text, aFolderId);
       
   466 				index_item->AddExcerptL(*excerpt);
       
   467 				CleanupStack::PopAndDestroy(excerpt);
       
   468 				excerptFieldAdded  = ETrue;
       
   469 			}
       
   470 
       
   471             // TODO: add only few kilobytes of the body?
       
   472             index_item->AddFieldL(body_field, *text);
       
   473             ++bodycount;
       
   474 
       
   475             CleanupStack::PopAndDestroy( 3, &attFile ); // text, textSource, attFile
       
   476             }		
       
   477         else 
       
   478             {
       
   479             // add attachment name when binary file.
       
   480             if ( !excerptFieldAdded )
       
   481                 {
       
   482                 // attachment name might not be set
       
   483                 HBufC* excerpt = CreateExcerptLC(iMmsMtm->Sender(), recipientArray, subject, attInfo->AttachmentName(), aFolderId);
       
   484                 index_item->AddExcerptL(*excerpt);
       
   485                 CleanupStack::PopAndDestroy(excerpt);
       
   486                 excerptFieldAdded  = ETrue;
       
   487                 }
       
   488             }
       
   489 	    CleanupStack::PopAndDestroy( attInfo );		
       
   490 	    }
       
   491 
       
   492     // If no excerpt has been added yet, then add information have
       
   493     if ( !excerptFieldAdded )
       
   494         {
       
   495         HBufC* excerpt = CreateExcerptLC(iMmsMtm->Sender(), recipientArray, subject, KNullDesC(), aFolderId);
       
   496         index_item->AddExcerptL(*excerpt);
       
   497         CleanupStack::PopAndDestroy(excerpt);
       
   498         }
       
   499 
       
   500     // Cleanup
       
   501     CleanupStack::PopAndDestroy( msvStore );
       
   502 
       
   503     // Pop the item
       
   504     CleanupStack::Pop(index_item);
       
   505     return index_item;
       
   506     }
       
   507 
       
   508 // ---------------------------------------------------------------------------
       
   509 // CMessageDataHandler::CreateEmailDocumentL
       
   510 // ---------------------------------------------------------------------------
       
   511 //
       
   512 CSearchDocument* CMessageDataHandler::CreateEmailDocumentL(const TMsvId& aMsvId, const TMsvId& aFolderId)
       
   513 	{
       
   514 	// creating CSearchDocument object with unique ID for this application
       
   515 	TBuf<KMaxDocId> docid_str;
       
   516 	docid_str.AppendNum(aMsvId);
       
   517 	CSearchDocument* index_item = CSearchDocument::NewLC(docid_str, _L(EMAILAPPCLASS));
       
   518 
       
   519 	// Open the message entry
       
   520 	CMsvEntry* message_entry = CMsvEntry::NewL(iMsvSession, aMsvId, TMsvSelectionOrdering());
       
   521 	CleanupStack::PushL(message_entry);
       
   522 	
       
   523 	// Get body
       
   524 	CParaFormatLayer* paraFormatLayer = CParaFormatLayer::NewL();
       
   525 	CleanupStack::PushL(paraFormatLayer);
       
   526 	CCharFormatLayer* charFormatLayer = CCharFormatLayer::NewL();
       
   527 	CleanupStack::PushL(charFormatLayer);
       
   528 	CRichText* richtext = CRichText::NewL(paraFormatLayer, charFormatLayer);
       
   529 	CleanupStack::PushL(richtext);
       
   530 	CImEmailMessage* message_body = CImEmailMessage::NewLC(*message_entry);
       
   531 	message_body->GetBodyTextL(aMsvId, CImEmailMessage::EThisMessageOnly, *richtext, *paraFormatLayer, *charFormatLayer);
       
   532 	
       
   533 	// Read the message header
       
   534 	CMsvStore* message_store = message_entry->ReadStoreL();
       
   535 	CleanupStack::PushL(message_store);
       
   536 	CImHeader* header = CImHeader::NewLC();
       
   537 	header->RestoreL(*message_store);
       
   538 	
       
   539 	// Add from field
       
   540 	index_item->AddFieldL(KFromField, header->From());
       
   541 
       
   542 	// Add the ToRecipients as content items
       
   543 	TBuf<64> to_field;
       
   544 	for (TInt i = 0; i < header->ToRecipients().MdcaCount(); i++)
       
   545 		{
       
   546 		to_field = KToField;
       
   547 		if (i>0)
       
   548 			to_field.AppendNum(i);
       
   549 		index_item->AddFieldL(to_field, header->ToRecipients().MdcaPoint(i));
       
   550 		}
       
   551 
       
   552 	// Add the CcRecipients as content items
       
   553 	TBuf<64> cc_field;
       
   554 	for (TInt i = 0; i < header->CcRecipients().MdcaCount(); i++)
       
   555 		{
       
   556 		cc_field = KCcField;
       
   557 		if (i>0)
       
   558 			cc_field.AppendNum(i);
       
   559 		index_item->AddFieldL(cc_field, header->CcRecipients().MdcaPoint(i));
       
   560 		}
       
   561 
       
   562 	// Add the BccRecipients as content items
       
   563 	TBuf<64> bcc_field;
       
   564 	for (TInt i = 0; i < header->BccRecipients().MdcaCount(); i++)
       
   565 		{
       
   566 		bcc_field = KBccField;
       
   567 		if (i>0)
       
   568 			bcc_field.AppendNum(i);
       
   569 		index_item->AddFieldL(bcc_field, header->BccRecipients().MdcaPoint(i));
       
   570 		}
       
   571 
       
   572 	const TInt richTxtLen = (richtext->DocumentLength() < KMaxDocumentSize) ? richtext->DocumentLength() : KMaxDocumentSize;
       
   573 	HBufC* body_text = richtext->Read(0).Left(richTxtLen).AllocLC();
       
   574 
       
   575 	// Add subject
       
   576 	TPtrC subject(header->Subject());
       
   577 	index_item->AddFieldL(KSubjectField, subject);
       
   578 	
       
   579 	// Add message body
       
   580 	index_item->AddFieldL(KBodyField, *body_text);
       
   581 	
       
   582 	// Add excerpt
       
   583     HBufC* excerpt = CreateExcerptLC(header->From(), header->ToRecipients(), subject, *body_text, aFolderId);
       
   584     index_item->AddExcerptL(*excerpt);
       
   585 	CleanupStack::PopAndDestroy(excerpt);
       
   586 
       
   587 	// Cleanup everything last item message entry
       
   588 	CleanupStack::PopAndDestroy(8, message_entry);
       
   589 
       
   590 	// Pop the item
       
   591 	CleanupStack::Pop(index_item);
       
   592 	return index_item;	
       
   593 	}
       
   594 
       
   595 // ---------------------------------------------------------------------------
       
   596 // CMessageDataHandler::CreateExcerptLC
       
   597 // ---------------------------------------------------------------------------
       
   598 //
       
   599 HBufC* CMessageDataHandler::CreateExcerptLC(const TDesC& aFromAddress,
       
   600 											const CDesCArray& aRecipientArray,
       
   601 											const TDesC& aSubject,
       
   602 											const TDesC& aBodyText,
       
   603 											const TMsvId& aFolderId)
       
   604 	{
       
   605 	_LIT(KEllipsis, "...");
       
   606 	_LIT(KSpace, " ");
       
   607 	TInt excerptLength = KMsgBodyExcerptSymbols + KEllipsis().Length(); 
       
   608 
       
   609 	TMsvEntry entry;
       
   610 	TMsvId service = 0;
       
   611 	iMsvSession.GetEntry(aFolderId, service, entry);
       
   612 	HBufC *folder_str = entry.iDetails.AllocLC();
       
   613 
       
   614 	excerptLength += folder_str->Length();
       
   615 	excerptLength += KSpace().Length();
       
   616 
       
   617 	if ((aFromAddress.Length() > 0) && (aFolderId == KMsvGlobalInBoxIndexEntryIdValue))
       
   618 		{
       
   619 		excerptLength += aFromAddress.Length();
       
   620 		excerptLength += KSpace().Length();
       
   621 		}
       
   622 	if ((aRecipientArray.MdcaCount() > 0) && (aFolderId != KMsvGlobalInBoxIndexEntryIdValue))
       
   623 		{
       
   624 		excerptLength += aRecipientArray.MdcaPoint(0).Length();
       
   625 		excerptLength += KSpace().Length(); 
       
   626 		}
       
   627 	if (aSubject.Length() > 0)
       
   628 		{
       
   629 		excerptLength += aSubject.Length();
       
   630 		excerptLength += KSpace().Length();
       
   631 		}
       
   632 
       
   633 	HBufC* excerpt = HBufC::NewL(excerptLength);
       
   634 	TPtr excerptPtr = excerpt->Des();
       
   635 
       
   636 	excerptPtr.Copy(*folder_str);
       
   637 	excerptPtr.Append(KSpace);
       
   638 	
       
   639 	if ((aFromAddress.Length() > 0) && (aFolderId == KMsvGlobalInBoxIndexEntryIdValue))
       
   640 		{
       
   641 		excerptPtr.Append(aFromAddress);
       
   642 		excerptPtr.Append(KSpace);
       
   643 		}
       
   644 	if ((aRecipientArray.MdcaCount() > 0) && (aFolderId != KMsvGlobalInBoxIndexEntryIdValue))
       
   645 		{
       
   646 		excerptPtr.Append(aRecipientArray.MdcaPoint(0));
       
   647 		excerptPtr.Append(KSpace);
       
   648 		}
       
   649 	if (aSubject.Length() > 0)
       
   650 		{
       
   651 		excerptPtr.Append(aSubject);
       
   652 		excerptPtr.Append(KSpace);
       
   653 		}
       
   654 
       
   655 	excerptPtr.Append(aBodyText.Left(KMsgBodyExcerptSymbols));
       
   656 	if (aBodyText.Length() > KMsgBodyExcerptSymbols)
       
   657 		excerptPtr.Append(KEllipsis);
       
   658 
       
   659 	CleanupStack::PopAndDestroy(folder_str);
       
   660 	CleanupStack::PushL(excerpt);
       
   661 	return excerpt;
       
   662 	}
       
   663 
       
   664 // ---------------------------------------------------------------------------
       
   665 // CMessageDataHandler::IsTextUcs2
       
   666 // ---------------------------------------------------------------------------
       
   667 //
       
   668 TBool CMessageDataHandler::IsTextUcs2(const TDesC8& aText)
       
   669     {
       
   670     TBool ret = EFalse;
       
   671     // Check UCS-2 Byte order mark is in the first two bytes of aText
       
   672     if (aText.Length() >= sizeof(KMmsByteOrderMark))
       
   673         {
       
   674         TPtrC ptr(reinterpret_cast<const TUint16*>(aText.Ptr()), 
       
   675                         aText.Length() / sizeof(TText));
       
   676 
       
   677         if (KMmsByteOrderMark == ptr[0] ||
       
   678             KMmsReversedByteOrderMark == ptr[0])
       
   679             {
       
   680             ret = ETrue;
       
   681             }
       
   682         }
       
   683     return ret;
       
   684     }   	
       
   685 
       
   686 // ---------------------------------------------------------------------------
       
   687 // CMessageDataHandler::TextContainsUtf8Bom
       
   688 // ---------------------------------------------------------------------------
       
   689 //
       
   690 TBool CMessageDataHandler::TextContainsUtf8Bom(const TDesC8& aText)
       
   691     {    
       
   692     TBool ret = EFalse;
       
   693     // Check to see if there is the UTF8 BOM at the begining
       
   694     TPtrC8 utf8Id(KUtf8Bom, KUtf8BomLength);
       
   695     if (aText.Length() >= KUtf8BomLength &&
       
   696         aText.Left(KUtf8BomLength) == utf8Id)
       
   697         {
       
   698         ret = ETrue;
       
   699         }
       
   700     return ret;
       
   701     }
       
   702 
       
   703 // ---------------------------------------------------------------------------
       
   704 // CMessageDataHandler::TextFileCharsetL
       
   705 // ---------------------------------------------------------------------------
       
   706 //
       
   707 TUint CMessageDataHandler::TextFileCharsetL(RFs aFs, RFile aFile)
       
   708     {
       
   709     TUint ret = KMmsUsAscii;
       
   710     TBuf8<sizeof(KMmsByteOrderMark)> ucs2Buf;
       
   711 
       
   712     TInt size;
       
   713     User::LeaveIfError(aFile.Size(size));
       
   714     if (size >= sizeof(KMmsByteOrderMark))
       
   715         {
       
   716         // Check for the UCS-2 Byte Order Mark (BOM) at the beginning 
       
   717         // beginning of the file
       
   718         User::LeaveIfError(aFile.Read(ucs2Buf));
       
   719         if(IsTextUcs2(ucs2Buf))
       
   720             {
       
   721             ret = KMmsIso10646Ucs2;
       
   722             }
       
   723         }
       
   724 
       
   725     if (KMmsIso10646Ucs2 != ret)
       
   726         {
       
   727         // If the text is not UCS-2 it will probably be Utf8 or Ascii
       
   728 
       
   729         TInt seekPos = 0;
       
   730         User::LeaveIfError(aFile.Seek(ESeekStart, seekPos));
       
   731         
       
   732         HBufC8* buf = HBufC8::NewLC(size);
       
   733         TPtr8 ptr = buf->Des();
       
   734         User::LeaveIfError(aFile.Read(ptr));
       
   735 
       
   736         // Check to see if there is the UTF8 BOM at the begining
       
   737         if (TextContainsUtf8Bom(ptr))
       
   738             {
       
   739             ret = KMmsUtf8;
       
   740             }
       
   741         else
       
   742             {
       
   743             CCnvCharacterSetConverter* converter = 
       
   744                               CCnvCharacterSetConverter::NewLC();
       
   745             CArrayFix<CCnvCharacterSetConverter::SCharacterSet>* availCharSets =
       
   746                 CCnvCharacterSetConverter::CreateArrayOfCharacterSetsAvailableLC(aFs);
       
   747 
       
   748             CArrayFix<CCnvCharacterSetConverter::SCharacterSet>* utf8CharSet = 
       
   749                 new (ELeave) CArrayFixFlat<CCnvCharacterSetConverter::SCharacterSet>(1); 
       
   750             CleanupStack::PushL(utf8CharSet);
       
   751 
       
   752             TInt count = availCharSets->Count();
       
   753             for (TInt i = 0; i < count; i++)
       
   754                 {
       
   755                 CCnvCharacterSetConverter::SCharacterSet& charSet = (*availCharSets)[i];
       
   756                 if (KCharacterSetIdentifierUtf8 == charSet.Identifier())
       
   757                     {
       
   758                     utf8CharSet->AppendL(charSet);
       
   759                     break;
       
   760                     }
       
   761                 }
       
   762             TInt confidence;
       
   763             TUint charSetId;
       
   764             converter->AutoDetectCharacterSetL(confidence, 
       
   765                                                charSetId, 
       
   766                                                *utf8CharSet,
       
   767                                                *buf);
       
   768             const TInt KMaxConfidence = 100;
       
   769             if (KMaxConfidence == confidence)
       
   770                 {
       
   771                 ret = KMmsUtf8;
       
   772                 }
       
   773             CleanupStack::PopAndDestroy(3, converter);
       
   774 
       
   775             }
       
   776 
       
   777         CleanupStack::PopAndDestroy(buf);
       
   778         }
       
   779 
       
   780     TInt zero = 0;
       
   781     User::LeaveIfError(aFile.Seek(ESeekStart, zero));
       
   782 
       
   783     return ret;
       
   784     }
       
   785 
       
   786 // ---------------------------------------------------------------------------
       
   787 // CMessageDataHandler::ConvertToUcs2FromUtfL
       
   788 // ---------------------------------------------------------------------------
       
   789 //
       
   790 void CMessageDataHandler::ConvertToUcs2FromUtfL(RFs& aFs,
       
   791                                                  TDes& aUcs2Text,
       
   792                                                  const TDesC8& aUtfText,
       
   793                                                  TUint aMibCharset)
       
   794     {
       
   795     TPtrC8 toConvert(aUtfText);
       
   796     if (KMmsUtf8 == aMibCharset)
       
   797         {
       
   798         if (TextContainsUtf8Bom(toConvert))
       
   799             {
       
   800             toConvert.Set(toConvert.Mid(KUtf8BomLength));
       
   801             }
       
   802         }
       
   803     // prepare to convert character set to unicode
       
   804     CCnvCharacterSetConverter* converter = 
       
   805                           CCnvCharacterSetConverter::NewLC();
       
   806     // change character set ID from MIB to Symbian
       
   807     TUint charsetID = converter->ConvertMibEnumOfCharacterSetToIdentifierL(
       
   808                                      aMibCharset, aFs);
       
   809     CCnvCharacterSetConverter::TAvailability availability =
       
   810             converter->PrepareToConvertToOrFromL(charsetID, aFs);
       
   811 
       
   812     if (availability == CCnvCharacterSetConverter::ENotAvailable)
       
   813         {
       
   814         User::Leave(KErrNotSupported);
       
   815         }
       
   816     TInt state = CCnvCharacterSetConverter::KStateDefault;
       
   817 
       
   818     User::LeaveIfError(converter->ConvertToUnicode(aUcs2Text, toConvert, state));
       
   819 
       
   820     CleanupStack::PopAndDestroy(converter);
       
   821     }
       
   822     
       
   823 	
       
   824 // -----------------------------------------------------------------------------
       
   825 // CMessageDataHandler::DoCancel
       
   826 // -----------------------------------------------------------------------------
       
   827 //   
       
   828 void CMessageDataHandler::DoCancel()
       
   829 	{
       
   830 	}
       
   831 
       
   832 // -----------------------------------------------------------------------------
       
   833 // CMessageDataHandler::RunL
       
   834 // -----------------------------------------------------------------------------
       
   835 //   
       
   836 void CMessageDataHandler::RunL()
       
   837 	{
       
   838 		CPIXLOGSTRING2( "CMessageDataHandler::RunL status %d",iStatus.Int() );
       
   839 
       
   840 	// Implement round robin for the CActives
       
   841 	Deque();
       
   842 	CActiveScheduler::Add(this);
       
   843 
       
   844 	// Handle next message
       
   845 	if (iMessageArray.Count() > 0)
       
   846 		{
       
   847 		// Take first id from array
       
   848 		CreateMessageIndexItemL(iMessageArray[0].iMessageId,
       
   849 				iMessageArray[0].iActionType, iMessageArray[0].iFolderId);
       
   850 		
       
   851 		// Remove item that is handled
       
   852 		iMessageArray.Remove(0);
       
   853 
       
   854 		// Handle next
       
   855 		HandleNextRequest();
       
   856 		}
       
   857 	}
       
   858 
       
   859 // -----------------------------------------------------------------------------
       
   860 // CMessageDataHandler::RunError
       
   861 // -----------------------------------------------------------------------------
       
   862 //   
       
   863 TInt CMessageDataHandler::RunError(TInt aError)
       
   864 	{
       
   865 		CPIXLOGSTRING2( "CMessageDataHandler::RunError err %d", aError );
       
   866 	if (iMessageArray.Count() > 0)
       
   867 		{
       
   868 		// Remove item that is handled
       
   869 		iMessageArray.Remove(0);
       
   870 
       
   871 		// Handle next after the error
       
   872 		HandleNextRequest();
       
   873 		}
       
   874 	return KErrNone;
       
   875 	}
       
   876 
       
   877 // ---------------------------------------------------------------------------
       
   878 // HandleNextRequest
       
   879 // ---------------------------------------------------------------------------
       
   880 //
       
   881 void CMessageDataHandler::HandleNextRequest()
       
   882 	{
       
   883 	if (!IsActive())
       
   884 		{
       
   885 		SetActive();
       
   886 		TRequestStatus* status = &iStatus;
       
   887 		User::RequestComplete(status, KErrNone);
       
   888 		}
       
   889 	}
       
   890 
       
   891 // End of File
       
   892