email/pop3andsmtpmtm/clientmtms/src/MIUTRSLV.CPP
changeset 0 72b543305e3a
child 34 84197e66a4bd
equal deleted inserted replaced
-1:000000000000 0:72b543305e3a
       
     1 // Copyright (c) 1999-2009 Nokia Corporation and/or its subsidiary(-ies).
       
     2 // All rights reserved.
       
     3 // This component and the accompanying materials are made available
       
     4 // under the terms of "Eclipse Public License v1.0"
       
     5 // which accompanies this distribution, and is available
       
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     7 //
       
     8 // Initial Contributors:
       
     9 // Nokia Corporation - initial contribution.
       
    10 //
       
    11 // Contributors:
       
    12 //
       
    13 // Description:
       
    14 // MIUTRSLV.CPP
       
    15 //
       
    16 
       
    17 #include "MIUTRSLV.H"
       
    18 #include <msvuids.h>
       
    19 #include "MIUTMSG.H"
       
    20 #include "MIUT_ERR.H"
       
    21 
       
    22 #include <cmsvmimeheaders.h>
       
    23 #include <mmsvattachmentmanager.h>
       
    24 
       
    25 #ifdef SYMBIAN_ENABLE_SPLIT_HEADERS
       
    26 #include "cimmessagepart.h"
       
    27 #include "miut_errconsts.h"
       
    28 #include "timrfc822datefield.h"
       
    29 #endif
       
    30 
       
    31 _LIT(KImMhtmlCidString, "cid");
       
    32 _LIT8(KImMhtmlStartString, "start");
       
    33 
       
    34 
       
    35 // This class implements the URI resolving process described in RFC 2110.
       
    36 // Also see RFC 2112 and 1808.
       
    37 
       
    38 // MHTML messages may contain multiple HTML body parts. Each of these body parts
       
    39 // is able to reference another body part within the same multipart/related
       
    40 // structure. These references are called URI's.
       
    41 
       
    42 // When an MHTML message is parsed by the message engine, the HTML body of each
       
    43 // part is stored as a file. The following classes are a means of finding the
       
    44 // file name of the body part that corresponds to a given a URI.
       
    45 
       
    46 CImMhtmlUriResolver* CImMhtmlUriResolver::NewL(CMsvEntry& aEntry)
       
    47 	{
       
    48 	CImMhtmlUriResolver* self = NewLC(aEntry);
       
    49 	CleanupStack::Pop(); // self
       
    50 	return self;
       
    51 	}
       
    52 
       
    53 CImMhtmlUriResolver* CImMhtmlUriResolver::NewLC(CMsvEntry& aEntry)
       
    54 	{
       
    55 	CImMhtmlUriResolver* self = new (ELeave) CImMhtmlUriResolver(aEntry);
       
    56 	CleanupStack::PushL(self);
       
    57 	self->ConstructL();
       
    58 	return self;
       
    59 	}
       
    60 void CImMhtmlUriResolver::ResolveL(const TDesC& aURI, const TDesC& aHtmlBase, TMsvId aCurrentPartId,TBool aFileNameOnly, TRequestStatus& aStatus)
       
    61 	{
       
    62 	Queue(aStatus);
       
    63 	iResolved = EFalse;
       
    64 	delete iUri;
       
    65 	iUri = CImMhtmlUri::NewL(aURI);
       
    66 	iBodyPartId = aCurrentPartId;
       
    67 	iCurrentEntry.SetEntryL(aCurrentPartId);
       
    68 	iState = EImResolvingUri;
       
    69 	
       
    70 	iTryingThisMessage = EFalse;
       
    71 	iFileNameOnly = aFileNameOnly;
       
    72 	ResolveL(aHtmlBase, aCurrentPartId);
       
    73 	}
       
    74 
       
    75 
       
    76 void CImMhtmlUriResolver::ResolveL(const TDesC& aHtmlBase, TMsvId aCurrentPartId)
       
    77 	{
       
    78 
       
    79 	if (!(iUri->IsAbsolute()))
       
    80 	// Use the aHtmlBase parameter as a base to make an absolute URI from the given relative one.
       
    81 	// Try and find a match for this URI.
       
    82 		{
       
    83 		if (aHtmlBase.Length() != 0)
       
    84 			{
       
    85 			CImMhtmlUri* baseUri = CImMhtmlUri::NewLC(aHtmlBase);
       
    86 			if (baseUri->IsAbsolute())
       
    87 				{
       
    88 				iUri->MakeAbsoluteL(*baseUri);
       
    89 				}
       
    90 			CleanupStack::PopAndDestroy(); // baseUri
       
    91 			}
       
    92 		}
       
    93 
       
    94 	if (!(iUri->IsAbsolute()))
       
    95 	// Use the Content-location value that is associated with the current part as a base.
       
    96 	// Use this base to make an absolute URI from the given one and then search for it.
       
    97 		{
       
    98 		HBufC* contentLocation = GetContentLocationL(aCurrentPartId);
       
    99 		if (contentLocation)
       
   100 			{
       
   101 			CleanupStack::PushL(contentLocation);
       
   102 			CImMhtmlUri* baseUri = CImMhtmlUri::NewLC(contentLocation->Des());
       
   103 			if (baseUri->IsAbsolute())
       
   104 				{
       
   105 				iUri->MakeAbsoluteL(*baseUri);
       
   106 				}
       
   107 			CleanupStack::PopAndDestroy(2); // baseUri, contentLocation
       
   108 			}
       
   109 		}
       
   110 		
       
   111 	iStatus=KRequestPending;
       
   112 	SetActive();
       
   113 	TRequestStatus* status = &iStatus;
       
   114 	User::RequestComplete(status, KErrNone);
       
   115 	}
       
   116 
       
   117 void CImMhtmlUriResolver::FindFirstL(TMsvId aRootMessageId,TBool aFileNameOnly, TRequestStatus &aStatus)
       
   118 	{
       
   119 	Queue(aStatus);
       
   120 	iMhtmlFirstPageFinder->FindL(aRootMessageId,aFileNameOnly, iStatus);
       
   121 	iFileNameOnly = aFileNameOnly;
       
   122 	iState = EImFindingFirstUri;
       
   123 	SetActive();
       
   124 	}
       
   125 
       
   126 CImMhtmlUriResolver::~CImMhtmlUriResolver()
       
   127 	{
       
   128 	iFile.Close();
       
   129 	delete iUri;
       
   130 	delete iMhtmlFileFinder;
       
   131 	delete iMhtmlFirstPageFinder;
       
   132 	iUriCacheArray.ResetAndDestroy();
       
   133 	}
       
   134 
       
   135 	
       
   136 TInt CImMhtmlUriResolver::FileHandle(RFile& aFile) const	
       
   137 	{
       
   138 	if(iResolved)
       
   139 		{
       
   140 		// someone requested for the file handle,
       
   141 		// pass the handle and create a empty file handle
       
   142 		aFile = iFile;
       
   143 		iFile=RFile();
       
   144 		return KErrNone;	
       
   145 		}
       
   146 	else
       
   147 		{
       
   148 		return KErrNotFound;	
       
   149 		}	
       
   150 	}
       
   151 
       
   152 HBufC* CImMhtmlUriResolver::FileNameL() const
       
   153 	{
       
   154 	if (iResolved)
       
   155 		{
       
   156 		HBufC* fileName = HBufC::NewL(iFileName.Length());
       
   157 		(*fileName) = iFileName;
       
   158 		return fileName;
       
   159 		}
       
   160 	else
       
   161 		{
       
   162 		return iUri ? iUri->TextL(ETrue) : 0;
       
   163 		}
       
   164 	}
       
   165 
       
   166 TMsvId CImMhtmlUriResolver::LinkedEntryId() const
       
   167 	{
       
   168 	return iLinkedEntryId;
       
   169 	}
       
   170 
       
   171 void CImMhtmlUriResolver::ConstructL()
       
   172 	{
       
   173 	CActiveScheduler::Add(this);
       
   174 	iMhtmlFileFinder = CImMhtmlFileFinder::NewL(iCurrentEntry,iUriCacheArray);
       
   175 	iMhtmlFirstPageFinder = CImMhtmlFirstPageFinder::NewL(iCurrentEntry);
       
   176 	}
       
   177 
       
   178 void CImMhtmlUriResolver::DoRunL()
       
   179 	{
       
   180 	TBool matchUri = EFalse;
       
   181 
       
   182 	if ((iState == EImFindingFile)
       
   183 		&& (!iMhtmlFileFinder->MatchFound())
       
   184 		&& (iTryingThisMessage))
       
   185 		// Fix for MIME::lite.
       
   186 		// The body part could not be found using the thismessage: scheme,
       
   187 		// so look for a content location with the original unresolved URI.
       
   188 		{
       
   189 		matchUri = ETrue;
       
   190 		iTryingThisMessage = EFalse;
       
   191 		
       
   192 		CImMhtmlUri* unresolvedUri = CImMhtmlUri::NewLC(iUri->OriginalUriText()->Des());
       
   193 		delete iUri;
       
   194 		iUri = unresolvedUri;
       
   195 		CleanupStack::Pop(); // unresolvedUri
       
   196 		}
       
   197 
       
   198 	if (EImResolvingUri == iState)
       
   199 		{
       
   200 		if (!(iUri->IsAbsolute()))
       
   201 			{
       
   202 			iCurrentEntry.SetEntryL(iCurrentEntry.Entry().Parent());
       
   203 
       
   204 			if ((KUidMsvMessageEntry != iCurrentEntry.Entry().iType)
       
   205 				&& (KUidMsvFolderEntry != iCurrentEntry.Entry().iType))
       
   206 			// If there are no parent entries then use 'thismessage:/' as the base.
       
   207 				{
       
   208 				_LIT(KDefaultBase, "thismessage:/");
       
   209 				CImMhtmlUri* defaultBase = CImMhtmlUri::NewLC(KDefaultBase);
       
   210 				iUri->MakeAbsoluteL(*defaultBase);
       
   211 				CleanupStack::PopAndDestroy(); // defaultBase
       
   212 				matchUri = ETrue;
       
   213 				iTryingThisMessage = ETrue;
       
   214 				}
       
   215 			// If a valid base is still needed to complete the uri then try and find it in the parent headers.
       
   216 			else
       
   217 				{
       
   218 				ResolveL(KNullDesC ,iCurrentEntry.Entry().Id());
       
   219 				iState=EImTryingWithoutResolve;
       
   220 				}
       
   221 			}
       
   222 		else
       
   223 			{
       
   224 			matchUri = ETrue;
       
   225 			}
       
   226 		}
       
   227 	else if (iState == EImTryingWithoutResolve)
       
   228 		{
       
   229 		matchUri = ETrue;
       
   230 		}
       
   231 
       
   232 
       
   233 	if (matchUri)
       
   234 		{
       
   235 		if(CheckCacheForLinkedEntryL())
       
   236 			{
       
   237 			if (iStatus == KImcmHTMLPartNotPopulated)					
       
   238 				{
       
   239 				User::Leave(KImcmHTMLPartNotPopulated);	
       
   240 				}
       
   241 			}	
       
   242 		else
       
   243 			{
       
   244 			// Search the appropriate structures for the file that matches the absolute URI.
       
   245 			TBool cidUri = iUri->CompareScheme(KImMhtmlCidString);
       
   246 			// Do not include the scheme if the URI is a content-id ('cid:').
       
   247 			HBufC* uriText = iUri->TextL(!cidUri);
       
   248 	
       
   249 			CleanupStack::PushL(uriText);
       
   250 			iMhtmlFileFinder->FindL(uriText->Des(), iBodyPartId,iFileNameOnly, iStatus);
       
   251 			CleanupStack::PopAndDestroy(); // uriText
       
   252 			iState = EImFindingFile;
       
   253 			SetActive();
       
   254 			}
       
   255 		
       
   256 		}
       
   257 	}
       
   258 /** 
       
   259 Searches in cache for a URl that need to be resolved. If URL found in cache then it implies that URL 
       
   260 has been resolved in previous look ups (Each entry of cache contains a URL and its corresponding Linked Entry)
       
   261 @return True if cache contains URI else false
       
   262 */
       
   263 TBool CImMhtmlUriResolver::CheckCacheForLinkedEntryL()
       
   264 	{	
       
   265 	TInt count = iUriCacheArray.Count();
       
   266 	if(count)
       
   267 		{
       
   268 		CImCacheUriEntry* cacheEntry = NULL;
       
   269 		for(TInt i=0; i < count; ++i)
       
   270 			{
       
   271 			cacheEntry = iUriCacheArray[i];
       
   272 			if((iUri->OriginalUriText()->Des().Compare(cacheEntry->GetContentLocation()->Des()) == 0 ) || (iUri->OriginalUriText()->Des().Compare(cacheEntry->GetContentId()->Des()) == 0 ))
       
   273 				{
       
   274 				iLinkedEntryId = cacheEntry->GetUriEntry();
       
   275 				iCurrentEntry.SetEntryL(iLinkedEntryId);
       
   276 				CMsvStore* store = iCurrentEntry.ReadStoreL();
       
   277 				CleanupStack::PushL(store);
       
   278 				MMsvAttachmentManager& attachmentMgr = store->AttachmentManagerL();
       
   279 				// emails have one attachment per attachment entry
       
   280 				if(attachmentMgr.AttachmentCount())
       
   281 					{
       
   282 					if(iFileNameOnly)
       
   283 						{
       
   284 						CMsvAttachment* attachment = attachmentMgr.GetAttachmentInfoL(0);
       
   285 						iFileName = attachment->FilePath();
       
   286 						delete attachment;
       
   287 						}
       
   288 					else 
       
   289 						{
       
   290 						iFile = attachmentMgr.GetAttachmentFileL(0);	
       
   291 						}		
       
   292 					}
       
   293 				CleanupStack::PopAndDestroy(store);
       
   294 
       
   295 			// Check that the file exists. If it doesn't then complete with an error.
       
   296 			if (!iCurrentEntry.Entry().Complete())
       
   297 					{
       
   298 					iStatus = KImcmHTMLPartNotPopulated;
       
   299 					}
       
   300 				iResolved = ETrue;	//need to constract the uriresolver entry.
       
   301 				return ETrue;
       
   302 				}
       
   303 			}
       
   304 		}
       
   305 	return EFalse;
       
   306 	}
       
   307 
       
   308 
       
   309 void CImMhtmlUriResolver::DoComplete(TInt& aStatus)
       
   310 	{
       
   311 	if (EImFindingFirstUri == iState)
       
   312 		{
       
   313 		if ((iStatus == KErrNone) || (iStatus == KImcmHTMLPartNotPopulated))
       
   314 			{
       
   315 			if(iFileNameOnly)	
       
   316 				{
       
   317 				iMhtmlFirstPageFinder->Result(iFileName, iLinkedEntryId);			
       
   318 				}
       
   319 			else
       
   320 				{
       
   321 				iMhtmlFirstPageFinder->Result(iFile,iLinkedEntryId);
       
   322 				}
       
   323 			iResolved = ETrue;
       
   324 			}
       
   325 		}
       
   326 	else if (EImFindingFile == iState)
       
   327 		{
       
   328 		if ((iMhtmlFileFinder->MatchFound()) || (iStatus == KImcmHTMLPartNotPopulated))
       
   329 			{
       
   330 			if(iFileNameOnly)	
       
   331 				{
       
   332 				iMhtmlFileFinder->Result(iFileName, iLinkedEntryId);					
       
   333 				}
       
   334 			else
       
   335 				{
       
   336 				iMhtmlFileFinder->Result(iFile,iLinkedEntryId);
       
   337 				}
       
   338 			
       
   339 			iResolved = ETrue;
       
   340 			}
       
   341 		}
       
   342 	
       
   343 	if ((!iResolved) && (aStatus != KImcmHTMLPartNotPopulated))
       
   344 		{
       
   345 		aStatus = KErrNotFound;
       
   346 		}
       
   347 	}
       
   348 
       
   349 void CImMhtmlUriResolver::DoCancel()
       
   350 	{
       
   351 	switch (iState)
       
   352 		{
       
   353 		case EImFindingFile:
       
   354 			iMhtmlFileFinder->Cancel();
       
   355 			break;
       
   356 		case EImFindingFirstUri:
       
   357 			iMhtmlFirstPageFinder->Cancel();
       
   358 			break;
       
   359 		default:
       
   360 			break;
       
   361 		}
       
   362 	CMsgActive::DoCancel();
       
   363 	}
       
   364 
       
   365 CImMhtmlUriResolver::CImMhtmlUriResolver(CMsvEntry& aEntry) :  CMsgActive(EPriorityStandard), iCurrentEntry(aEntry)
       
   366 	{
       
   367 
       
   368 	}
       
   369 
       
   370 HBufC* CImMhtmlUriResolver::GetContentLocationL(TMsvId aEntryId)
       
   371 	{
       
   372 // Get the Content-location value from the mime header of the specified entry.
       
   373 	iCurrentEntry.SetEntryL(aEntryId);
       
   374 
       
   375 	HBufC* result = 0;
       
   376 
       
   377 	if(iCurrentEntry.HasStoreL())
       
   378 		{
       
   379 		CMsvStore* entryStore = iCurrentEntry.ReadStoreL();
       
   380 		CleanupStack::PushL(entryStore);
       
   381 		if (entryStore->IsPresentL(KUidMsgFileMimeHeader))
       
   382 			{
       
   383 			CImMimeHeader* mimeHeader = CImMimeHeader::NewLC();
       
   384 			mimeHeader->RestoreL(*entryStore);
       
   385 			TPtrC16 contentLocationPtr = mimeHeader->ContentLocation();
       
   386 			result = HBufC::NewL(contentLocationPtr.Length());
       
   387 			(*result) = contentLocationPtr;
       
   388 			CleanupStack::PopAndDestroy(); // mimeHeader
       
   389 			}
       
   390 		CleanupStack::PopAndDestroy(); // entryStore
       
   391 		}
       
   392 	return result;
       
   393 	}
       
   394 
       
   395 CImMhtmlChildEntrySearcher* CImMhtmlChildEntrySearcher::NewL(CMsvEntry& aEntry, RPointerArray<CImCacheUriEntry>& aUriCacheUriArray)
       
   396 	{
       
   397 	CImMhtmlChildEntrySearcher* self = new (ELeave) CImMhtmlChildEntrySearcher(aEntry, aUriCacheUriArray);
       
   398 	CActiveScheduler::Add(self);
       
   399 	return self;
       
   400 	}
       
   401 
       
   402 void CImMhtmlChildEntrySearcher::StartL(TMsvId aEntry, TDesC& aUri, TRequestStatus& aStatus)
       
   403 	{
       
   404 
       
   405 	delete iUri;
       
   406 	iUri = 0;
       
   407 	iUri = HBufC::NewL(aUri.Length());
       
   408 	(*iUri) = aUri;
       
   409 
       
   410 	delete iChildEntries;
       
   411 	iChildEntries = 0;
       
   412 	iEntry.SetEntryL(aEntry);
       
   413 	iChildEntries = iEntry.ChildrenL();
       
   414  	TInt index = iChildEntries->Count();
       
   415  	while (index--)
       
   416  		{
       
   417  		if (iEntry.ChildDataL((*iChildEntries)[index]).iType == KUidMsvFolderEntry)
       
   418  			iChildEntries->Delete(index);
       
   419  		}
       
   420 	iChildEntryIndex = 0;
       
   421 
       
   422 	iFound = EFalse;
       
   423 
       
   424 	if (iChildEntries->Count() != 0)
       
   425 		{
       
   426 		CheckCurrentEntryL();
       
   427 		Queue(aStatus);
       
   428 		}
       
   429 	else
       
   430 		{
       
   431 		Queue(aStatus);
       
   432 		iStatus=KRequestPending;
       
   433 		SetActive();
       
   434 		TRequestStatus* status = &iStatus;
       
   435 		User::RequestComplete(status, KErrNone);
       
   436 		}
       
   437 	}
       
   438 
       
   439 CImMhtmlChildEntrySearcher::~CImMhtmlChildEntrySearcher()
       
   440 	{
       
   441 	delete iUri;
       
   442 	delete iChildEntries;
       
   443 	}
       
   444 
       
   445 TBool CImMhtmlChildEntrySearcher::SearchResult(TMsvId& aSearchResultEntry)
       
   446 	{
       
   447 	if (iFound)
       
   448 		{
       
   449 		aSearchResultEntry = (*iChildEntries)[iChildEntryIndex];
       
   450 		}
       
   451 	return iFound;
       
   452 	}
       
   453 
       
   454 void CImMhtmlChildEntrySearcher::DoRunL()
       
   455 	{
       
   456 	if (!iFound)
       
   457 		{
       
   458 		iChildEntryIndex++;
       
   459 		if (iChildEntryIndex < iChildEntries->Count())
       
   460 			{
       
   461 			CheckCurrentEntryL();
       
   462 			}
       
   463 		}
       
   464 	}
       
   465 
       
   466 void CImMhtmlChildEntrySearcher::DoComplete(TInt& )
       
   467 	{
       
   468 
       
   469 	}
       
   470 
       
   471 /** 
       
   472 Search for a TMsvId entry in cache. If found there is no need to open 
       
   473 store to get content-location, content-id of that entry because cache contains that information
       
   474 @return index of the cache if cache contains URI else 0
       
   475 */
       
   476 TInt CImMhtmlChildEntrySearcher::CheckCacheForEntryId(TMsvId aId)
       
   477 {
       
   478 	TInt count = iUriCacheArray.Count();
       
   479 	if(count)
       
   480 		{
       
   481 		CImCacheUriEntry* cacheEntry = NULL;
       
   482 		for(TInt i=0; i < count; ++i)
       
   483 			{
       
   484 			cacheEntry = iUriCacheArray[i];
       
   485 			if(cacheEntry->GetUriEntry() == aId)
       
   486 			return i;
       
   487 			}
       
   488 		}
       
   489 	return KErrNotFound;
       
   490 }
       
   491 
       
   492 void CImMhtmlChildEntrySearcher::CheckCurrentEntryL()
       
   493 //Compares the search URI with the content-location and content-id fields of each child entry in cache if not found then
       
   494 // compares the search URI with the content-location and content-id fields of each child entry from store.
       
   495 // It sets iFound if either content field in the current entry matches the URI.
       
   496 	{
       
   497 	TInt index = CheckCacheForEntryId((*iChildEntries)[iChildEntryIndex]);
       
   498 	if( index != KErrNotFound )
       
   499 		{
       
   500 		CImCacheUriEntry* uriEntry = iUriCacheArray[index];
       
   501 		iFound = CheckContentDetailsL(uriEntry->GetContentLocation()->Des(),uriEntry->GetContentId()->Des());
       
   502 		}
       
   503 	else
       
   504 		{
       
   505 		iEntry.SetEntryL((*iChildEntries)[iChildEntryIndex]);
       
   506 		if (iEntry.HasStoreL() && (iEntry.Entry().iType != KUidMsvFolderEntry))
       
   507 			{
       
   508 			CMsvStore* entryStore = iEntry.ReadStoreL();
       
   509 			CleanupStack::PushL(entryStore);
       
   510 			// Get the content-location and content-id values for the current entry.
       
   511 			if (entryStore->IsPresentL(KUidMsgFileMimeHeader))
       
   512 				{
       
   513 				CImMimeHeader* mimeHeader = CImMimeHeader::NewLC();
       
   514 				mimeHeader->RestoreL(*entryStore);
       
   515 				TPtrC16 contentLocationPtr = mimeHeader->ContentLocation();
       
   516 				TPtrC8 contentIdPtr = mimeHeader->ContentID();
       
   517 				// Copy the 8 bit contentId string into a 16 bit wide descriptor.
       
   518 				TInt contentIdLength = contentIdPtr.Length();
       
   519 				HBufC* contentId = HBufC::NewL(contentIdLength);
       
   520 				CleanupStack::PushL(contentId);
       
   521 				TInt contentIdCopyCounter = 0;
       
   522 				TPtr copyOfContentId = contentId->Des();
       
   523 				for (contentIdCopyCounter = 0; contentIdCopyCounter < contentIdLength; contentIdCopyCounter++)
       
   524 					{
       
   525 					copyOfContentId.Append(contentIdPtr[contentIdCopyCounter]);
       
   526 					}
       
   527 
       
   528 				// Compare the content-location and content-id values to the search URI string. 
       
   529 				iFound = CheckContentDetailsL(contentLocationPtr, copyOfContentId);
       
   530 				//Add entry to cache. So that for each new URI lookup, first 
       
   531 				//look in the cache to see URI has been loaded during a previous lookup.
       
   532 				CImCacheUriEntry* uriEntry  = CImCacheUriEntry::NewL(contentLocationPtr,copyOfContentId,iEntry.EntryId());
       
   533 				if(iUriCacheArray.Append(uriEntry) != KErrNone)
       
   534 					{
       
   535 					delete uriEntry;
       
   536 					} 
       
   537 				CleanupStack::PopAndDestroy(2); // contentId, mimeHeader
       
   538 				}
       
   539 			CleanupStack::PopAndDestroy(); // entryStore
       
   540 			}
       
   541 		}
       
   542 	iStatus=KRequestPending;
       
   543 	SetActive();
       
   544 	TRequestStatus* status = &iStatus;
       
   545 	User::RequestComplete(status, KErrNone);
       
   546 	}
       
   547 
       
   548 
       
   549 TBool CImMhtmlChildEntrySearcher::CheckContentDetailsL(const TDesC& aContentLocation, const TDesC& aContentId)
       
   550 // Compare the URI to the given content-location and content-id
       
   551 	{
       
   552 	TBool matchFound = EFalse;
       
   553 
       
   554 	if ((iUri->Des()).CompareF(aContentLocation) == 0)
       
   555 		{
       
   556 		matchFound = ETrue;
       
   557 		}
       
   558 	else if ((iUri->Des()).CompareF(aContentId) == 0)
       
   559 		{
       
   560 		matchFound = ETrue;
       
   561 		}
       
   562 
       
   563 	return matchFound;
       
   564 	}
       
   565 
       
   566 CImMhtmlChildEntrySearcher::CImMhtmlChildEntrySearcher(CMsvEntry &aEntry, RPointerArray<CImCacheUriEntry>& aUriCacheUriArray) : CMsgActive(EPriorityStandard), iEntry(aEntry),	iUriCacheArray(aUriCacheUriArray)
       
   567 	{
       
   568 	}
       
   569 
       
   570 
       
   571 
       
   572 
       
   573 
       
   574 
       
   575 CImMhtmlFileFinder* CImMhtmlFileFinder::NewL(CMsvEntry& aEntry, RPointerArray<CImCacheUriEntry>& aUriCacheUriArray)
       
   576 	{
       
   577 	CImMhtmlFileFinder* self = new (ELeave) CImMhtmlFileFinder(aEntry);
       
   578 	CleanupStack::PushL(self);
       
   579 	self->ConstructL(aUriCacheUriArray);
       
   580 	CleanupStack::Pop(); // self
       
   581 	return self;
       
   582 	}
       
   583 
       
   584 void CImMhtmlFileFinder::FindL(const TDesC& aUri, TMsvId aBodyPartId, TBool aFileNameOnly,TRequestStatus &aStatus)
       
   585 // Recursively search the parent to find a match for the given content-ID or content-location.
       
   586 	{
       
   587 	Queue(aStatus);
       
   588 
       
   589 	delete iUri;
       
   590 	iUri = 0;
       
   591 	iUri = HBufC::NewL(aUri.Length());
       
   592 	(*iUri) = aUri;
       
   593 
       
   594 	iCurrentBodyPartId = aBodyPartId;
       
   595 	iMatchFound = EFalse;
       
   596 	
       
   597 	iFileNameOnly = aFileNameOnly;
       
   598 	DoFindL();
       
   599 	}
       
   600 
       
   601 void CImMhtmlFileFinder::DoFindL()
       
   602 	{
       
   603 	iCurrentEntry.SetEntryL(iCurrentBodyPartId);
       
   604 
       
   605 	TPtr uri = iUri->Des();
       
   606 	iChildEntrySearcher->StartL((iCurrentEntry.Entry()).Parent(), uri, iStatus);
       
   607 	SetActive();
       
   608 	}
       
   609 	
       
   610 void CImMhtmlFileFinder::Result(RFile& aFile, TMsvId& aEntryId) const
       
   611 	{
       
   612 	aFile= iFile;
       
   613 	iFile = RFile();
       
   614 	aEntryId = iLinkedEntryId;	
       
   615 	}
       
   616 
       
   617 void CImMhtmlFileFinder::Result(TFileName& aFileName, TMsvId& aEntryId) const
       
   618 	{
       
   619 	aFileName = iFileName;
       
   620 	aEntryId = iLinkedEntryId;
       
   621 	}
       
   622 
       
   623 TBool CImMhtmlFileFinder::MatchFound() const
       
   624 	{
       
   625 	return iMatchFound;
       
   626 	}
       
   627 
       
   628 CImMhtmlFileFinder::~CImMhtmlFileFinder()
       
   629 	{
       
   630 	iFile.Close();
       
   631 	delete iUri;
       
   632 	delete iChildEntrySearcher;
       
   633 	}
       
   634 
       
   635 CImMhtmlFileFinder::CImMhtmlFileFinder(CMsvEntry &aEntry) : CMsgActive(EPriorityStandard), iCurrentEntry(aEntry)
       
   636 	{
       
   637 
       
   638 	}
       
   639 
       
   640 
       
   641 void CImMhtmlFileFinder::ConstructL(RPointerArray<CImCacheUriEntry>& aUriCacheUriArray)
       
   642 	{
       
   643 	CActiveScheduler::Add(this);
       
   644 	iChildEntrySearcher = CImMhtmlChildEntrySearcher::NewL(iCurrentEntry, aUriCacheUriArray);
       
   645 	}
       
   646 
       
   647 void CImMhtmlFileFinder::DoRunL()
       
   648 	{
       
   649 	if (iStatus == KErrNone)
       
   650 		{
       
   651 		TMsvId matchingEntry;
       
   652 		iMatchFound = iChildEntrySearcher->SearchResult(matchingEntry);
       
   653 		if (!iMatchFound)
       
   654 			{
       
   655 			// If no match for the URI is found under the current entry then search the parent.
       
   656 			iCurrentEntry.SetEntryL(iCurrentBodyPartId);
       
   657 			iCurrentBodyPartId = iCurrentEntry.Entry().Parent();
       
   658 			DoFindL();
       
   659 			}
       
   660 		else
       
   661 			{
       
   662 			// If a match is found the set the result values.
       
   663 			iLinkedEntryId = matchingEntry;
       
   664 			iCurrentEntry.SetEntryL(iLinkedEntryId);
       
   665 			CMsvStore* store = iCurrentEntry.ReadStoreL();
       
   666 			CleanupStack::PushL(store);
       
   667 			MMsvAttachmentManager& attachmentMgr = store->AttachmentManagerL();
       
   668 			// emails have one attachment per attachment entry
       
   669 			if(attachmentMgr.AttachmentCount())
       
   670 				{
       
   671 				if(iFileNameOnly)
       
   672 					{
       
   673 					CMsvAttachment* attachment = attachmentMgr.GetAttachmentInfoL(0);
       
   674 					iFileName = attachment->FilePath();
       
   675 					delete attachment;
       
   676 					}
       
   677 				else 
       
   678 					{
       
   679 					iFile = attachmentMgr.GetAttachmentFileL(0);	
       
   680 					}		
       
   681 				}
       
   682 			CleanupStack::PopAndDestroy(store);
       
   683 
       
   684 			// Check that the file exists. If it doesn't then complete with an error.
       
   685 			if (!iCurrentEntry.Entry().Complete())
       
   686 				{
       
   687 				iStatus = KImcmHTMLPartNotPopulated;
       
   688 				}
       
   689 			}
       
   690 		}
       
   691 	}
       
   692 
       
   693 void CImMhtmlFileFinder::DoCancel()
       
   694 	{
       
   695 	iChildEntrySearcher->Cancel();
       
   696 	CMsgActive::DoCancel();
       
   697 	}
       
   698 
       
   699 void CImMhtmlFileFinder::DoComplete(TInt& aStatus)
       
   700 	{
       
   701 	if (iStatus == KImcmHTMLPartNotPopulated)
       
   702 		{
       
   703 		aStatus = KImcmHTMLPartNotPopulated;
       
   704 		}
       
   705 	else if (aStatus == KErrNotFound)
       
   706 		{
       
   707 		aStatus = KErrNone;
       
   708 		}
       
   709 	}
       
   710 
       
   711 
       
   712 
       
   713 
       
   714 
       
   715 
       
   716 CImMhtmlFirstPageFinder* CImMhtmlFirstPageFinder::NewL(CMsvEntry& aEntry)
       
   717 	{
       
   718 	CImMhtmlFirstPageFinder* self = new (ELeave) CImMhtmlFirstPageFinder(aEntry);
       
   719 	CleanupStack::PushL(self);
       
   720 	self->ConstructL();
       
   721 	CleanupStack::Pop();
       
   722 	return self;
       
   723 	}
       
   724 	
       
   725 void CImMhtmlFirstPageFinder::FindL(TMsvId aRootMessage,TBool aFileNameOnly, TRequestStatus& aStatus)
       
   726 // Find the first html part of the specified message.
       
   727 // Use the Id function to retrieve the result.
       
   728 	{
       
   729 	Queue(aStatus);
       
   730 
       
   731 	iNextUnrelatedEntryStack->Reset();
       
   732 	iRelatedDepthCounter = 0;
       
   733 
       
   734 	delete iEntryStack;
       
   735 	iEntryStack = 0;
       
   736 	iCurrentEntry.SetEntryL(aRootMessage);
       
   737 	iEntryStack = iCurrentEntry.ChildrenL();
       
   738 	TKeyArrayFix sortKey(0, ECmpTInt32);
       
   739 	iEntryStack->Sort(sortKey);
       
   740 
       
   741 	// The order of the list must be reversed because items are taken from the end.
       
   742 	TInt startCounter = 0;
       
   743 	TInt endCounter = iEntryStack->Count() - 1;
       
   744 	TMsvId savedId;
       
   745 	while (startCounter < endCounter)
       
   746 		{
       
   747 		savedId = (*iEntryStack)[startCounter];
       
   748 		(*iEntryStack)[startCounter] = (*iEntryStack)[endCounter];
       
   749 		(*iEntryStack)[endCounter] = savedId;
       
   750 		startCounter++;
       
   751 		endCounter--;
       
   752 		}
       
   753 
       
   754 	iHtmlPartFound = EFalse;
       
   755 	iUnrelatedHtmlPartFound = EFalse;
       
   756 
       
   757 	SetStartParameterL();
       
   758 
       
   759 	DoFindL();
       
   760 	iFileNameOnly = aFileNameOnly;
       
   761 	}
       
   762 
       
   763 void CImMhtmlFirstPageFinder::SetStartParameterL()
       
   764 	{
       
   765 	CMsvStore* store = NULL;
       
   766 	if(iCurrentEntry.HasStoreL())
       
   767 		{
       
   768 		store = iCurrentEntry.ReadStoreL();
       
   769 		CleanupStack::PushL(store);
       
   770 	
       
   771 		delete iStartParameter;
       
   772 		iStartParameter = 0;
       
   773 		if (store->IsPresentL(KUidMsgFileMimeHeader))
       
   774 			{
       
   775 			CImMimeHeader* mimeHeader = CImMimeHeader::NewLC();
       
   776 			TRAPD(err, mimeHeader->RestoreL(*store));
       
   777 			if (KErrNotFound == err)
       
   778 				{
       
   779 				err = KImcmInvalidMessageStructure;
       
   780 				}
       
   781 			User::LeaveIfError(err);
       
   782 			const CDesC8Array& contentTypeParams = mimeHeader->ContentTypeParams();
       
   783 			TInt startLength = ((TDesC&)KImMhtmlStartString).Length();
       
   784 			TInt compareResult = 1;
       
   785 			// Search for the start parameter.
       
   786 			TInt paramIndex = contentTypeParams.Count();
       
   787 			while ((paramIndex > 0) && (compareResult != 0))
       
   788 				{
       
   789 				paramIndex--;
       
   790 				compareResult = ((contentTypeParams[paramIndex]).Left(startLength)).CompareF(KImMhtmlStartString);
       
   791 				}
       
   792 
       
   793 			if (compareResult == 0)
       
   794 			// The 'start' parameter has been found, now the value needs to be extracted.
       
   795 				{
       
   796 				TPtrC8 startValue = contentTypeParams[paramIndex].Right(contentTypeParams[paramIndex].Length() - startLength);
       
   797 				
       
   798 				// Remove any leading whitespace and a single '=' character.
       
   799 				TBool equalsFound = EFalse;
       
   800 				TBool firstValueCharacterFound = EFalse;
       
   801 				while ((startValue.Length() > 0) && (!firstValueCharacterFound))
       
   802 					{
       
   803 					if ((startValue[0] == '=') && (!equalsFound))
       
   804 						{
       
   805 						equalsFound = ETrue;
       
   806 						startValue.Set(startValue.Right(startValue.Length() - 1));
       
   807 						}
       
   808 					else if (startValue[0] == ' ')
       
   809 						{
       
   810 						startValue.Set(startValue.Right(startValue.Length() - 1));
       
   811 						}
       
   812 					else
       
   813 						{
       
   814 						firstValueCharacterFound = ETrue;
       
   815 						}
       
   816 					}
       
   817 
       
   818 				// Remove the quotes if they exist.
       
   819 				if (startValue.Length() > 1)
       
   820 					{
       
   821 					if ((startValue[0] == '"') && (startValue[startValue.Length() - 1] == '"'))
       
   822 						{
       
   823 						startValue.Set(startValue.Mid(1, startValue.Length() - 2));
       
   824 						}
       
   825 					}
       
   826 
       
   827 				// Keep a copy of the unquoted start parameter.
       
   828 				delete iStartParameter;
       
   829 				iStartParameter = 0;
       
   830 				iStartParameter = HBufC8::NewL(startValue.Length());
       
   831 				(*iStartParameter) = startValue;
       
   832 				}
       
   833 			CleanupStack::PopAndDestroy(); // mimeHeader
       
   834 			}
       
   835 		CleanupStack::PopAndDestroy(); // store
       
   836 		}
       
   837 		else
       
   838 		{
       
   839 			iStatus=KErrNotFound;		
       
   840 		}
       
   841 	}
       
   842 
       
   843 void CImMhtmlFirstPageFinder::DoFindL()
       
   844 	{
       
   845 	// Get the entry details from the item at the head of the stack.
       
   846 	if (iEntryStack->Count() > 0)
       
   847 		{
       
   848 		iCurrentEntry.SetEntryL((*iEntryStack)[iEntryStack->Count() - 1] );
       
   849 
       
   850 		// Check if the current entry is at the top of the unrelated stack
       
   851 		// If it is then we are no longer under the related structure.
       
   852 		if (iNextUnrelatedEntryStack->Count() != 0)
       
   853 			{
       
   854 			if (iCurrentEntry.Entry().Id() == (*iNextUnrelatedEntryStack)[iNextUnrelatedEntryStack->Count() - 1])
       
   855 				{
       
   856 				iRelatedDepthCounter--;
       
   857 				iNextUnrelatedEntryStack->ResizeL(iNextUnrelatedEntryStack->Count() - 1);
       
   858 				}				
       
   859 			}
       
   860 
       
   861 		// Pop the entry from the stack.
       
   862 		iEntryStack->ResizeL(iEntryStack->Count() - 1);
       
   863 
       
   864 		// If the current entry is a related type then increase the related depth counter
       
   865 		// We need to know if we are under a related entry in order to recognise the first HTML part
       
   866 
       
   867 		TUid entryType = iCurrentEntry.Entry().iType;
       
   868 		if (EFolderTypeRelated == ((TMsvEmailEntry)iCurrentEntry.Entry()).MessageFolderType())
       
   869 			{
       
   870 			iRelatedDepthCounter++;
       
   871 			if (iEntryStack->Count() != 0)
       
   872 				{
       
   873 				iNextUnrelatedEntryStack->AppendL((*iEntryStack)[iEntryStack->Count() - 1]);
       
   874 				}
       
   875 			}
       
   876 
       
   877 		if (KUidMsvEmailHtmlEntry == entryType)
       
   878 			{
       
   879 			if (iStartParameter != 0)
       
   880 				{
       
   881 				CMsvStore* store = iCurrentEntry.ReadStoreL();
       
   882 				CleanupStack::PushL(store);
       
   883 				if (store->IsPresentL(KUidMsgFileMimeHeader))
       
   884 					{
       
   885 					CImMimeHeader* mimeHeader = CImMimeHeader::NewLC();
       
   886 					mimeHeader->RestoreL(*store);
       
   887 					TPtrC8 contentId = mimeHeader->ContentID();
       
   888 					if ((iStartParameter->Des()).CompareF(contentId) == 0)
       
   889 						// If the start parameter matches the content-id then the first HTML part
       
   890 						// has been found.
       
   891 						{
       
   892 						iHtmlPartFound = ETrue;
       
   893 						iFirstHtmlPartId = iCurrentEntry.Entry().Id();
       
   894 						}
       
   895 					CleanupStack::PopAndDestroy(); // mimeHeader
       
   896 					}
       
   897 				CleanupStack::PopAndDestroy(); // store
       
   898 				}
       
   899 			else
       
   900 				{
       
   901 				if (iRelatedDepthCounter > 0)
       
   902 					// This entry is under a related structure (either directly or indirectly)
       
   903 					// so it is the one we are after.
       
   904 					// HTML parts that are not under a related structure are normal attachments
       
   905 					// and NOT part of an MHTML message.
       
   906 					{
       
   907 					iHtmlPartFound = ETrue;
       
   908 					iFirstHtmlPartId = iCurrentEntry.Entry().Id();
       
   909 					}
       
   910 				else
       
   911 					{
       
   912 					if ((!iHtmlPartFound) && (!iUnrelatedHtmlPartFound))
       
   913 						{
       
   914 						iUnrelatedHtmlPartFound = ETrue;
       
   915 						iFirstUnrelatedHtmlPartId = iCurrentEntry.Entry().Id();
       
   916 						}
       
   917 					}
       
   918 				}
       
   919 			}
       
   920 
       
   921 		if (KUidMsvFolderEntry == entryType)
       
   922 			{
       
   923 			// Push the sorted child items on to the stack.
       
   924 			CMsvEntrySelection* childEntries = iCurrentEntry.ChildrenL();
       
   925 			CleanupStack::PushL(childEntries);
       
   926 			TKeyArrayFix sortKey(0, ECmpTInt32);
       
   927 			childEntries->Sort(sortKey);
       
   928 
       
   929 			// The entries need to be added in reverse order because they are retrieved from a stack.
       
   930 			TInt childEntriesCounter = childEntries->Count();
       
   931 			while (childEntriesCounter > 0)
       
   932 				{
       
   933 				childEntriesCounter--;
       
   934  				// Ignore any entries that weren't folders or HTML entries.
       
   935  				if ((iCurrentEntry.ChildDataL((*childEntries)[childEntriesCounter]).iType == KUidMsvFolderEntry)
       
   936  					|| (iCurrentEntry.ChildDataL((*childEntries)[childEntriesCounter]).iType == KUidMsvEmailHtmlEntry))
       
   937  					{
       
   938  					iEntryStack->AppendL((*childEntries)[childEntriesCounter]);
       
   939  					}
       
   940   				}
       
   941 			CleanupStack::PopAndDestroy(childEntries); 
       
   942 			}
       
   943 
       
   944 		}
       
   945 
       
   946 	TRequestStatus* status = &iStatus;
       
   947 	iStatus=KRequestPending;
       
   948 	SetActive();
       
   949 	if ((!iCurrentEntry.Entry().Complete()) && (iHtmlPartFound))
       
   950 		{
       
   951 		User::RequestComplete(status, KImcmHTMLPartNotPopulated);
       
   952 		}
       
   953 	else
       
   954 		{
       
   955 		User::RequestComplete(status, KErrNone);
       
   956 		}
       
   957 	}
       
   958 
       
   959 void CImMhtmlFirstPageFinder::Result(RFile& aFile, TMsvId& aEntryId) const
       
   960 	{
       
   961 	aFile = iFile;
       
   962 	iFile = RFile();
       
   963 	aEntryId = iFirstHtmlPartId;	
       
   964 	}
       
   965 
       
   966 void CImMhtmlFirstPageFinder::Result(TFileName& aFileName, TMsvId& aEntryId) const
       
   967 	{
       
   968 	aFileName = iFileName;
       
   969 	aEntryId = iFirstHtmlPartId;	
       
   970 	}
       
   971 
       
   972 CImMhtmlFirstPageFinder::~CImMhtmlFirstPageFinder()
       
   973 	{
       
   974 	iFile.Close();
       
   975 	delete iEntryStack;
       
   976 	delete iStartParameter;
       
   977 	delete iNextUnrelatedEntryStack;
       
   978 	}
       
   979 
       
   980 CImMhtmlFirstPageFinder::CImMhtmlFirstPageFinder(CMsvEntry& aEntry) : CMsgActive(EPriorityStandard), iCurrentEntry(aEntry)
       
   981 	{
       
   982 	}
       
   983 
       
   984 void CImMhtmlFirstPageFinder::ConstructL()
       
   985 	{
       
   986 	CActiveScheduler::Add(this);
       
   987 	iNextUnrelatedEntryStack = new (ELeave) CMsvEntrySelection;
       
   988 	}
       
   989 
       
   990 void CImMhtmlFirstPageFinder::DoRunL()
       
   991 	{
       
   992 	// We are done if we could not find the parent structure, or if we have found an HTML part.
       
   993 	if (iStatus == KErrNone)
       
   994 		{
       
   995 		if ((iEntryStack->Count() != 0) && (!iHtmlPartFound))
       
   996 			{
       
   997 			DoFindL();
       
   998 			}
       
   999 		else
       
  1000 			{
       
  1001 			if (iUnrelatedHtmlPartFound)
       
  1002 				{
       
  1003 				iHtmlPartFound = ETrue;
       
  1004 				iFirstHtmlPartId = iFirstUnrelatedHtmlPartId;
       
  1005 				}
       
  1006 			}
       
  1007 		}
       
  1008 
       
  1009 	if (iHtmlPartFound && !IsActive())
       
  1010 		{
       
  1011 		iCurrentEntry.SetEntryL(iFirstHtmlPartId);
       
  1012 		CMsvStore* store = iCurrentEntry.ReadStoreL();
       
  1013 		CleanupStack::PushL(store);
       
  1014 		MMsvAttachmentManager& attachmentMgr = store->AttachmentManagerL();
       
  1015 		// get the file handle to pass it to clients who request for it using
       
  1016 		// function CImEmailMessage::GetUniversalResourceIdentifierL()
       
  1017 		if(attachmentMgr.AttachmentCount())
       
  1018 			{
       
  1019 			if(iFileNameOnly)
       
  1020 				{
       
  1021 				CMsvAttachment* attachment = attachmentMgr.GetAttachmentInfoL(0);
       
  1022 				iFileName = attachment->FilePath();
       
  1023 				delete attachment;
       
  1024 				}
       
  1025 			else 
       
  1026 				{
       
  1027 				iFile = attachmentMgr.GetAttachmentFileL(0);	
       
  1028 				}	
       
  1029 			}
       
  1030 		CleanupStack::PopAndDestroy(store); 
       
  1031 		}
       
  1032 	}
       
  1033 
       
  1034 void CImMhtmlFirstPageFinder::DoComplete(TInt& aStatus)
       
  1035 	{
       
  1036 	if (!iHtmlPartFound)
       
  1037 		{
       
  1038 		aStatus = KErrNotFound;
       
  1039 		}
       
  1040 	else
       
  1041 		{
       
  1042 		aStatus = KErrNone;
       
  1043 		}
       
  1044 	}
       
  1045 
       
  1046 
       
  1047 
       
  1048 
       
  1049 // The following class implements a class for parsing and combining URI's.
       
  1050 // See RFC 1808 for more details.
       
  1051 
       
  1052 CImMhtmlUri* CImMhtmlUri::NewL(const TDesC& aUriText)
       
  1053 	{
       
  1054 	CImMhtmlUri* self = NewLC(aUriText);
       
  1055 	CleanupStack::Pop(); // self
       
  1056 	return self;
       
  1057 	}
       
  1058 
       
  1059 CImMhtmlUri* CImMhtmlUri::NewLC(const TDesC& aUriText)
       
  1060 	{
       
  1061 	CImMhtmlUri* self = new (ELeave) CImMhtmlUri();
       
  1062 	CleanupStack::PushL(self);
       
  1063 	self->ConstructL(aUriText);
       
  1064 	return self;
       
  1065 	}
       
  1066 
       
  1067 void CImMhtmlUri::ConstructL(const TDesC& aUriText)
       
  1068 	{
       
  1069 	iUriText = HBufC::NewL(aUriText.Length());
       
  1070 	(*iUriText) = aUriText;
       
  1071 	iDirectoryPath = new (ELeave) CDesCArrayFlat(8);
       
  1072 	ParseL();
       
  1073 	}
       
  1074 
       
  1075 void CImMhtmlUri::MakeAbsoluteL(const CImMhtmlUri& aBaseUri)
       
  1076 	{
       
  1077 	TBool done = EFalse;
       
  1078 	
       
  1079 	if (iScheme == 0)
       
  1080 		{
       
  1081 		if (aBaseUri.iScheme)
       
  1082 			{
       
  1083 			iScheme = HBufC::NewL(aBaseUri.iScheme->Length());
       
  1084 			(*iScheme) = aBaseUri.iScheme->Des();
       
  1085 			}
       
  1086 		}
       
  1087 	else
       
  1088 		{
       
  1089 		done = ETrue;
       
  1090 		}
       
  1091 	
       
  1092 	if ((iNetLoc == 0) && (!done))
       
  1093 		{
       
  1094 		if (aBaseUri.iNetLoc)
       
  1095 			{
       
  1096 			iNetLoc = HBufC::NewL(aBaseUri.iNetLoc->Length());
       
  1097 			(*iNetLoc) = aBaseUri.iNetLoc->Des();
       
  1098 			}
       
  1099 		}
       
  1100 	else
       
  1101 		{
       
  1102 		done = ETrue;
       
  1103 		}
       
  1104 
       
  1105 	if ((!iAbsolutePath) && (!done))
       
  1106 		{
       
  1107 		// Try to add any directories from the base before hand.
       
  1108 		TInt count = aBaseUri.iDirectoryPath->Count();
       
  1109 
       
  1110 		if (iDirectoryPath->Count() != 0)
       
  1111 			{
       
  1112 			done = ETrue;
       
  1113 			if (aBaseUri.iContainsFileName)
       
  1114 				{
       
  1115 				count--;
       
  1116 				}
       
  1117 			}
       
  1118 		else
       
  1119 			{
       
  1120 			iContainsFileName = aBaseUri.iContainsFileName;
       
  1121 			}
       
  1122 
       
  1123 		while (count > 0)
       
  1124 			{
       
  1125 			count--;
       
  1126 			iDirectoryPath->InsertL(0, (*(aBaseUri.iDirectoryPath))[count]);
       
  1127 			}
       
  1128 		}
       
  1129 	else
       
  1130 		{
       
  1131 		done = ETrue;
       
  1132 		}
       
  1133 
       
  1134 	if ((iParameters == 0) && (!done))
       
  1135 		{
       
  1136 		if (aBaseUri.iParameters)
       
  1137 			{
       
  1138 			iParameters = HBufC::NewL(aBaseUri.iParameters->Length());
       
  1139 			(*iParameters) = aBaseUri.iParameters->Des();
       
  1140 			}
       
  1141 		}
       
  1142 	else
       
  1143 		{
       
  1144 		done = ETrue;
       
  1145 		}
       
  1146 
       
  1147 	if ((iQuery == 0) && (!done))
       
  1148 		{
       
  1149 		if (aBaseUri.iQuery)
       
  1150 			{
       
  1151 			iQuery = HBufC::NewL(aBaseUri.iQuery->Length());
       
  1152 			(*iQuery) = aBaseUri.iQuery->Des();
       
  1153 			}
       
  1154 		}
       
  1155 	else
       
  1156 		{
       
  1157 		done = ETrue;
       
  1158 		}
       
  1159 
       
  1160 	if ((iFragment == 0) && (!done))
       
  1161 		{
       
  1162 		if (aBaseUri.iFragment)
       
  1163 			{
       
  1164 			iFragment = HBufC::NewL(aBaseUri.iFragment->Length());
       
  1165 			(*iFragment) = aBaseUri.iFragment->Des();
       
  1166 			}
       
  1167 		}
       
  1168 
       
  1169 	Normalise();
       
  1170 	}
       
  1171 
       
  1172 HBufC* CImMhtmlUri::TextL(TBool aIncludeScheme)
       
  1173 	{
       
  1174 	// First calculate the size of the required HBufC
       
  1175 	TInt length = 0;
       
  1176 	
       
  1177 	if ((iScheme) && (aIncludeScheme))
       
  1178 		{
       
  1179 		length += (iScheme->Des()).Length() + 1;
       
  1180 		}
       
  1181 
       
  1182 	if (iNetLoc)
       
  1183 		{
       
  1184 		length += (iNetLoc->Des()).Length() + 2;
       
  1185 		}
       
  1186 
       
  1187 	if (iParameters)
       
  1188 		{
       
  1189 		length += (iParameters->Des()).Length() + 1;
       
  1190 		}
       
  1191 
       
  1192 	if (iQuery)
       
  1193 		{
       
  1194 		length += (iQuery->Des()).Length() + 1;
       
  1195 		}
       
  1196 
       
  1197 	if (iFragment)
       
  1198 		{
       
  1199 		length += (iFragment->Des()).Length() + 1;
       
  1200 		}
       
  1201 
       
  1202 	if (iDirectoryPath != 0)
       
  1203 		{
       
  1204 		TInt counter = iDirectoryPath->Count();
       
  1205 		while (counter > 0)
       
  1206 			{
       
  1207 			counter--;
       
  1208 			length += ((*iDirectoryPath)[counter]).Length();
       
  1209 			length++;
       
  1210 			}
       
  1211 		}
       
  1212 
       
  1213 	if (iAbsolutePath != 0)
       
  1214 		{
       
  1215 		length++;
       
  1216 		}
       
  1217 
       
  1218 	if (!iContainsFileName)
       
  1219 		{
       
  1220 		length++;
       
  1221 		}
       
  1222 
       
  1223 	HBufC* text = HBufC::NewL(length);
       
  1224 
       
  1225 	if ((iScheme) && (aIncludeScheme))
       
  1226 		{
       
  1227 		(text->Des()).Append(iScheme->Des());
       
  1228 		(text->Des()).Append(TChar(':'));
       
  1229 		}
       
  1230 
       
  1231 	if (iNetLoc)
       
  1232 		{
       
  1233 		(text->Des()).Append(TChar('/'));
       
  1234 		(text->Des()).Append(TChar('/'));
       
  1235 		(text->Des()).Append(iNetLoc->Des());
       
  1236 		}
       
  1237 
       
  1238 	if( iDirectoryPath != 0 )
       
  1239 		{
       
  1240 		if (((iAbsolutePath) || (iNetLoc)) && (iDirectoryPath->Count()))
       
  1241 			{
       
  1242 			(text->Des()).Append(TChar('/'));
       
  1243 			}
       
  1244 
       
  1245 		TInt counter = 0;
       
  1246 		TInt count = iDirectoryPath->Count();
       
  1247 		while (counter < count)
       
  1248 			{
       
  1249 			(text->Des()).Append((*iDirectoryPath)[counter]);
       
  1250 
       
  1251 			counter++;
       
  1252 
       
  1253 			if ((counter < count) || (!iContainsFileName))
       
  1254 				{
       
  1255 				(text->Des()).Append(TChar('/'));
       
  1256 				}
       
  1257 			}
       
  1258 		}
       
  1259 
       
  1260 	if (iParameters)
       
  1261 		{
       
  1262 		(text->Des()).Append(TChar(';'));
       
  1263 		(text->Des()).Append(iParameters->Des());
       
  1264 		}
       
  1265 
       
  1266 	if (iQuery)
       
  1267 		{
       
  1268 		(text->Des()).Append(TChar('?'));
       
  1269 		(text->Des()).Append(iQuery->Des());
       
  1270 		}
       
  1271 
       
  1272 	if (iFragment)
       
  1273 		{
       
  1274 		(text->Des()).Append(TChar('#'));
       
  1275 		(text->Des()).Append(iFragment->Des());
       
  1276 		}
       
  1277 
       
  1278 	return text;
       
  1279 	}
       
  1280 
       
  1281 
       
  1282 TBool CImMhtmlUri::IsAbsolute() const
       
  1283 	{
       
  1284 	return (iScheme == 0) ? EFalse : ETrue;
       
  1285 	}
       
  1286 
       
  1287 
       
  1288 TBool CImMhtmlUri::CompareScheme(const TDesC& aScheme) const
       
  1289 // Returns ETrue if the given descriptor matches the scheme of this URI, returns EFalse otherwise.
       
  1290 	{
       
  1291 	if (iScheme)
       
  1292 		{
       
  1293 		return (aScheme.CompareF(iScheme->Des()) == 0);
       
  1294 		}
       
  1295 	else
       
  1296 		{
       
  1297 		return EFalse;
       
  1298 		}
       
  1299 	}
       
  1300 
       
  1301 
       
  1302 HBufC* CImMhtmlUri::OriginalUriText()
       
  1303 	{
       
  1304 	return iUriText;
       
  1305 	}
       
  1306 
       
  1307 
       
  1308 CImMhtmlUri::~CImMhtmlUri()
       
  1309 	{
       
  1310 	delete iDirectoryPath;
       
  1311 
       
  1312 	delete iUriText;
       
  1313 	delete iScheme;
       
  1314 	delete iNetLoc;
       
  1315 	delete iParameters;
       
  1316 	delete iQuery;
       
  1317 	delete iFragment;
       
  1318 	}
       
  1319 
       
  1320 CImMhtmlUri::CImMhtmlUri()
       
  1321 	{
       
  1322 
       
  1323 	}
       
  1324 
       
  1325 void CImMhtmlUri::ParseL()
       
  1326 	{
       
  1327 	TInt textIndex = 0;
       
  1328 	TInt textCount = iUriText->Length();
       
  1329 
       
  1330 	TInt stringStart = 0;
       
  1331 	TInt stringLength = 0;
       
  1332 	TImUriDelimiterType delimiterType;
       
  1333 
       
  1334 	iState = EParsingFirstString;
       
  1335 
       
  1336 	while (textIndex <= textCount)
       
  1337 		{
       
  1338 		delimiterType = Delimiter(textIndex);
       
  1339 
       
  1340 		if (EImUriNotDelimiter != delimiterType)
       
  1341 			{
       
  1342 			switch (iState)
       
  1343 				{
       
  1344 				case EParsingFirstString:
       
  1345 					switch(delimiterType)
       
  1346 						{
       
  1347 						case EImUriScheme:
       
  1348 							if (stringLength)
       
  1349 								{
       
  1350 								delete iScheme;
       
  1351 								iScheme = NULL;
       
  1352 								iScheme = HBufC::NewL(stringLength);
       
  1353 								(*iScheme) = iUriText->Mid(stringStart, stringLength);
       
  1354 								}
       
  1355 							ChangeState(delimiterType);
       
  1356 							break;
       
  1357 						case EImUriPath:
       
  1358 							if ((0 == stringLength)
       
  1359 								&& (0 == stringStart))
       
  1360 								{
       
  1361 								iAbsolutePath = ETrue;
       
  1362 								}
       
  1363 						case EImUriParameter:
       
  1364 						case EImUriQuery:
       
  1365 						case EImUriFragment:
       
  1366 						case EImUriEnd:
       
  1367 							if (stringLength)
       
  1368 								{
       
  1369 								iDirectoryPath->AppendL(iUriText->Mid(stringStart, stringLength));
       
  1370 								iContainsFileName = (EImUriPath != delimiterType);
       
  1371 								}
       
  1372 							ChangeState(delimiterType);
       
  1373 							break;
       
  1374 						case EImUriNetLoc:
       
  1375 							stringLength = 0;
       
  1376 							stringStart = 0;
       
  1377 							ChangeState(delimiterType);
       
  1378 						default:
       
  1379 							break;
       
  1380 						};
       
  1381 					break;
       
  1382 				case EParsingScheme:
       
  1383 					if (stringLength)
       
  1384 						{
       
  1385 						delete iScheme;
       
  1386 						iScheme = NULL;
       
  1387 						iScheme = HBufC::NewL(stringLength);
       
  1388 						(*iScheme) = iUriText->Mid(stringStart, stringLength);
       
  1389 						}
       
  1390 					ChangeState(delimiterType);
       
  1391 					break;
       
  1392 				case EParsingNetLoc:
       
  1393 					if (stringLength)
       
  1394 						{
       
  1395 						delete iNetLoc;
       
  1396 						iNetLoc = NULL;
       
  1397 						iNetLoc = HBufC::NewL(stringLength);
       
  1398 						(*iNetLoc) = iUriText->Mid(stringStart, stringLength);
       
  1399 						}
       
  1400 					ChangeState(delimiterType);
       
  1401 					break;
       
  1402 				case EParsingPath:
       
  1403 					if (stringLength)
       
  1404 						{
       
  1405 						iDirectoryPath->AppendL(iUriText->Mid(stringStart, stringLength));
       
  1406 						}
       
  1407 					if ((delimiterType!=EImUriPath) && (stringLength != 0))
       
  1408 						{
       
  1409 						iContainsFileName = ETrue;
       
  1410 						}
       
  1411 					ChangeState(delimiterType);
       
  1412 					break;
       
  1413 				case EParsingParameter:
       
  1414 					if (stringLength)
       
  1415 						{
       
  1416 						// If more than one parameters are there
       
  1417 						if(iParameters)
       
  1418 							{
       
  1419 							TInt previousParameterLength = (iParameters->Des()).Length() + 1;
       
  1420 							iParameters = iParameters->ReAlloc(previousParameterLength + stringLength);
       
  1421 							//Append ";" between the parameters
       
  1422 							(iParameters->Des()).Append(TChar(';'));
       
  1423 							HBufC* tempParameter = HBufC::NewL(stringLength);
       
  1424 							*tempParameter = iUriText->Mid(stringStart, stringLength);
       
  1425 							(iParameters->Des()).Append(tempParameter->Des());
       
  1426 							delete tempParameter;
       
  1427 							}
       
  1428 						// If all the parameters has been processed or only one parameter element
       
  1429 						else
       
  1430 							{
       
  1431 							iParameters = HBufC::NewL(stringLength);
       
  1432 							(*iParameters) = iUriText->Mid(stringStart, stringLength);
       
  1433 							}
       
  1434 						}
       
  1435 					ChangeState(delimiterType);
       
  1436 					break;
       
  1437 				case EParsingQuery:
       
  1438 					if (stringLength)
       
  1439 						{
       
  1440 						delete iQuery;
       
  1441 						iQuery = NULL;
       
  1442 						iQuery = HBufC::NewL(stringLength);
       
  1443 						(*iQuery) = iUriText->Mid(stringStart, stringLength);
       
  1444 						}
       
  1445 					ChangeState(delimiterType);
       
  1446 					break;
       
  1447 				case EParsingFragment:
       
  1448 					if (stringLength)
       
  1449 						{
       
  1450 						delete iFragment;
       
  1451 						iFragment = NULL;
       
  1452 						iFragment = HBufC::NewL(stringLength);
       
  1453 						(*iFragment) = iUriText->Mid(stringStart, stringLength);
       
  1454 						}
       
  1455 					ChangeState(delimiterType);
       
  1456 					break;
       
  1457 				}
       
  1458 
       
  1459 			stringStart = textIndex + 1;
       
  1460 			stringLength = 0;
       
  1461 			}
       
  1462 		else
       
  1463 			{
       
  1464 			stringLength++;
       
  1465 			}
       
  1466 
       
  1467 		textIndex++;
       
  1468 		}
       
  1469 	}
       
  1470 
       
  1471 void CImMhtmlUri::Normalise()
       
  1472 	{
       
  1473 	_LIT(KImSinglePeriod, ".");
       
  1474 	_LIT(KImDoublePeriod, "..");
       
  1475 
       
  1476 	// Remove any single '.' character at the end of the path as this will have replaced a file name if it were present.
       
  1477 	if (iDirectoryPath->Count() != 0)
       
  1478 		{
       
  1479 		if ((*iDirectoryPath)[iDirectoryPath->Count() - 1] == KImSinglePeriod)
       
  1480 			{
       
  1481 			// Remove the filename.
       
  1482 			iContainsFileName = EFalse;
       
  1483 			iDirectoryPath->Delete(iDirectoryPath->Count() - 1);
       
  1484 			}
       
  1485 		}
       
  1486 
       
  1487 
       
  1488 	TBool directoryRemoved = ETrue;
       
  1489 	TInt count;
       
  1490 	TInt counter;
       
  1491 	while (directoryRemoved)
       
  1492 		{
       
  1493 		directoryRemoved = EFalse;
       
  1494 		count = iDirectoryPath->Count();
       
  1495 		counter = 0;
       
  1496 		while ((counter < count) && (!directoryRemoved))
       
  1497 			{
       
  1498 			if ((*iDirectoryPath)[counter] == KImDoublePeriod)
       
  1499 				{
       
  1500 				if (counter > 0)
       
  1501 					{
       
  1502 					directoryRemoved = ETrue;
       
  1503 					iDirectoryPath->Delete(counter - 1, 2);
       
  1504 					if (counter == count - 1)
       
  1505 						{
       
  1506 						iContainsFileName = EFalse;
       
  1507 						}
       
  1508 					}
       
  1509 				}
       
  1510 			else if ((*iDirectoryPath)[counter] == KImSinglePeriod)
       
  1511 				{
       
  1512 				iDirectoryPath->Delete(counter);
       
  1513 				directoryRemoved = ETrue;
       
  1514 				}
       
  1515 			counter++;
       
  1516 			}
       
  1517 		}
       
  1518 	}
       
  1519 
       
  1520 CImMhtmlUri::TImUriDelimiterType CImMhtmlUri::Delimiter(TInt& aIndex)
       
  1521 	{
       
  1522 	TImUriDelimiterType delimiterType = EImUriNotDelimiter;
       
  1523 
       
  1524 	if (aIndex >= iUriText->Length())
       
  1525 		{
       
  1526 		return EImUriEnd;
       
  1527 		}
       
  1528 
       
  1529 	TChar currentCharacter = (*iUriText)[aIndex];
       
  1530 
       
  1531 	if ((iState == EParsingFirstString)
       
  1532 		&& (TChar(':') == currentCharacter))
       
  1533 		{
       
  1534 		return EImUriScheme;
       
  1535 		}
       
  1536 
       
  1537 	if (((iState == EParsingFirstString)
       
  1538 		|| (iState == EParsingNetLoc)
       
  1539 		|| (iState == EParsingPath))
       
  1540 		&& (TChar('/') == currentCharacter))
       
  1541 		{
       
  1542 		// Path or NetLoc, so check the next character if there is one.
       
  1543 		if (aIndex + 1 < iUriText->Length())
       
  1544 			{
       
  1545 			if (TChar('/') == TChar((*iUriText)[aIndex+1]))
       
  1546 				{
       
  1547 				aIndex++;
       
  1548 				return EImUriNetLoc;
       
  1549 				}
       
  1550 			else
       
  1551 				{
       
  1552 				return EImUriPath;
       
  1553 				}
       
  1554 			}
       
  1555 		else
       
  1556 			{
       
  1557 			return EImUriPath;
       
  1558 			}
       
  1559 		}
       
  1560 
       
  1561 	if ((iState != EParsingQuery)
       
  1562 		&& (iState != EParsingFragment)
       
  1563 		&& (TChar(';') == currentCharacter))
       
  1564 		{
       
  1565 		return EImUriParameter;
       
  1566 		}
       
  1567 
       
  1568 	if ((iState != EParsingFragment)
       
  1569 		&& (TChar('?') == currentCharacter))
       
  1570 		{
       
  1571 		return EImUriQuery;
       
  1572 		}
       
  1573 
       
  1574 	if (TChar('#') == currentCharacter)
       
  1575 		{
       
  1576 		return EImUriFragment;
       
  1577 		}
       
  1578 
       
  1579 	return delimiterType;
       
  1580 	}
       
  1581 
       
  1582 
       
  1583 void CImMhtmlUri::ChangeState(TImUriDelimiterType aDelimiterType)
       
  1584 	{
       
  1585 	switch (aDelimiterType)
       
  1586 		{
       
  1587 		case EImUriScheme:
       
  1588 			iState = EParsingFirstString;
       
  1589 			break;
       
  1590 		case EImUriNetLoc:
       
  1591 			iState = EParsingNetLoc;
       
  1592 			break;
       
  1593 		case EImUriPath:
       
  1594 			iState = EParsingPath;
       
  1595 			break;
       
  1596 		case EImUriParameter:
       
  1597 			iState = EParsingParameter;
       
  1598 			break;
       
  1599 		case EImUriQuery:
       
  1600 			iState = EParsingQuery;
       
  1601 			break;
       
  1602 		case EImUriFragment:
       
  1603 			iState = EParsingFragment;
       
  1604 			break;
       
  1605 		case EImUriEnd:
       
  1606 			iState = EParsingFirstString;
       
  1607 			break;
       
  1608 		default:
       
  1609 			break;
       
  1610 		}
       
  1611 	}
       
  1612 
       
  1613 //CImCacheUriEntry
       
  1614 CImCacheUriEntry* CImCacheUriEntry::NewL(const TDesC& aContentLocation, const TDesC& aContentId,TMsvId aEntry)
       
  1615 	{
       
  1616 	CImCacheUriEntry* self = new (ELeave) CImCacheUriEntry();
       
  1617 	CleanupStack::PushL(self);
       
  1618 	self->ConstructL(aContentLocation,aContentId,aEntry);
       
  1619 	CleanupStack::Pop();
       
  1620 	return self;
       
  1621 	}
       
  1622 	
       
  1623 void CImCacheUriEntry::ConstructL(const TDesC& aContentLocation, const TDesC& aContentId,TMsvId aEntry)
       
  1624 	{
       
  1625 	iContentLocation = aContentLocation.AllocL();
       
  1626 	iContentId = aContentId.AllocL();
       
  1627 	iUriEntry = aEntry;
       
  1628 	}
       
  1629 /**
       
  1630 Constructor
       
  1631 */
       
  1632 CImCacheUriEntry::CImCacheUriEntry()
       
  1633 	{
       
  1634 	}
       
  1635 /**
       
  1636 Destructor
       
  1637 */
       
  1638 CImCacheUriEntry::~CImCacheUriEntry()
       
  1639 	{
       
  1640 	delete iContentLocation;
       
  1641 	delete iContentId;
       
  1642 	}
       
  1643 /**
       
  1644 @return URI Contentlocation
       
  1645 */
       
  1646 HBufC* CImCacheUriEntry::GetContentLocation()
       
  1647 	{
       
  1648 	return (iContentLocation);
       
  1649 	}
       
  1650 /**
       
  1651 @return ContentId
       
  1652 */
       
  1653 HBufC* CImCacheUriEntry::GetContentId()
       
  1654 	{
       
  1655 	return (iContentId);
       
  1656 	}
       
  1657 /**
       
  1658 @return URI Entry Id
       
  1659 */
       
  1660 TMsvId CImCacheUriEntry::GetUriEntry()
       
  1661 	{
       
  1662 	return iUriEntry;
       
  1663 	}