|         |      1 /* | 
|         |      2 * Copyright (c) 2002-2004 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:  Loads html content | 
|         |     15 * | 
|         |     16 */ | 
|         |     17  | 
|         |     18  | 
|         |     19  | 
|         |     20 // INCLUDE FILES | 
|         |     21 #include 	"MailLog.h" | 
|         |     22 #include 	"MailUtils.h" | 
|         |     23 #include    "MailLoadStateHtml.h" | 
|         |     24 #include    "MailLoadStateInline.h" | 
|         |     25 #include 	"MailLoadStateMachine.h" | 
|         |     26 #include 	"MsgMailViewerHtmlConv.h" | 
|         |     27 #include 	<MailPlainView.rsg> | 
|         |     28 #include    <MMailAppUiInterface.h> | 
|         |     29 #include    <CMailMessage.h> | 
|         |     30 #include 	<StringLoader.h> | 
|         |     31 #include 	<charconv.h> | 
|         |     32  | 
|         |     33 _LIT8( KStartTag, "<html>" ); | 
|         |     34 _LIT8( KHtmlHeader1, "<meta http-equiv=\"Content-Type\" content=\"text/html; charset="); | 
|         |     35 _LIT8( KHtmlHeader2, "\">\n"); | 
|         |     36 _LIT8( KCharsetTag, "CHARSET" ); | 
|         |     37 _LIT16( KCDrive, "C:" ); | 
|         |     38 const TInt KPathNameLength( 100 ); | 
|         |     39  | 
|         |     40 // ============================ MEMBER FUNCTIONS =============================== | 
|         |     41  | 
|         |     42 // load html file | 
|         |     43 // ----------------------------------------------------------------------------- | 
|         |     44 // CLoadHtmlFile::MessageLoadingL | 
|         |     45 // ----------------------------------------------------------------------------- | 
|         |     46 // | 
|         |     47 void CLoadHtmlFile::MessageLoadingL(TInt aStatus, CMailMessage& aMessage) | 
|         |     48 	{ | 
|         |     49 	if( aStatus == CMailMessage::EBodyTextReady ) | 
|         |     50 		{ | 
|         |     51         TRAPD( err, HandleBodyTextReadyL( aMessage ) ); | 
|         |     52  | 
|         |     53         if( err ) | 
|         |     54             { | 
|         |     55             // Complete request and leave if error occured | 
|         |     56             CompleteRequest( err ); | 
|         |     57             User::LeaveIfError( err ); | 
|         |     58             } | 
|         |     59 		} | 
|         |     60 	} | 
|         |     61  | 
|         |     62 // ----------------------------------------------------------------------------- | 
|         |     63 // CLoadHtmlFile::CLoadHtmlFile | 
|         |     64 // ----------------------------------------------------------------------------- | 
|         |     65 // | 
|         |     66 CLoadHtmlFile::CLoadHtmlFile( | 
|         |     67 	MMailAppUiInterface* aAppUI, MStateMachine& aStateMachine ) : | 
|         |     68 	CActive( CActive::EPriorityStandard ) | 
|         |     69 	{ | 
|         |     70 	CActiveScheduler::Add( this ); | 
|         |     71 	iAppUI = aAppUI; | 
|         |     72 	iStateMachine = &aStateMachine; | 
|         |     73 	} | 
|         |     74  | 
|         |     75 // ----------------------------------------------------------------------------- | 
|         |     76 // CLoadHtmlFile::~CLoadHtmlFile | 
|         |     77 // ----------------------------------------------------------------------------- | 
|         |     78 // | 
|         |     79 CLoadHtmlFile::~CLoadHtmlFile() | 
|         |     80 	{ | 
|         |     81 	Cancel(); | 
|         |     82 	delete iConverter; | 
|         |     83 	} | 
|         |     84  | 
|         |     85 // ----------------------------------------------------------------------------- | 
|         |     86 // CLoadHtmlFile::NextStateL | 
|         |     87 // ----------------------------------------------------------------------------- | 
|         |     88 // | 
|         |     89 MLoadState* CLoadHtmlFile::NextStateL() | 
|         |     90 	{ | 
|         |     91 	return new( ELeave ) CLoadInlineImages( | 
|         |     92 		iAppUI, *iStateMachine ); | 
|         |     93 	} | 
|         |     94  | 
|         |     95 // ----------------------------------------------------------------------------- | 
|         |     96 // CLoadHtmlFile::MakeRequestL | 
|         |     97 // ----------------------------------------------------------------------------- | 
|         |     98 // | 
|         |     99 void CLoadHtmlFile::MakeRequestL( | 
|         |    100 	TRequestStatus& aStatus, | 
|         |    101 	CMailMessage& aMessage ) | 
|         |    102 	{ | 
|         |    103 	iLoadStatus = &aStatus; | 
|         |    104 	iMessage = &aMessage; | 
|         |    105 	aMessage.LoadHtmlContentL( *this ); | 
|         |    106 	aStatus = KRequestPending; | 
|         |    107 	} | 
|         |    108  | 
|         |    109 // ----------------------------------------------------------------------------- | 
|         |    110 // CLoadHtmlFile::HandleBodyTextReadyL | 
|         |    111 // ----------------------------------------------------------------------------- | 
|         |    112 // | 
|         |    113 void CLoadHtmlFile::HandleBodyTextReadyL( CMailMessage& aMessage ) | 
|         |    114     { | 
|         |    115 	RFile handle = aMessage.HtmlContent(); | 
|         |    116 	CleanupClosePushL( handle ); | 
|         |    117  | 
|         |    118 	if ( handle.SubSessionHandle() == 0 ) | 
|         |    119 		{ | 
|         |    120 		// if html content can not be found try to show plain text | 
|         |    121 		// content | 
|         |    122 		CRichText* bodyText = aMessage.MessageBody(); | 
|         |    123 		// Partial loaded or corrupted message? | 
|         |    124 		if ( aMessage.MessageEntry().PartialDownloaded() ) | 
|         |    125 			{ | 
|         |    126 			HBufC* text = StringLoader::LoadLC( | 
|         |    127 				R_QTN_MAIL_REST_OF_MAIL_NOT_FETCHED, CCoeEnv::Static()); | 
|         |    128  | 
|         |    129 	        bodyText->InsertL(0, *text); | 
|         |    130 	        CleanupStack::PopAndDestroy(); // text | 
|         |    131 			} | 
|         |    132 		else // Corrupted? | 
|         |    133 			{ | 
|         |    134 			MailUtils::InformationNoteL( | 
|         |    135 				R_MAIL_VIEWER_HTML_ERROR_DLG_TEXT ); | 
|         |    136 			} | 
|         |    137         iAppUI->SetBodyTextL(*aMessage.MessageBody()); | 
|         |    138         CompleteRequest( KErrNone ); | 
|         |    139 		} | 
|         |    140 	else | 
|         |    141 		{ | 
|         |    142 		// Add html content as attachment before conversion. | 
|         |    143 		if ( !aMessage.MessageEntry().PartialDownloaded() ) | 
|         |    144 			{ | 
|         |    145 			AddHtmlFileAttachmentAndCharsetL( aMessage, handle ); | 
|         |    146 			} | 
|         |    147         ParseHtmlFileL( aMessage, handle ); | 
|         |    148 		} | 
|         |    149     CleanupStack::PopAndDestroy(); // handle | 
|         |    150     } | 
|         |    151  | 
|         |    152 // ----------------------------------------------------------------------------- | 
|         |    153 // CLoadHtmlFile::ShowHtmlErrorNoteIfNeededL | 
|         |    154 // ----------------------------------------------------------------------------- | 
|         |    155 // | 
|         |    156 void CLoadHtmlFile::ShowHtmlErrorNoteIfNeededL( TInt aResult ) | 
|         |    157 	{ | 
|         |    158     if ( aResult == KErrNotFound ) | 
|         |    159         { | 
|         |    160 		MailUtils::InformationNoteL( R_MAIL_VIEWER_HTML_ERROR_DLG_TEXT ); | 
|         |    161         } | 
|         |    162     else if ( aResult == KErrCorrupt ) | 
|         |    163         { | 
|         |    164 		MailUtils::InformationNoteL( R_MAIL_VIEWER_HTML_CORRUPTED_NOTE_TEXT ); | 
|         |    165         } | 
|         |    166     else if ( aResult == KErrEof ) | 
|         |    167         { | 
|         |    168         // Successfully parsed. Do nothing. | 
|         |    169         } | 
|         |    170     else | 
|         |    171         { | 
|         |    172         User::LeaveIfError( aResult ); | 
|         |    173         } | 
|         |    174 	} | 
|         |    175  | 
|         |    176 // ----------------------------------------------------------------------------- | 
|         |    177 // CLoadHtmlFile::AddHtmlFileAttachmentL | 
|         |    178 // ----------------------------------------------------------------------------- | 
|         |    179 // | 
|         |    180 void CLoadHtmlFile::AddHtmlFileAttachmentL( | 
|         |    181     CMailMessage& aMessage, RFile aFile ) | 
|         |    182     { | 
|         |    183 	CMsvAttachment* htmlFileInfo = CMsvAttachment::NewL( | 
|         |    184 		CMsvAttachment::EMsvFile ); | 
|         |    185 	CleanupStack::PushL( htmlFileInfo ); | 
|         |    186  | 
|         |    187 	TInt htmlSize(0); | 
|         |    188 	aFile.Size( htmlSize ); | 
|         |    189 	htmlFileInfo->SetSize( htmlSize ); | 
|         |    190 	TFileName filename; | 
|         |    191 	User::LeaveIfError( aFile.Name( filename ) ); | 
|         |    192 	htmlFileInfo->SetAttachmentNameL( filename ); | 
|         |    193 	htmlFileInfo->SetComplete( ETrue ); | 
|         |    194 	htmlFileInfo->SetId( aMessage.MhtmlPartId() ); | 
|         |    195  | 
|         |    196     iAppUI->AddAttachmentL( *htmlFileInfo, EFalse ); | 
|         |    197     CleanupStack::PopAndDestroy( htmlFileInfo ); | 
|         |    198     } | 
|         |    199  | 
|         |    200 // ----------------------------------------------------------------------------- | 
|         |    201 // CLoadHtmlFile::ParseHtmlFileL | 
|         |    202 // ----------------------------------------------------------------------------- | 
|         |    203 // | 
|         |    204 void CLoadHtmlFile::ParseHtmlFileL(CMailMessage& aMessage, RFile aFile ) | 
|         |    205     { | 
|         |    206     LOG( "CLoadHtmlFile::ParseHtmlFileL" ); | 
|         |    207     LOGHANDLESIZE( aFile ); | 
|         |    208  | 
|         |    209     // Get the charset of the html part from the message. If the message | 
|         |    210     // thinks it knows the html charset then force the conversion of the html | 
|         |    211     // part using the specified character set decoding. | 
|         |    212     // | 
|         |    213     // Otherwise, if the html message part character set is unknown, then | 
|         |    214     // we'll let the conversion object try to identify the character set during | 
|         |    215     // the parsing process. | 
|         |    216     const TUint htmlCharSetId = aMessage.HtmlCharsetIdL(); | 
|         |    217     const TBool forceCharSet = ( htmlCharSetId != 0 ); | 
|         |    218  | 
|         |    219     delete iConverter; | 
|         |    220     iConverter = NULL; | 
|         |    221     iConverter = CMsgMailViewerHtmlConv::NewL( | 
|         |    222             aFile, | 
|         |    223             htmlCharSetId, | 
|         |    224             forceCharSet ); | 
|         |    225  | 
|         |    226     iConverter->Convert( &iStatus ); | 
|         |    227     SetActive(); | 
|         |    228     } | 
|         |    229  | 
|         |    230 // ----------------------------------------------------------------------------- | 
|         |    231 // CLoadHtmlFile::RunL | 
|         |    232 // ----------------------------------------------------------------------------- | 
|         |    233 // | 
|         |    234 void CLoadHtmlFile::RunL() | 
|         |    235     { | 
|         |    236     LOG( "CLoadHtmlFile::RunL" ); | 
|         |    237     ShowHtmlErrorNoteIfNeededL( iStatus.Int() ); | 
|         |    238  | 
|         |    239     CRichText* bodyText = iMessage->MessageBody(); | 
|         |    240     bodyText->Reset(); | 
|         |    241     bodyText->InsertL(0, *(iConverter->GetText())); | 
|         |    242  | 
|         |    243     // If the conversion process successfully identified the characterset | 
|         |    244     // of the html part, then update the message with this new charset | 
|         |    245     // decoding value. | 
|         |    246     if ( iConverter->AutoParsedCharSetNameAndIdentifier() ) | 
|         |    247         { | 
|         |    248         const TUint autoParsedCharSetId = iConverter->AutoParsedCharSetIdentifier(); | 
|         |    249         iMessage->OverrideHtmlMessageCharset( autoParsedCharSetId ); | 
|         |    250         } | 
|         |    251  | 
|         |    252     iStateMachine->SetIdArray( iConverter->FileIdArray() ); | 
|         |    253  | 
|         |    254     if ( iMessage->MessageEntry().PartialDownloaded() ) | 
|         |    255         { | 
|         |    256         HBufC* text = StringLoader::LoadLC( | 
|         |    257             R_QTN_MAIL_REST_OF_MAIL_NOT_FETCHED, CCoeEnv::Static()); | 
|         |    258  | 
|         |    259         bodyText->InsertL(bodyText->DocumentLength(), CEditableText::ELineBreak); | 
|         |    260  | 
|         |    261         bodyText->InsertL(bodyText->DocumentLength(), *text); | 
|         |    262  | 
|         |    263         CleanupStack::PopAndDestroy(); // text | 
|         |    264         } | 
|         |    265  | 
|         |    266     iAppUI->SetBodyTextL( *(iMessage->MessageBody()) ); | 
|         |    267  | 
|         |    268     // All done | 
|         |    269     CompleteRequest( KErrNone ); | 
|         |    270     } | 
|         |    271  | 
|         |    272 // ----------------------------------------------------------------------------- | 
|         |    273 // CLoadHtmlFile::RunError | 
|         |    274 // ----------------------------------------------------------------------------- | 
|         |    275 // | 
|         |    276 TInt CLoadHtmlFile::RunError( TInt aError ) | 
|         |    277     { | 
|         |    278     LOG( "CLoadHtmlFile::DoCancel" ); | 
|         |    279     CompleteRequest( aError ); | 
|         |    280     return KErrNone; | 
|         |    281     } | 
|         |    282  | 
|         |    283 // ----------------------------------------------------------------------------- | 
|         |    284 // CLoadHtmlFile::DoCancel | 
|         |    285 // ----------------------------------------------------------------------------- | 
|         |    286 // | 
|         |    287 void CLoadHtmlFile::DoCancel() | 
|         |    288     { | 
|         |    289     LOG( "CLoadHtmlFile::DoCancel" ); | 
|         |    290  | 
|         |    291     if( iConverter ) | 
|         |    292         { | 
|         |    293         iConverter->Cancel(); | 
|         |    294         } | 
|         |    295     } | 
|         |    296  | 
|         |    297 // ----------------------------------------------------------------------------- | 
|         |    298 // CLoadHtmlFile::CompleteRequest | 
|         |    299 // ----------------------------------------------------------------------------- | 
|         |    300 // | 
|         |    301 void CLoadHtmlFile::CompleteRequest( TInt aError ) | 
|         |    302     { | 
|         |    303     LOG( "CLoadHtmlFile::CompleteRequest" ); | 
|         |    304     User::RequestComplete( iLoadStatus, aError ); | 
|         |    305     iAppUI->ViewMessageComplete(); | 
|         |    306     } | 
|         |    307  | 
|         |    308 // ----------------------------------------------------------------------------- | 
|         |    309 // CLoadHtmlFile::AddCharsetToHtmlAttachment | 
|         |    310 // ----------------------------------------------------------------------------- | 
|         |    311 // | 
|         |    312 void CLoadHtmlFile::AddHtmlFileAttachmentAndCharsetL( CMailMessage& aMessage, RFile& aHandle ) | 
|         |    313 	{ | 
|         |    314 	// We have to check if the html body contains information about | 
|         |    315 	// charset used. If it does, we use original file. Otherwise | 
|         |    316 	// we create a new html file which has charset | 
|         |    317 	// information added | 
|         |    318  | 
|         |    319 	// Get charset Id and handle for the html body content | 
|         |    320 	TUint htmlCharsetId = aMessage.HtmlCharsetIdL(); | 
|         |    321  | 
|         |    322 	// Convert charset Id into string | 
|         |    323 	RFs& fs = CCoeEnv::Static()->FsSession(); | 
|         |    324 	CCnvCharacterSetConverter* charConv = CCnvCharacterSetConverter::NewLC(); | 
|         |    325 	HBufC8* charsetBuf = charConv-> | 
|         |    326 		ConvertCharacterSetIdentifierToStandardNameL( | 
|         |    327 				htmlCharsetId, fs); | 
|         |    328 	CleanupStack::PopAndDestroy( charConv ); // charConv | 
|         |    329 	CleanupStack::PushL( charsetBuf ); | 
|         |    330 	TPtr8 charsetPtr = charsetBuf->Des(); | 
|         |    331  | 
|         |    332 	// Calculate buffer size for charsetRowBuf and also for | 
|         |    333 	// htmlContentBuf to avoid reallocation of memory | 
|         |    334 	TInt bufferSize( 0 ); | 
|         |    335 	bufferSize += KHtmlHeader1().Length(); | 
|         |    336 	bufferSize += charsetBuf->Length(); | 
|         |    337 	bufferSize += KHtmlHeader2().Length(); | 
|         |    338  | 
|         |    339 	// Read html content from the html file | 
|         |    340 	TInt fileSize(0); | 
|         |    341 	aHandle.Size( fileSize ); | 
|         |    342 	HBufC8* htmlContentBuf = HBufC8::NewLC( fileSize+bufferSize ); | 
|         |    343 	TPtr8 htmlContentPtr = htmlContentBuf->Des(); | 
|         |    344 	aHandle.Read( htmlContentPtr ); | 
|         |    345 	TInt i( 0 ); | 
|         |    346 	aHandle.Seek( ESeekStart, i );	// rewind the file | 
|         |    347  | 
|         |    348 	// Try to find strings CHARSET and <html> | 
|         |    349 	// If the string is not found append information containing charset | 
|         |    350 	TInt charsetFoundAt( htmlContentBuf->Find( KCharsetTag ) ); | 
|         |    351 	TInt htmlTagFoundAt( htmlContentBuf->Find( KStartTag ) ); | 
|         |    352  | 
|         |    353 	// If CHARSET is defined in the email but it is not found from the | 
|         |    354 	// html body part, we have to add it ourselves. | 
|         |    355 	// Else use the original html file | 
|         |    356 	if( charsetFoundAt <= 0 | 
|         |    357 		&& htmlTagFoundAt >= 0 ) | 
|         |    358 		{ | 
|         |    359 		// Create a new hmtl line containing character set information | 
|         |    360 		// and append it. | 
|         |    361 		// Create new buffer for storing charset html info row and | 
|         |    362 		// insert it to the buffer containing html body | 
|         |    363 		HBufC8* charsetRowBuf = HBufC8::NewLC( bufferSize ); | 
|         |    364 		TPtr8 charsetRowPtr = charsetRowBuf->Des(); | 
|         |    365 		charsetRowPtr.Append( KHtmlHeader1 ); | 
|         |    366 		charsetRowPtr.Append( charsetPtr ); | 
|         |    367 		charsetRowPtr.Append( KHtmlHeader2 ); | 
|         |    368 		htmlContentPtr.Insert( htmlTagFoundAt, charsetRowPtr ); | 
|         |    369 		CleanupStack::PopAndDestroy( charsetRowBuf ); | 
|         |    370  | 
|         |    371 		// create mailviewer folder in c:\private | 
|         |    372 		HBufC* pathNameBuf = HBufC::NewLC( KPathNameLength ); | 
|         |    373 		TPtr pathNamePtr = pathNameBuf->Des(); | 
|         |    374 		fs.PrivatePath( pathNamePtr ); | 
|         |    375 		pathNamePtr.Insert( 0, KCDrive ); | 
|         |    376  | 
|         |    377 		TInt makeDir = fs.MkDir( pathNamePtr ); | 
|         |    378 		// Itīs ok if directory already exists. If other errors, | 
|         |    379 		// use original html file | 
|         |    380 		if( makeDir != KErrAlreadyExists && makeDir < 0 ) | 
|         |    381 			{ | 
|         |    382 			AddHtmlFileAttachmentL( aMessage, aHandle ); | 
|         |    383 			} | 
|         |    384 		else	// continue creating new html attachment | 
|         |    385 			{ | 
|         |    386 			// create new html attachment | 
|         |    387 			RFile newHtmlFile; | 
|         |    388 			HBufC* newHtmlFileNameBuf = HBufC::NewLC( KPathNameLength ); | 
|         |    389 			TPtr newHtmlFileNamePtr = newHtmlFileNameBuf->Des(); | 
|         |    390 			aHandle.Name( newHtmlFileNamePtr ); | 
|         |    391 			pathNamePtr.Append( newHtmlFileNamePtr ); | 
|         |    392 			CleanupStack::PopAndDestroy( newHtmlFileNameBuf ); | 
|         |    393  | 
|         |    394 			TInt openResult = newHtmlFile.Replace( fs, pathNamePtr, EFileWrite ); | 
|         |    395 			CleanupClosePushL( newHtmlFile ); | 
|         |    396 			if( openResult >= KErrNone ) | 
|         |    397 				{ | 
|         |    398 				TInt writeResult = newHtmlFile.Write( 0, htmlContentPtr ); | 
|         |    399 				if( writeResult >= KErrNone ) | 
|         |    400 					{ | 
|         |    401 					AddHtmlFileAttachmentL( aMessage, newHtmlFile ); | 
|         |    402 					} | 
|         |    403 				else	// else use original html file | 
|         |    404 					{ | 
|         |    405 					AddHtmlFileAttachmentL( aMessage, aHandle ); | 
|         |    406 					} | 
|         |    407 				} | 
|         |    408 			CleanupStack::PopAndDestroy( &newHtmlFile ); | 
|         |    409 			} | 
|         |    410 		CleanupStack::PopAndDestroy( pathNameBuf ); | 
|         |    411 		} | 
|         |    412 	else	// charset found, use original html file | 
|         |    413 		{ | 
|         |    414 		AddHtmlFileAttachmentL( aMessage, aHandle ); | 
|         |    415 		} | 
|         |    416 	CleanupStack::PopAndDestroy( 2, charsetBuf );	// htmlContentBuf | 
|         |    417 	} | 
|         |    418  | 
|         |    419  | 
|         |    420 //  End of File |