--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/email/pop3andsmtpmtm/clientmtms/src/MIUTRSLV.CPP Thu Dec 17 08:44:11 2009 +0200
@@ -0,0 +1,1663 @@
+// Copyright (c) 1999-2009 Nokia Corporation and/or its subsidiary(-ies).
+// All rights reserved.
+// This component and the accompanying materials are made available
+// under the terms of "Eclipse Public License v1.0"
+// which accompanies this distribution, and is available
+// at the URL "http://www.eclipse.org/legal/epl-v10.html".
+//
+// Initial Contributors:
+// Nokia Corporation - initial contribution.
+//
+// Contributors:
+//
+// Description:
+// MIUTRSLV.CPP
+//
+
+#include "MIUTRSLV.H"
+#include <msvuids.h>
+#include "MIUTMSG.H"
+#include "MIUT_ERR.H"
+
+#include <cmsvmimeheaders.h>
+#include <mmsvattachmentmanager.h>
+
+#ifdef SYMBIAN_ENABLE_SPLIT_HEADERS
+#include "cimmessagepart.h"
+#include "miut_errconsts.h"
+#include "timrfc822datefield.h"
+#endif
+
+_LIT(KImMhtmlCidString, "cid");
+_LIT8(KImMhtmlStartString, "start");
+
+
+// This class implements the URI resolving process described in RFC 2110.
+// Also see RFC 2112 and 1808.
+
+// MHTML messages may contain multiple HTML body parts. Each of these body parts
+// is able to reference another body part within the same multipart/related
+// structure. These references are called URI's.
+
+// When an MHTML message is parsed by the message engine, the HTML body of each
+// part is stored as a file. The following classes are a means of finding the
+// file name of the body part that corresponds to a given a URI.
+
+CImMhtmlUriResolver* CImMhtmlUriResolver::NewL(CMsvEntry& aEntry)
+ {
+ CImMhtmlUriResolver* self = NewLC(aEntry);
+ CleanupStack::Pop(); // self
+ return self;
+ }
+
+CImMhtmlUriResolver* CImMhtmlUriResolver::NewLC(CMsvEntry& aEntry)
+ {
+ CImMhtmlUriResolver* self = new (ELeave) CImMhtmlUriResolver(aEntry);
+ CleanupStack::PushL(self);
+ self->ConstructL();
+ return self;
+ }
+void CImMhtmlUriResolver::ResolveL(const TDesC& aURI, const TDesC& aHtmlBase, TMsvId aCurrentPartId,TBool aFileNameOnly, TRequestStatus& aStatus)
+ {
+ Queue(aStatus);
+ iResolved = EFalse;
+ delete iUri;
+ iUri = CImMhtmlUri::NewL(aURI);
+ iBodyPartId = aCurrentPartId;
+ iCurrentEntry.SetEntryL(aCurrentPartId);
+ iState = EImResolvingUri;
+
+ iTryingThisMessage = EFalse;
+ iFileNameOnly = aFileNameOnly;
+ ResolveL(aHtmlBase, aCurrentPartId);
+ }
+
+
+void CImMhtmlUriResolver::ResolveL(const TDesC& aHtmlBase, TMsvId aCurrentPartId)
+ {
+
+ if (!(iUri->IsAbsolute()))
+ // Use the aHtmlBase parameter as a base to make an absolute URI from the given relative one.
+ // Try and find a match for this URI.
+ {
+ if (aHtmlBase.Length() != 0)
+ {
+ CImMhtmlUri* baseUri = CImMhtmlUri::NewLC(aHtmlBase);
+ if (baseUri->IsAbsolute())
+ {
+ iUri->MakeAbsoluteL(*baseUri);
+ }
+ CleanupStack::PopAndDestroy(); // baseUri
+ }
+ }
+
+ if (!(iUri->IsAbsolute()))
+ // Use the Content-location value that is associated with the current part as a base.
+ // Use this base to make an absolute URI from the given one and then search for it.
+ {
+ HBufC* contentLocation = GetContentLocationL(aCurrentPartId);
+ if (contentLocation)
+ {
+ CleanupStack::PushL(contentLocation);
+ CImMhtmlUri* baseUri = CImMhtmlUri::NewLC(contentLocation->Des());
+ if (baseUri->IsAbsolute())
+ {
+ iUri->MakeAbsoluteL(*baseUri);
+ }
+ CleanupStack::PopAndDestroy(2); // baseUri, contentLocation
+ }
+ }
+
+ iStatus=KRequestPending;
+ SetActive();
+ TRequestStatus* status = &iStatus;
+ User::RequestComplete(status, KErrNone);
+ }
+
+void CImMhtmlUriResolver::FindFirstL(TMsvId aRootMessageId,TBool aFileNameOnly, TRequestStatus &aStatus)
+ {
+ Queue(aStatus);
+ iMhtmlFirstPageFinder->FindL(aRootMessageId,aFileNameOnly, iStatus);
+ iFileNameOnly = aFileNameOnly;
+ iState = EImFindingFirstUri;
+ SetActive();
+ }
+
+CImMhtmlUriResolver::~CImMhtmlUriResolver()
+ {
+ iFile.Close();
+ delete iUri;
+ delete iMhtmlFileFinder;
+ delete iMhtmlFirstPageFinder;
+ iUriCacheArray.ResetAndDestroy();
+ }
+
+
+TInt CImMhtmlUriResolver::FileHandle(RFile& aFile) const
+ {
+ if(iResolved)
+ {
+ // someone requested for the file handle,
+ // pass the handle and create a empty file handle
+ aFile = iFile;
+ iFile=RFile();
+ return KErrNone;
+ }
+ else
+ {
+ return KErrNotFound;
+ }
+ }
+
+HBufC* CImMhtmlUriResolver::FileNameL() const
+ {
+ if (iResolved)
+ {
+ HBufC* fileName = HBufC::NewL(iFileName.Length());
+ (*fileName) = iFileName;
+ return fileName;
+ }
+ else
+ {
+ return iUri ? iUri->TextL(ETrue) : 0;
+ }
+ }
+
+TMsvId CImMhtmlUriResolver::LinkedEntryId() const
+ {
+ return iLinkedEntryId;
+ }
+
+void CImMhtmlUriResolver::ConstructL()
+ {
+ CActiveScheduler::Add(this);
+ iMhtmlFileFinder = CImMhtmlFileFinder::NewL(iCurrentEntry,iUriCacheArray);
+ iMhtmlFirstPageFinder = CImMhtmlFirstPageFinder::NewL(iCurrentEntry);
+ }
+
+void CImMhtmlUriResolver::DoRunL()
+ {
+ TBool matchUri = EFalse;
+
+ if ((iState == EImFindingFile)
+ && (!iMhtmlFileFinder->MatchFound())
+ && (iTryingThisMessage))
+ // Fix for MIME::lite.
+ // The body part could not be found using the thismessage: scheme,
+ // so look for a content location with the original unresolved URI.
+ {
+ matchUri = ETrue;
+ iTryingThisMessage = EFalse;
+
+ CImMhtmlUri* unresolvedUri = CImMhtmlUri::NewLC(iUri->OriginalUriText()->Des());
+ delete iUri;
+ iUri = unresolvedUri;
+ CleanupStack::Pop(); // unresolvedUri
+ }
+
+ if (EImResolvingUri == iState)
+ {
+ if (!(iUri->IsAbsolute()))
+ {
+ iCurrentEntry.SetEntryL(iCurrentEntry.Entry().Parent());
+
+ if ((KUidMsvMessageEntry != iCurrentEntry.Entry().iType)
+ && (KUidMsvFolderEntry != iCurrentEntry.Entry().iType))
+ // If there are no parent entries then use 'thismessage:/' as the base.
+ {
+ _LIT(KDefaultBase, "thismessage:/");
+ CImMhtmlUri* defaultBase = CImMhtmlUri::NewLC(KDefaultBase);
+ iUri->MakeAbsoluteL(*defaultBase);
+ CleanupStack::PopAndDestroy(); // defaultBase
+ matchUri = ETrue;
+ iTryingThisMessage = ETrue;
+ }
+ // If a valid base is still needed to complete the uri then try and find it in the parent headers.
+ else
+ {
+ ResolveL(KNullDesC ,iCurrentEntry.Entry().Id());
+ iState=EImTryingWithoutResolve;
+ }
+ }
+ else
+ {
+ matchUri = ETrue;
+ }
+ }
+ else if (iState == EImTryingWithoutResolve)
+ {
+ matchUri = ETrue;
+ }
+
+
+ if (matchUri)
+ {
+ if(CheckCacheForLinkedEntryL())
+ {
+ if (iStatus == KImcmHTMLPartNotPopulated)
+ {
+ User::Leave(KImcmHTMLPartNotPopulated);
+ }
+ }
+ else
+ {
+ // Search the appropriate structures for the file that matches the absolute URI.
+ TBool cidUri = iUri->CompareScheme(KImMhtmlCidString);
+ // Do not include the scheme if the URI is a content-id ('cid:').
+ HBufC* uriText = iUri->TextL(!cidUri);
+
+ CleanupStack::PushL(uriText);
+ iMhtmlFileFinder->FindL(uriText->Des(), iBodyPartId,iFileNameOnly, iStatus);
+ CleanupStack::PopAndDestroy(); // uriText
+ iState = EImFindingFile;
+ SetActive();
+ }
+
+ }
+ }
+/**
+Searches in cache for a URl that need to be resolved. If URL found in cache then it implies that URL
+has been resolved in previous look ups (Each entry of cache contains a URL and its corresponding Linked Entry)
+@return True if cache contains URI else false
+*/
+TBool CImMhtmlUriResolver::CheckCacheForLinkedEntryL()
+ {
+ TInt count = iUriCacheArray.Count();
+ if(count)
+ {
+ CImCacheUriEntry* cacheEntry = NULL;
+ for(TInt i=0; i < count; ++i)
+ {
+ cacheEntry = iUriCacheArray[i];
+ if((iUri->OriginalUriText()->Des().Compare(cacheEntry->GetContentLocation()->Des()) == 0 ) || (iUri->OriginalUriText()->Des().Compare(cacheEntry->GetContentId()->Des()) == 0 ))
+ {
+ iLinkedEntryId = cacheEntry->GetUriEntry();
+ iCurrentEntry.SetEntryL(iLinkedEntryId);
+ CMsvStore* store = iCurrentEntry.ReadStoreL();
+ CleanupStack::PushL(store);
+ MMsvAttachmentManager& attachmentMgr = store->AttachmentManagerL();
+ // emails have one attachment per attachment entry
+ if(attachmentMgr.AttachmentCount())
+ {
+ if(iFileNameOnly)
+ {
+ CMsvAttachment* attachment = attachmentMgr.GetAttachmentInfoL(0);
+ iFileName = attachment->FilePath();
+ delete attachment;
+ }
+ else
+ {
+ iFile = attachmentMgr.GetAttachmentFileL(0);
+ }
+ }
+ CleanupStack::PopAndDestroy(store);
+
+ // Check that the file exists. If it doesn't then complete with an error.
+ if (!iCurrentEntry.Entry().Complete())
+ {
+ iStatus = KImcmHTMLPartNotPopulated;
+ }
+ iResolved = ETrue; //need to constract the uriresolver entry.
+ return ETrue;
+ }
+ }
+ }
+ return EFalse;
+ }
+
+
+void CImMhtmlUriResolver::DoComplete(TInt& aStatus)
+ {
+ if (EImFindingFirstUri == iState)
+ {
+ if ((iStatus == KErrNone) || (iStatus == KImcmHTMLPartNotPopulated))
+ {
+ if(iFileNameOnly)
+ {
+ iMhtmlFirstPageFinder->Result(iFileName, iLinkedEntryId);
+ }
+ else
+ {
+ iMhtmlFirstPageFinder->Result(iFile,iLinkedEntryId);
+ }
+ iResolved = ETrue;
+ }
+ }
+ else if (EImFindingFile == iState)
+ {
+ if ((iMhtmlFileFinder->MatchFound()) || (iStatus == KImcmHTMLPartNotPopulated))
+ {
+ if(iFileNameOnly)
+ {
+ iMhtmlFileFinder->Result(iFileName, iLinkedEntryId);
+ }
+ else
+ {
+ iMhtmlFileFinder->Result(iFile,iLinkedEntryId);
+ }
+
+ iResolved = ETrue;
+ }
+ }
+
+ if ((!iResolved) && (aStatus != KImcmHTMLPartNotPopulated))
+ {
+ aStatus = KErrNotFound;
+ }
+ }
+
+void CImMhtmlUriResolver::DoCancel()
+ {
+ switch (iState)
+ {
+ case EImFindingFile:
+ iMhtmlFileFinder->Cancel();
+ break;
+ case EImFindingFirstUri:
+ iMhtmlFirstPageFinder->Cancel();
+ break;
+ default:
+ break;
+ }
+ CMsgActive::DoCancel();
+ }
+
+CImMhtmlUriResolver::CImMhtmlUriResolver(CMsvEntry& aEntry) : CMsgActive(EPriorityStandard), iCurrentEntry(aEntry)
+ {
+
+ }
+
+HBufC* CImMhtmlUriResolver::GetContentLocationL(TMsvId aEntryId)
+ {
+// Get the Content-location value from the mime header of the specified entry.
+ iCurrentEntry.SetEntryL(aEntryId);
+
+ HBufC* result = 0;
+
+ if(iCurrentEntry.HasStoreL())
+ {
+ CMsvStore* entryStore = iCurrentEntry.ReadStoreL();
+ CleanupStack::PushL(entryStore);
+ if (entryStore->IsPresentL(KUidMsgFileMimeHeader))
+ {
+ CImMimeHeader* mimeHeader = CImMimeHeader::NewLC();
+ mimeHeader->RestoreL(*entryStore);
+ TPtrC16 contentLocationPtr = mimeHeader->ContentLocation();
+ result = HBufC::NewL(contentLocationPtr.Length());
+ (*result) = contentLocationPtr;
+ CleanupStack::PopAndDestroy(); // mimeHeader
+ }
+ CleanupStack::PopAndDestroy(); // entryStore
+ }
+ return result;
+ }
+
+CImMhtmlChildEntrySearcher* CImMhtmlChildEntrySearcher::NewL(CMsvEntry& aEntry, RPointerArray<CImCacheUriEntry>& aUriCacheUriArray)
+ {
+ CImMhtmlChildEntrySearcher* self = new (ELeave) CImMhtmlChildEntrySearcher(aEntry, aUriCacheUriArray);
+ CActiveScheduler::Add(self);
+ return self;
+ }
+
+void CImMhtmlChildEntrySearcher::StartL(TMsvId aEntry, TDesC& aUri, TRequestStatus& aStatus)
+ {
+
+ delete iUri;
+ iUri = 0;
+ iUri = HBufC::NewL(aUri.Length());
+ (*iUri) = aUri;
+
+ delete iChildEntries;
+ iChildEntries = 0;
+ iEntry.SetEntryL(aEntry);
+ iChildEntries = iEntry.ChildrenL();
+ TInt index = iChildEntries->Count();
+ while (index--)
+ {
+ if (iEntry.ChildDataL((*iChildEntries)[index]).iType == KUidMsvFolderEntry)
+ iChildEntries->Delete(index);
+ }
+ iChildEntryIndex = 0;
+
+ iFound = EFalse;
+
+ if (iChildEntries->Count() != 0)
+ {
+ CheckCurrentEntryL();
+ Queue(aStatus);
+ }
+ else
+ {
+ Queue(aStatus);
+ iStatus=KRequestPending;
+ SetActive();
+ TRequestStatus* status = &iStatus;
+ User::RequestComplete(status, KErrNone);
+ }
+ }
+
+CImMhtmlChildEntrySearcher::~CImMhtmlChildEntrySearcher()
+ {
+ delete iUri;
+ delete iChildEntries;
+ }
+
+TBool CImMhtmlChildEntrySearcher::SearchResult(TMsvId& aSearchResultEntry)
+ {
+ if (iFound)
+ {
+ aSearchResultEntry = (*iChildEntries)[iChildEntryIndex];
+ }
+ return iFound;
+ }
+
+void CImMhtmlChildEntrySearcher::DoRunL()
+ {
+ if (!iFound)
+ {
+ iChildEntryIndex++;
+ if (iChildEntryIndex < iChildEntries->Count())
+ {
+ CheckCurrentEntryL();
+ }
+ }
+ }
+
+void CImMhtmlChildEntrySearcher::DoComplete(TInt& )
+ {
+
+ }
+
+/**
+Search for a TMsvId entry in cache. If found there is no need to open
+store to get content-location, content-id of that entry because cache contains that information
+@return index of the cache if cache contains URI else 0
+*/
+TInt CImMhtmlChildEntrySearcher::CheckCacheForEntryId(TMsvId aId)
+{
+ TInt count = iUriCacheArray.Count();
+ if(count)
+ {
+ CImCacheUriEntry* cacheEntry = NULL;
+ for(TInt i=0; i < count; ++i)
+ {
+ cacheEntry = iUriCacheArray[i];
+ if(cacheEntry->GetUriEntry() == aId)
+ return i;
+ }
+ }
+ return KErrNotFound;
+}
+
+void CImMhtmlChildEntrySearcher::CheckCurrentEntryL()
+//Compares the search URI with the content-location and content-id fields of each child entry in cache if not found then
+// compares the search URI with the content-location and content-id fields of each child entry from store.
+// It sets iFound if either content field in the current entry matches the URI.
+ {
+ TInt index = CheckCacheForEntryId((*iChildEntries)[iChildEntryIndex]);
+ if( index != KErrNotFound )
+ {
+ CImCacheUriEntry* uriEntry = iUriCacheArray[index];
+ iFound = CheckContentDetailsL(uriEntry->GetContentLocation()->Des(),uriEntry->GetContentId()->Des());
+ }
+ else
+ {
+ iEntry.SetEntryL((*iChildEntries)[iChildEntryIndex]);
+ if (iEntry.HasStoreL() && (iEntry.Entry().iType != KUidMsvFolderEntry))
+ {
+ CMsvStore* entryStore = iEntry.ReadStoreL();
+ CleanupStack::PushL(entryStore);
+ // Get the content-location and content-id values for the current entry.
+ if (entryStore->IsPresentL(KUidMsgFileMimeHeader))
+ {
+ CImMimeHeader* mimeHeader = CImMimeHeader::NewLC();
+ mimeHeader->RestoreL(*entryStore);
+ TPtrC16 contentLocationPtr = mimeHeader->ContentLocation();
+ TPtrC8 contentIdPtr = mimeHeader->ContentID();
+ // Copy the 8 bit contentId string into a 16 bit wide descriptor.
+ TInt contentIdLength = contentIdPtr.Length();
+ HBufC* contentId = HBufC::NewL(contentIdLength);
+ CleanupStack::PushL(contentId);
+ TInt contentIdCopyCounter = 0;
+ TPtr copyOfContentId = contentId->Des();
+ for (contentIdCopyCounter = 0; contentIdCopyCounter < contentIdLength; contentIdCopyCounter++)
+ {
+ copyOfContentId.Append(contentIdPtr[contentIdCopyCounter]);
+ }
+
+ // Compare the content-location and content-id values to the search URI string.
+ iFound = CheckContentDetailsL(contentLocationPtr, copyOfContentId);
+ //Add entry to cache. So that for each new URI lookup, first
+ //look in the cache to see URI has been loaded during a previous lookup.
+ CImCacheUriEntry* uriEntry = CImCacheUriEntry::NewL(contentLocationPtr,copyOfContentId,iEntry.EntryId());
+ if(iUriCacheArray.Append(uriEntry) != KErrNone)
+ {
+ delete uriEntry;
+ }
+ CleanupStack::PopAndDestroy(2); // contentId, mimeHeader
+ }
+ CleanupStack::PopAndDestroy(); // entryStore
+ }
+ }
+ iStatus=KRequestPending;
+ SetActive();
+ TRequestStatus* status = &iStatus;
+ User::RequestComplete(status, KErrNone);
+ }
+
+
+TBool CImMhtmlChildEntrySearcher::CheckContentDetailsL(const TDesC& aContentLocation, const TDesC& aContentId)
+// Compare the URI to the given content-location and content-id
+ {
+ TBool matchFound = EFalse;
+
+ if ((iUri->Des()).CompareF(aContentLocation) == 0)
+ {
+ matchFound = ETrue;
+ }
+ else if ((iUri->Des()).CompareF(aContentId) == 0)
+ {
+ matchFound = ETrue;
+ }
+
+ return matchFound;
+ }
+
+CImMhtmlChildEntrySearcher::CImMhtmlChildEntrySearcher(CMsvEntry &aEntry, RPointerArray<CImCacheUriEntry>& aUriCacheUriArray) : CMsgActive(EPriorityStandard), iEntry(aEntry), iUriCacheArray(aUriCacheUriArray)
+ {
+ }
+
+
+
+
+
+
+CImMhtmlFileFinder* CImMhtmlFileFinder::NewL(CMsvEntry& aEntry, RPointerArray<CImCacheUriEntry>& aUriCacheUriArray)
+ {
+ CImMhtmlFileFinder* self = new (ELeave) CImMhtmlFileFinder(aEntry);
+ CleanupStack::PushL(self);
+ self->ConstructL(aUriCacheUriArray);
+ CleanupStack::Pop(); // self
+ return self;
+ }
+
+void CImMhtmlFileFinder::FindL(const TDesC& aUri, TMsvId aBodyPartId, TBool aFileNameOnly,TRequestStatus &aStatus)
+// Recursively search the parent to find a match for the given content-ID or content-location.
+ {
+ Queue(aStatus);
+
+ delete iUri;
+ iUri = 0;
+ iUri = HBufC::NewL(aUri.Length());
+ (*iUri) = aUri;
+
+ iCurrentBodyPartId = aBodyPartId;
+ iMatchFound = EFalse;
+
+ iFileNameOnly = aFileNameOnly;
+ DoFindL();
+ }
+
+void CImMhtmlFileFinder::DoFindL()
+ {
+ iCurrentEntry.SetEntryL(iCurrentBodyPartId);
+
+ TPtr uri = iUri->Des();
+ iChildEntrySearcher->StartL((iCurrentEntry.Entry()).Parent(), uri, iStatus);
+ SetActive();
+ }
+
+void CImMhtmlFileFinder::Result(RFile& aFile, TMsvId& aEntryId) const
+ {
+ aFile= iFile;
+ iFile = RFile();
+ aEntryId = iLinkedEntryId;
+ }
+
+void CImMhtmlFileFinder::Result(TFileName& aFileName, TMsvId& aEntryId) const
+ {
+ aFileName = iFileName;
+ aEntryId = iLinkedEntryId;
+ }
+
+TBool CImMhtmlFileFinder::MatchFound() const
+ {
+ return iMatchFound;
+ }
+
+CImMhtmlFileFinder::~CImMhtmlFileFinder()
+ {
+ iFile.Close();
+ delete iUri;
+ delete iChildEntrySearcher;
+ }
+
+CImMhtmlFileFinder::CImMhtmlFileFinder(CMsvEntry &aEntry) : CMsgActive(EPriorityStandard), iCurrentEntry(aEntry)
+ {
+
+ }
+
+
+void CImMhtmlFileFinder::ConstructL(RPointerArray<CImCacheUriEntry>& aUriCacheUriArray)
+ {
+ CActiveScheduler::Add(this);
+ iChildEntrySearcher = CImMhtmlChildEntrySearcher::NewL(iCurrentEntry, aUriCacheUriArray);
+ }
+
+void CImMhtmlFileFinder::DoRunL()
+ {
+ if (iStatus == KErrNone)
+ {
+ TMsvId matchingEntry;
+ iMatchFound = iChildEntrySearcher->SearchResult(matchingEntry);
+ if (!iMatchFound)
+ {
+ // If no match for the URI is found under the current entry then search the parent.
+ iCurrentEntry.SetEntryL(iCurrentBodyPartId);
+ iCurrentBodyPartId = iCurrentEntry.Entry().Parent();
+ DoFindL();
+ }
+ else
+ {
+ // If a match is found the set the result values.
+ iLinkedEntryId = matchingEntry;
+ iCurrentEntry.SetEntryL(iLinkedEntryId);
+ CMsvStore* store = iCurrentEntry.ReadStoreL();
+ CleanupStack::PushL(store);
+ MMsvAttachmentManager& attachmentMgr = store->AttachmentManagerL();
+ // emails have one attachment per attachment entry
+ if(attachmentMgr.AttachmentCount())
+ {
+ if(iFileNameOnly)
+ {
+ CMsvAttachment* attachment = attachmentMgr.GetAttachmentInfoL(0);
+ iFileName = attachment->FilePath();
+ delete attachment;
+ }
+ else
+ {
+ iFile = attachmentMgr.GetAttachmentFileL(0);
+ }
+ }
+ CleanupStack::PopAndDestroy(store);
+
+ // Check that the file exists. If it doesn't then complete with an error.
+ if (!iCurrentEntry.Entry().Complete())
+ {
+ iStatus = KImcmHTMLPartNotPopulated;
+ }
+ }
+ }
+ }
+
+void CImMhtmlFileFinder::DoCancel()
+ {
+ iChildEntrySearcher->Cancel();
+ CMsgActive::DoCancel();
+ }
+
+void CImMhtmlFileFinder::DoComplete(TInt& aStatus)
+ {
+ if (iStatus == KImcmHTMLPartNotPopulated)
+ {
+ aStatus = KImcmHTMLPartNotPopulated;
+ }
+ else if (aStatus == KErrNotFound)
+ {
+ aStatus = KErrNone;
+ }
+ }
+
+
+
+
+
+
+CImMhtmlFirstPageFinder* CImMhtmlFirstPageFinder::NewL(CMsvEntry& aEntry)
+ {
+ CImMhtmlFirstPageFinder* self = new (ELeave) CImMhtmlFirstPageFinder(aEntry);
+ CleanupStack::PushL(self);
+ self->ConstructL();
+ CleanupStack::Pop();
+ return self;
+ }
+
+void CImMhtmlFirstPageFinder::FindL(TMsvId aRootMessage,TBool aFileNameOnly, TRequestStatus& aStatus)
+// Find the first html part of the specified message.
+// Use the Id function to retrieve the result.
+ {
+ Queue(aStatus);
+
+ iNextUnrelatedEntryStack->Reset();
+ iRelatedDepthCounter = 0;
+
+ delete iEntryStack;
+ iEntryStack = 0;
+ iCurrentEntry.SetEntryL(aRootMessage);
+ iEntryStack = iCurrentEntry.ChildrenL();
+ TKeyArrayFix sortKey(0, ECmpTInt32);
+ iEntryStack->Sort(sortKey);
+
+ // The order of the list must be reversed because items are taken from the end.
+ TInt startCounter = 0;
+ TInt endCounter = iEntryStack->Count() - 1;
+ TMsvId savedId;
+ while (startCounter < endCounter)
+ {
+ savedId = (*iEntryStack)[startCounter];
+ (*iEntryStack)[startCounter] = (*iEntryStack)[endCounter];
+ (*iEntryStack)[endCounter] = savedId;
+ startCounter++;
+ endCounter--;
+ }
+
+ iHtmlPartFound = EFalse;
+ iUnrelatedHtmlPartFound = EFalse;
+
+ SetStartParameterL();
+
+ DoFindL();
+ iFileNameOnly = aFileNameOnly;
+ }
+
+void CImMhtmlFirstPageFinder::SetStartParameterL()
+ {
+ CMsvStore* store = NULL;
+ if(iCurrentEntry.HasStoreL())
+ {
+ store = iCurrentEntry.ReadStoreL();
+ CleanupStack::PushL(store);
+
+ delete iStartParameter;
+ iStartParameter = 0;
+ if (store->IsPresentL(KUidMsgFileMimeHeader))
+ {
+ CImMimeHeader* mimeHeader = CImMimeHeader::NewLC();
+ TRAPD(err, mimeHeader->RestoreL(*store));
+ if (KErrNotFound == err)
+ {
+ err = KImcmInvalidMessageStructure;
+ }
+ User::LeaveIfError(err);
+ const CDesC8Array& contentTypeParams = mimeHeader->ContentTypeParams();
+ TInt startLength = ((TDesC&)KImMhtmlStartString).Length();
+ TInt compareResult = 1;
+ // Search for the start parameter.
+ TInt paramIndex = contentTypeParams.Count();
+ while ((paramIndex > 0) && (compareResult != 0))
+ {
+ paramIndex--;
+ compareResult = ((contentTypeParams[paramIndex]).Left(startLength)).CompareF(KImMhtmlStartString);
+ }
+
+ if (compareResult == 0)
+ // The 'start' parameter has been found, now the value needs to be extracted.
+ {
+ TPtrC8 startValue = contentTypeParams[paramIndex].Right(contentTypeParams[paramIndex].Length() - startLength);
+
+ // Remove any leading whitespace and a single '=' character.
+ TBool equalsFound = EFalse;
+ TBool firstValueCharacterFound = EFalse;
+ while ((startValue.Length() > 0) && (!firstValueCharacterFound))
+ {
+ if ((startValue[0] == '=') && (!equalsFound))
+ {
+ equalsFound = ETrue;
+ startValue.Set(startValue.Right(startValue.Length() - 1));
+ }
+ else if (startValue[0] == ' ')
+ {
+ startValue.Set(startValue.Right(startValue.Length() - 1));
+ }
+ else
+ {
+ firstValueCharacterFound = ETrue;
+ }
+ }
+
+ // Remove the quotes if they exist.
+ if (startValue.Length() > 1)
+ {
+ if ((startValue[0] == '"') && (startValue[startValue.Length() - 1] == '"'))
+ {
+ startValue.Set(startValue.Mid(1, startValue.Length() - 2));
+ }
+ }
+
+ // Keep a copy of the unquoted start parameter.
+ delete iStartParameter;
+ iStartParameter = 0;
+ iStartParameter = HBufC8::NewL(startValue.Length());
+ (*iStartParameter) = startValue;
+ }
+ CleanupStack::PopAndDestroy(); // mimeHeader
+ }
+ CleanupStack::PopAndDestroy(); // store
+ }
+ else
+ {
+ iStatus=KErrNotFound;
+ }
+ }
+
+void CImMhtmlFirstPageFinder::DoFindL()
+ {
+ // Get the entry details from the item at the head of the stack.
+ if (iEntryStack->Count() > 0)
+ {
+ iCurrentEntry.SetEntryL((*iEntryStack)[iEntryStack->Count() - 1] );
+
+ // Check if the current entry is at the top of the unrelated stack
+ // If it is then we are no longer under the related structure.
+ if (iNextUnrelatedEntryStack->Count() != 0)
+ {
+ if (iCurrentEntry.Entry().Id() == (*iNextUnrelatedEntryStack)[iNextUnrelatedEntryStack->Count() - 1])
+ {
+ iRelatedDepthCounter--;
+ iNextUnrelatedEntryStack->ResizeL(iNextUnrelatedEntryStack->Count() - 1);
+ }
+ }
+
+ // Pop the entry from the stack.
+ iEntryStack->ResizeL(iEntryStack->Count() - 1);
+
+ // If the current entry is a related type then increase the related depth counter
+ // We need to know if we are under a related entry in order to recognise the first HTML part
+
+ TUid entryType = iCurrentEntry.Entry().iType;
+ if (EFolderTypeRelated == ((TMsvEmailEntry)iCurrentEntry.Entry()).MessageFolderType())
+ {
+ iRelatedDepthCounter++;
+ if (iEntryStack->Count() != 0)
+ {
+ iNextUnrelatedEntryStack->AppendL((*iEntryStack)[iEntryStack->Count() - 1]);
+ }
+ }
+
+ if (KUidMsvEmailHtmlEntry == entryType)
+ {
+ if (iStartParameter != 0)
+ {
+ CMsvStore* store = iCurrentEntry.ReadStoreL();
+ CleanupStack::PushL(store);
+ if (store->IsPresentL(KUidMsgFileMimeHeader))
+ {
+ CImMimeHeader* mimeHeader = CImMimeHeader::NewLC();
+ mimeHeader->RestoreL(*store);
+ TPtrC8 contentId = mimeHeader->ContentID();
+ if ((iStartParameter->Des()).CompareF(contentId) == 0)
+ // If the start parameter matches the content-id then the first HTML part
+ // has been found.
+ {
+ iHtmlPartFound = ETrue;
+ iFirstHtmlPartId = iCurrentEntry.Entry().Id();
+ }
+ CleanupStack::PopAndDestroy(); // mimeHeader
+ }
+ CleanupStack::PopAndDestroy(); // store
+ }
+ else
+ {
+ if (iRelatedDepthCounter > 0)
+ // This entry is under a related structure (either directly or indirectly)
+ // so it is the one we are after.
+ // HTML parts that are not under a related structure are normal attachments
+ // and NOT part of an MHTML message.
+ {
+ iHtmlPartFound = ETrue;
+ iFirstHtmlPartId = iCurrentEntry.Entry().Id();
+ }
+ else
+ {
+ if ((!iHtmlPartFound) && (!iUnrelatedHtmlPartFound))
+ {
+ iUnrelatedHtmlPartFound = ETrue;
+ iFirstUnrelatedHtmlPartId = iCurrentEntry.Entry().Id();
+ }
+ }
+ }
+ }
+
+ if (KUidMsvFolderEntry == entryType)
+ {
+ // Push the sorted child items on to the stack.
+ CMsvEntrySelection* childEntries = iCurrentEntry.ChildrenL();
+ CleanupStack::PushL(childEntries);
+ TKeyArrayFix sortKey(0, ECmpTInt32);
+ childEntries->Sort(sortKey);
+
+ // The entries need to be added in reverse order because they are retrieved from a stack.
+ TInt childEntriesCounter = childEntries->Count();
+ while (childEntriesCounter > 0)
+ {
+ childEntriesCounter--;
+ // Ignore any entries that weren't folders or HTML entries.
+ if ((iCurrentEntry.ChildDataL((*childEntries)[childEntriesCounter]).iType == KUidMsvFolderEntry)
+ || (iCurrentEntry.ChildDataL((*childEntries)[childEntriesCounter]).iType == KUidMsvEmailHtmlEntry))
+ {
+ iEntryStack->AppendL((*childEntries)[childEntriesCounter]);
+ }
+ }
+ CleanupStack::PopAndDestroy(childEntries);
+ }
+
+ }
+
+ TRequestStatus* status = &iStatus;
+ iStatus=KRequestPending;
+ SetActive();
+ if ((!iCurrentEntry.Entry().Complete()) && (iHtmlPartFound))
+ {
+ User::RequestComplete(status, KImcmHTMLPartNotPopulated);
+ }
+ else
+ {
+ User::RequestComplete(status, KErrNone);
+ }
+ }
+
+void CImMhtmlFirstPageFinder::Result(RFile& aFile, TMsvId& aEntryId) const
+ {
+ aFile = iFile;
+ iFile = RFile();
+ aEntryId = iFirstHtmlPartId;
+ }
+
+void CImMhtmlFirstPageFinder::Result(TFileName& aFileName, TMsvId& aEntryId) const
+ {
+ aFileName = iFileName;
+ aEntryId = iFirstHtmlPartId;
+ }
+
+CImMhtmlFirstPageFinder::~CImMhtmlFirstPageFinder()
+ {
+ iFile.Close();
+ delete iEntryStack;
+ delete iStartParameter;
+ delete iNextUnrelatedEntryStack;
+ }
+
+CImMhtmlFirstPageFinder::CImMhtmlFirstPageFinder(CMsvEntry& aEntry) : CMsgActive(EPriorityStandard), iCurrentEntry(aEntry)
+ {
+ }
+
+void CImMhtmlFirstPageFinder::ConstructL()
+ {
+ CActiveScheduler::Add(this);
+ iNextUnrelatedEntryStack = new (ELeave) CMsvEntrySelection;
+ }
+
+void CImMhtmlFirstPageFinder::DoRunL()
+ {
+ // We are done if we could not find the parent structure, or if we have found an HTML part.
+ if (iStatus == KErrNone)
+ {
+ if ((iEntryStack->Count() != 0) && (!iHtmlPartFound))
+ {
+ DoFindL();
+ }
+ else
+ {
+ if (iUnrelatedHtmlPartFound)
+ {
+ iHtmlPartFound = ETrue;
+ iFirstHtmlPartId = iFirstUnrelatedHtmlPartId;
+ }
+ }
+ }
+
+ if (iHtmlPartFound && !IsActive())
+ {
+ iCurrentEntry.SetEntryL(iFirstHtmlPartId);
+ CMsvStore* store = iCurrentEntry.ReadStoreL();
+ CleanupStack::PushL(store);
+ MMsvAttachmentManager& attachmentMgr = store->AttachmentManagerL();
+ // get the file handle to pass it to clients who request for it using
+ // function CImEmailMessage::GetUniversalResourceIdentifierL()
+ if(attachmentMgr.AttachmentCount())
+ {
+ if(iFileNameOnly)
+ {
+ CMsvAttachment* attachment = attachmentMgr.GetAttachmentInfoL(0);
+ iFileName = attachment->FilePath();
+ delete attachment;
+ }
+ else
+ {
+ iFile = attachmentMgr.GetAttachmentFileL(0);
+ }
+ }
+ CleanupStack::PopAndDestroy(store);
+ }
+ }
+
+void CImMhtmlFirstPageFinder::DoComplete(TInt& aStatus)
+ {
+ if (!iHtmlPartFound)
+ {
+ aStatus = KErrNotFound;
+ }
+ else
+ {
+ aStatus = KErrNone;
+ }
+ }
+
+
+
+
+// The following class implements a class for parsing and combining URI's.
+// See RFC 1808 for more details.
+
+CImMhtmlUri* CImMhtmlUri::NewL(const TDesC& aUriText)
+ {
+ CImMhtmlUri* self = NewLC(aUriText);
+ CleanupStack::Pop(); // self
+ return self;
+ }
+
+CImMhtmlUri* CImMhtmlUri::NewLC(const TDesC& aUriText)
+ {
+ CImMhtmlUri* self = new (ELeave) CImMhtmlUri();
+ CleanupStack::PushL(self);
+ self->ConstructL(aUriText);
+ return self;
+ }
+
+void CImMhtmlUri::ConstructL(const TDesC& aUriText)
+ {
+ iUriText = HBufC::NewL(aUriText.Length());
+ (*iUriText) = aUriText;
+ iDirectoryPath = new (ELeave) CDesCArrayFlat(8);
+ ParseL();
+ }
+
+void CImMhtmlUri::MakeAbsoluteL(const CImMhtmlUri& aBaseUri)
+ {
+ TBool done = EFalse;
+
+ if (iScheme == 0)
+ {
+ if (aBaseUri.iScheme)
+ {
+ iScheme = HBufC::NewL(aBaseUri.iScheme->Length());
+ (*iScheme) = aBaseUri.iScheme->Des();
+ }
+ }
+ else
+ {
+ done = ETrue;
+ }
+
+ if ((iNetLoc == 0) && (!done))
+ {
+ if (aBaseUri.iNetLoc)
+ {
+ iNetLoc = HBufC::NewL(aBaseUri.iNetLoc->Length());
+ (*iNetLoc) = aBaseUri.iNetLoc->Des();
+ }
+ }
+ else
+ {
+ done = ETrue;
+ }
+
+ if ((!iAbsolutePath) && (!done))
+ {
+ // Try to add any directories from the base before hand.
+ TInt count = aBaseUri.iDirectoryPath->Count();
+
+ if (iDirectoryPath->Count() != 0)
+ {
+ done = ETrue;
+ if (aBaseUri.iContainsFileName)
+ {
+ count--;
+ }
+ }
+ else
+ {
+ iContainsFileName = aBaseUri.iContainsFileName;
+ }
+
+ while (count > 0)
+ {
+ count--;
+ iDirectoryPath->InsertL(0, (*(aBaseUri.iDirectoryPath))[count]);
+ }
+ }
+ else
+ {
+ done = ETrue;
+ }
+
+ if ((iParameters == 0) && (!done))
+ {
+ if (aBaseUri.iParameters)
+ {
+ iParameters = HBufC::NewL(aBaseUri.iParameters->Length());
+ (*iParameters) = aBaseUri.iParameters->Des();
+ }
+ }
+ else
+ {
+ done = ETrue;
+ }
+
+ if ((iQuery == 0) && (!done))
+ {
+ if (aBaseUri.iQuery)
+ {
+ iQuery = HBufC::NewL(aBaseUri.iQuery->Length());
+ (*iQuery) = aBaseUri.iQuery->Des();
+ }
+ }
+ else
+ {
+ done = ETrue;
+ }
+
+ if ((iFragment == 0) && (!done))
+ {
+ if (aBaseUri.iFragment)
+ {
+ iFragment = HBufC::NewL(aBaseUri.iFragment->Length());
+ (*iFragment) = aBaseUri.iFragment->Des();
+ }
+ }
+
+ Normalise();
+ }
+
+HBufC* CImMhtmlUri::TextL(TBool aIncludeScheme)
+ {
+ // First calculate the size of the required HBufC
+ TInt length = 0;
+
+ if ((iScheme) && (aIncludeScheme))
+ {
+ length += (iScheme->Des()).Length() + 1;
+ }
+
+ if (iNetLoc)
+ {
+ length += (iNetLoc->Des()).Length() + 2;
+ }
+
+ if (iParameters)
+ {
+ length += (iParameters->Des()).Length() + 1;
+ }
+
+ if (iQuery)
+ {
+ length += (iQuery->Des()).Length() + 1;
+ }
+
+ if (iFragment)
+ {
+ length += (iFragment->Des()).Length() + 1;
+ }
+
+ if (iDirectoryPath != 0)
+ {
+ TInt counter = iDirectoryPath->Count();
+ while (counter > 0)
+ {
+ counter--;
+ length += ((*iDirectoryPath)[counter]).Length();
+ length++;
+ }
+ }
+
+ if (iAbsolutePath != 0)
+ {
+ length++;
+ }
+
+ if (!iContainsFileName)
+ {
+ length++;
+ }
+
+ HBufC* text = HBufC::NewL(length);
+
+ if ((iScheme) && (aIncludeScheme))
+ {
+ (text->Des()).Append(iScheme->Des());
+ (text->Des()).Append(TChar(':'));
+ }
+
+ if (iNetLoc)
+ {
+ (text->Des()).Append(TChar('/'));
+ (text->Des()).Append(TChar('/'));
+ (text->Des()).Append(iNetLoc->Des());
+ }
+
+ if( iDirectoryPath != 0 )
+ {
+ if (((iAbsolutePath) || (iNetLoc)) && (iDirectoryPath->Count()))
+ {
+ (text->Des()).Append(TChar('/'));
+ }
+
+ TInt counter = 0;
+ TInt count = iDirectoryPath->Count();
+ while (counter < count)
+ {
+ (text->Des()).Append((*iDirectoryPath)[counter]);
+
+ counter++;
+
+ if ((counter < count) || (!iContainsFileName))
+ {
+ (text->Des()).Append(TChar('/'));
+ }
+ }
+ }
+
+ if (iParameters)
+ {
+ (text->Des()).Append(TChar(';'));
+ (text->Des()).Append(iParameters->Des());
+ }
+
+ if (iQuery)
+ {
+ (text->Des()).Append(TChar('?'));
+ (text->Des()).Append(iQuery->Des());
+ }
+
+ if (iFragment)
+ {
+ (text->Des()).Append(TChar('#'));
+ (text->Des()).Append(iFragment->Des());
+ }
+
+ return text;
+ }
+
+
+TBool CImMhtmlUri::IsAbsolute() const
+ {
+ return (iScheme == 0) ? EFalse : ETrue;
+ }
+
+
+TBool CImMhtmlUri::CompareScheme(const TDesC& aScheme) const
+// Returns ETrue if the given descriptor matches the scheme of this URI, returns EFalse otherwise.
+ {
+ if (iScheme)
+ {
+ return (aScheme.CompareF(iScheme->Des()) == 0);
+ }
+ else
+ {
+ return EFalse;
+ }
+ }
+
+
+HBufC* CImMhtmlUri::OriginalUriText()
+ {
+ return iUriText;
+ }
+
+
+CImMhtmlUri::~CImMhtmlUri()
+ {
+ delete iDirectoryPath;
+
+ delete iUriText;
+ delete iScheme;
+ delete iNetLoc;
+ delete iParameters;
+ delete iQuery;
+ delete iFragment;
+ }
+
+CImMhtmlUri::CImMhtmlUri()
+ {
+
+ }
+
+void CImMhtmlUri::ParseL()
+ {
+ TInt textIndex = 0;
+ TInt textCount = iUriText->Length();
+
+ TInt stringStart = 0;
+ TInt stringLength = 0;
+ TImUriDelimiterType delimiterType;
+
+ iState = EParsingFirstString;
+
+ while (textIndex <= textCount)
+ {
+ delimiterType = Delimiter(textIndex);
+
+ if (EImUriNotDelimiter != delimiterType)
+ {
+ switch (iState)
+ {
+ case EParsingFirstString:
+ switch(delimiterType)
+ {
+ case EImUriScheme:
+ if (stringLength)
+ {
+ delete iScheme;
+ iScheme = NULL;
+ iScheme = HBufC::NewL(stringLength);
+ (*iScheme) = iUriText->Mid(stringStart, stringLength);
+ }
+ ChangeState(delimiterType);
+ break;
+ case EImUriPath:
+ if ((0 == stringLength)
+ && (0 == stringStart))
+ {
+ iAbsolutePath = ETrue;
+ }
+ case EImUriParameter:
+ case EImUriQuery:
+ case EImUriFragment:
+ case EImUriEnd:
+ if (stringLength)
+ {
+ iDirectoryPath->AppendL(iUriText->Mid(stringStart, stringLength));
+ iContainsFileName = (EImUriPath != delimiterType);
+ }
+ ChangeState(delimiterType);
+ break;
+ case EImUriNetLoc:
+ stringLength = 0;
+ stringStart = 0;
+ ChangeState(delimiterType);
+ default:
+ break;
+ };
+ break;
+ case EParsingScheme:
+ if (stringLength)
+ {
+ delete iScheme;
+ iScheme = NULL;
+ iScheme = HBufC::NewL(stringLength);
+ (*iScheme) = iUriText->Mid(stringStart, stringLength);
+ }
+ ChangeState(delimiterType);
+ break;
+ case EParsingNetLoc:
+ if (stringLength)
+ {
+ delete iNetLoc;
+ iNetLoc = NULL;
+ iNetLoc = HBufC::NewL(stringLength);
+ (*iNetLoc) = iUriText->Mid(stringStart, stringLength);
+ }
+ ChangeState(delimiterType);
+ break;
+ case EParsingPath:
+ if (stringLength)
+ {
+ iDirectoryPath->AppendL(iUriText->Mid(stringStart, stringLength));
+ }
+ if ((delimiterType!=EImUriPath) && (stringLength != 0))
+ {
+ iContainsFileName = ETrue;
+ }
+ ChangeState(delimiterType);
+ break;
+ case EParsingParameter:
+ if (stringLength)
+ {
+ // If more than one parameters are there
+ if(iParameters)
+ {
+ TInt previousParameterLength = (iParameters->Des()).Length() + 1;
+ iParameters = iParameters->ReAlloc(previousParameterLength + stringLength);
+ //Append ";" between the parameters
+ (iParameters->Des()).Append(TChar(';'));
+ HBufC* tempParameter = HBufC::NewL(stringLength);
+ *tempParameter = iUriText->Mid(stringStart, stringLength);
+ (iParameters->Des()).Append(tempParameter->Des());
+ delete tempParameter;
+ }
+ // If all the parameters has been processed or only one parameter element
+ else
+ {
+ iParameters = HBufC::NewL(stringLength);
+ (*iParameters) = iUriText->Mid(stringStart, stringLength);
+ }
+ }
+ ChangeState(delimiterType);
+ break;
+ case EParsingQuery:
+ if (stringLength)
+ {
+ delete iQuery;
+ iQuery = NULL;
+ iQuery = HBufC::NewL(stringLength);
+ (*iQuery) = iUriText->Mid(stringStart, stringLength);
+ }
+ ChangeState(delimiterType);
+ break;
+ case EParsingFragment:
+ if (stringLength)
+ {
+ delete iFragment;
+ iFragment = NULL;
+ iFragment = HBufC::NewL(stringLength);
+ (*iFragment) = iUriText->Mid(stringStart, stringLength);
+ }
+ ChangeState(delimiterType);
+ break;
+ }
+
+ stringStart = textIndex + 1;
+ stringLength = 0;
+ }
+ else
+ {
+ stringLength++;
+ }
+
+ textIndex++;
+ }
+ }
+
+void CImMhtmlUri::Normalise()
+ {
+ _LIT(KImSinglePeriod, ".");
+ _LIT(KImDoublePeriod, "..");
+
+ // Remove any single '.' character at the end of the path as this will have replaced a file name if it were present.
+ if (iDirectoryPath->Count() != 0)
+ {
+ if ((*iDirectoryPath)[iDirectoryPath->Count() - 1] == KImSinglePeriod)
+ {
+ // Remove the filename.
+ iContainsFileName = EFalse;
+ iDirectoryPath->Delete(iDirectoryPath->Count() - 1);
+ }
+ }
+
+
+ TBool directoryRemoved = ETrue;
+ TInt count;
+ TInt counter;
+ while (directoryRemoved)
+ {
+ directoryRemoved = EFalse;
+ count = iDirectoryPath->Count();
+ counter = 0;
+ while ((counter < count) && (!directoryRemoved))
+ {
+ if ((*iDirectoryPath)[counter] == KImDoublePeriod)
+ {
+ if (counter > 0)
+ {
+ directoryRemoved = ETrue;
+ iDirectoryPath->Delete(counter - 1, 2);
+ if (counter == count - 1)
+ {
+ iContainsFileName = EFalse;
+ }
+ }
+ }
+ else if ((*iDirectoryPath)[counter] == KImSinglePeriod)
+ {
+ iDirectoryPath->Delete(counter);
+ directoryRemoved = ETrue;
+ }
+ counter++;
+ }
+ }
+ }
+
+CImMhtmlUri::TImUriDelimiterType CImMhtmlUri::Delimiter(TInt& aIndex)
+ {
+ TImUriDelimiterType delimiterType = EImUriNotDelimiter;
+
+ if (aIndex >= iUriText->Length())
+ {
+ return EImUriEnd;
+ }
+
+ TChar currentCharacter = (*iUriText)[aIndex];
+
+ if ((iState == EParsingFirstString)
+ && (TChar(':') == currentCharacter))
+ {
+ return EImUriScheme;
+ }
+
+ if (((iState == EParsingFirstString)
+ || (iState == EParsingNetLoc)
+ || (iState == EParsingPath))
+ && (TChar('/') == currentCharacter))
+ {
+ // Path or NetLoc, so check the next character if there is one.
+ if (aIndex + 1 < iUriText->Length())
+ {
+ if (TChar('/') == TChar((*iUriText)[aIndex+1]))
+ {
+ aIndex++;
+ return EImUriNetLoc;
+ }
+ else
+ {
+ return EImUriPath;
+ }
+ }
+ else
+ {
+ return EImUriPath;
+ }
+ }
+
+ if ((iState != EParsingQuery)
+ && (iState != EParsingFragment)
+ && (TChar(';') == currentCharacter))
+ {
+ return EImUriParameter;
+ }
+
+ if ((iState != EParsingFragment)
+ && (TChar('?') == currentCharacter))
+ {
+ return EImUriQuery;
+ }
+
+ if (TChar('#') == currentCharacter)
+ {
+ return EImUriFragment;
+ }
+
+ return delimiterType;
+ }
+
+
+void CImMhtmlUri::ChangeState(TImUriDelimiterType aDelimiterType)
+ {
+ switch (aDelimiterType)
+ {
+ case EImUriScheme:
+ iState = EParsingFirstString;
+ break;
+ case EImUriNetLoc:
+ iState = EParsingNetLoc;
+ break;
+ case EImUriPath:
+ iState = EParsingPath;
+ break;
+ case EImUriParameter:
+ iState = EParsingParameter;
+ break;
+ case EImUriQuery:
+ iState = EParsingQuery;
+ break;
+ case EImUriFragment:
+ iState = EParsingFragment;
+ break;
+ case EImUriEnd:
+ iState = EParsingFirstString;
+ break;
+ default:
+ break;
+ }
+ }
+
+//CImCacheUriEntry
+CImCacheUriEntry* CImCacheUriEntry::NewL(const TDesC& aContentLocation, const TDesC& aContentId,TMsvId aEntry)
+ {
+ CImCacheUriEntry* self = new (ELeave) CImCacheUriEntry();
+ CleanupStack::PushL(self);
+ self->ConstructL(aContentLocation,aContentId,aEntry);
+ CleanupStack::Pop();
+ return self;
+ }
+
+void CImCacheUriEntry::ConstructL(const TDesC& aContentLocation, const TDesC& aContentId,TMsvId aEntry)
+ {
+ iContentLocation = aContentLocation.AllocL();
+ iContentId = aContentId.AllocL();
+ iUriEntry = aEntry;
+ }
+/**
+Constructor
+*/
+CImCacheUriEntry::CImCacheUriEntry()
+ {
+ }
+/**
+Destructor
+*/
+CImCacheUriEntry::~CImCacheUriEntry()
+ {
+ delete iContentLocation;
+ delete iContentId;
+ }
+/**
+@return URI Contentlocation
+*/
+HBufC* CImCacheUriEntry::GetContentLocation()
+ {
+ return (iContentLocation);
+ }
+/**
+@return ContentId
+*/
+HBufC* CImCacheUriEntry::GetContentId()
+ {
+ return (iContentId);
+ }
+/**
+@return URI Entry Id
+*/
+TMsvId CImCacheUriEntry::GetUriEntry()
+ {
+ return iUriEntry;
+ }