diff -r 6a20128ce557 -r ebfee66fde93 email/imap4mtm/imapsession/src/cimaplistbase.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/email/imap4mtm/imapsession/src/cimaplistbase.cpp Fri Jun 04 10:25:39 2010 +0100 @@ -0,0 +1,322 @@ +// Copyright (c) 2006-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: +// + + +#include "cimaplistbase.h" +#include "moutputstream.h" +#include "cimapsessionconsts.h" +#include "cimapatomparser.h" +#include "cimapatomwalker.h" +#include "cimaputils.h" +#include "cimapcharconv.h" +#include "cimapsettings.h" + +// Inbox mailbox name +_LIT16(KIMAP_INBOX, "INBOX"); + +const TUint KNullTerminator = '\0'; + +void CImapListBase::ConstructL(const TDesC& aReferenceName, const TDesC& aMailboxName) + { + iReferenceName = EncodeMailboxNameForSendL(aReferenceName); + iMailboxName = EncodeMailboxNameForSendL(aMailboxName); + iAtomWalker = CImapAtomWalker::NewL(iLogId); + } + +CImapListBase::CImapListBase(CImapFolderInfo* aSelectedFolderData, TInt aLogId, RArrayImapListFolderInfo& aFolderList, const CImapSettings& aImapSettings, const TDesC8& aSendMessageFormat, const TDesC8& aResponseIdentifier) + : CImapCommandEx(aSelectedFolderData, aLogId) + , iFolderList(aFolderList) + , iSendMessageFormat(aSendMessageFormat) + , iResponseIdentifier(aResponseIdentifier) + , iListParseState(EWaitingForResponse) + , iImapSettings(aImapSettings) + { + } + +CImapListBase::~CImapListBase() + { + delete iAtomWalker; + delete iAtomParser; + delete iReferenceName; + delete iMailboxName; + } + +/** +Formats and sends the IMAP LIST command. +@param aTagId Command sequence id which will be send along with the IMAP command. +@param aStream A wrapper for the outbound stream of a connected socket, using which +the command will be send to the server +*/ +void CImapListBase::SendMessageL(TInt aTagId, MOutputStream& aStream) + { + iTagId = aTagId; + + TInt bufLength = iSendMessageFormat.Length(); + bufLength += TagLength(aTagId); + bufLength += iReferenceName->Length(); + bufLength += iMailboxName->Length(); + + __ASSERT_DEBUG(iOutputBuffer==NULL, TImapServerPanic::ImapPanic(TImapServerPanic::ECommandOutputBufferNotNull)); + iOutputBuffer = HBufC8::NewL(bufLength); + iOutputBuffer->Des().Format(iSendMessageFormat, aTagId, iReferenceName, iMailboxName); + + //send the command to the server + aStream.SendDataReq(*iOutputBuffer); + } + +/** +If this is a LIST/LSUB response, then begin parsing it. +Parsing of LIST/LSUB responses is a two phase process. +First, build an atom tree using the atom parser. +The atom parser determines whether extra literal data is expected on the stream +Once the atom parser has enough data (either here or in ParseLineFollowingLiteralL()) +then the second phase is to process the atom tree by calling ProcessMailboxListL(). +Otherwise return not recognised +@return ENotRecognised (if not a LIST/LSUB response) + ECompleteUntagged (if a LIST/LSUB response with no literal data) + EResponseIncomplete (if a LIST/LSUB response wiht literal data expected) +*/ +CImapCommand::TParseBlockResult CImapListBase::ParseUntaggedResponseL() + { + TParseBlockResult result = ENotRecognised; + + // Is this a list response? + TPtrC8 part = GetNextPart(); // returns KNullDesC8 if there is no part available + + if(part.CompareF(iResponseIdentifier) == 0) + { + __ASSERT_DEBUG(iAtomParser == NULL, TImapServerPanic::ImapPanic(TImapServerPanic::EListBaseAtomParserAlreadyExists)); + iAtomParser = CImapAtomParser::NewL(ETrue, iLogId); + + TBool wantMore = iAtomParser->ProcessLineL(iUnparsedData); + if (wantMore) + { + result = EResponseIncomplete; + } + else + { + // All the data was received in the fist line. Process it now. + ProcessMailboxListL(); + result = ECompleteUntagged; + } + } + else + { + result = ENotRecognised; + } + + return result; + } + +/** +Delegates parsing of incoming literal data to the atom parser. +*/ +void CImapListBase::ParseLiteralBlockL() + { + __ASSERT_DEBUG(iAtomParser != NULL, TImapServerPanic::ImapPanic(TImapServerPanic::EListBaseAtomParserIsNull)); + iAtomParser->ProcessLiteralBlockL(iUnparsedData); + } + +/** +Delegates parsing of the incoming line of data to the atom parser. +If the atom parser has all the data it needs, then processing of the mailbox data +can begin. +@return whether further literal data is expected +*/ +TBool CImapListBase::ParseLineFollowingLiteralL() + { + __ASSERT_DEBUG(iAtomParser != NULL, TImapServerPanic::ImapPanic(TImapServerPanic::EListBaseAtomParserIsNull)); + + TBool wantMoreData = iAtomParser->ProcessLineL(iUnparsedData); + if(!wantMoreData) + { + // All the data for this LIST/LSUB response has been recieved. Process it now. + ProcessMailboxListL(); + } + + return wantMoreData; + } + +/** +Having received all the data for a LIST/LSUB response, this method processes the atom tree +representation of the response. +A CImapListFolderInfo object representing the response is populated and then inserted +in alphabetic order (based on the mailbox name) into the output array of CImapListFolderInfo objects +that was passed into this object on construction. +*/ +void CImapListBase::ProcessMailboxListL() + { + // mailbox-list = "(" [mbx-list-flags] ")" SP (DQUOTE QUOTED-CHAR DQUOTE / nil) SP mailbox + // + // mailbox = "INBOX" / astring + + __ASSERT_DEBUG(iAtomParser != NULL, TImapServerPanic::ImapPanic(TImapServerPanic::EListBaseAtomParserIsNull)); + + iAtomWalker->SetRootL(iAtomParser->RootAtom()); + iAtomWalker->WalkDownL(); + + CImapListFolderInfo* folderInfo = CImapListFolderInfo::NewL(); + CleanupStack::PushL(folderInfo); + + ProcessMailboxListFlagsL(*folderInfo); + ProcessHeirarchySeparatorL(*folderInfo); + ProcessMailboxL(*folderInfo); + + TLinearOrder sorter(CImapListFolderInfo::CompareByFolderName); + iFolderList.InsertInOrderL(folderInfo, sorter); + + // Finished with the atom tree for this response. + delete iAtomParser; + iAtomParser = NULL; + + CleanupStack::Pop(folderInfo); + } + +/** +Process the mbx-list-flags portion of the LIST/LSUB response +@param aFolderInfo recieves the flags data +*/ +void CImapListBase::ProcessMailboxListFlagsL(CImapListFolderInfo& aFolderInfo) + { + // mbx-list-flags = *(mbx-list-oflag SP) mbx-list-sflag *(SP mbx-list-oflag) / + // mbx-list-oflag *(SP mbx-list-oflag) + // + // mbx-list-oflag = "\Noinferiors" / flag-extension + // ; Other flags; multiple possible per LIST response + // + // flag-extension = "\" atom + // + // mbx-list-sflag = "\Noselect" / "\Marked" / "\Unmarked" + // ; Selectability flags; only one per LIST response + + // mbx-list-flags cannot contain brackets, so it is safe to search for its delimiting brackets + + // There may be no flags, so check for this first + if (iAtomWalker->PeekDown()) + { + iAtomWalker->WalkDownL(); + do + { + // mbx-list-oflag = "\Noinferiors" / flag-extension + if (iAtomWalker->CurrentMatch(KImapTxtNoInferiors)) + { + aFolderInfo.SetFlag(CImapListFolderInfo::ENoinferiors, ETrue); + } + + // mbx-list-sflag = "\Noselect" / "\Marked" / "\Unmarked" + // Server should only send one of these (but must send one) + else if (iAtomWalker->CurrentMatch(KImapTxtNoSelect)) + { + aFolderInfo.SetFlag(CImapListFolderInfo::ENoselect, ETrue); + } + else if (iAtomWalker->CurrentMatch(KImapTxtMarked)) + { + aFolderInfo.SetFlag(CImapListFolderInfo::EMarked, ETrue); + } + else if (iAtomWalker->CurrentMatch(KImapTxtUnmarked)) + { + aFolderInfo.SetFlag(CImapListFolderInfo::EUnmarked, ETrue); + } + + } while (iAtomWalker->WalkAcrossL(EFalse)); + + iAtomWalker->WalkUpL(); + } + } + +/** +Processes the heirarchy separator portion of the LIST/LSUB response. +@param aFolderInfo receives the heirarchy character +*/ +void CImapListBase::ProcessHeirarchySeparatorL(CImapListFolderInfo& aFolderInfo) + { + // now look for heirarchy separator + // (DQUOTE QUOTED-CHAR DQUOTE / nil) + + iAtomWalker->WalkAcrossL(ETrue); + TPtrC8 heirarchySeparator = iAtomWalker->CurrentDes(ETrue); // this is effectively an nstring + + if (heirarchySeparator.Length() == 1) + { + // this is the most likely scenario so start here. + aFolderInfo.iHierarchySeperator = heirarchySeparator[0]; + } + else if (heirarchySeparator.Length() == 0) + { + // The separator was NIL + aFolderInfo.iHierarchySeperator = KNullTerminator; + } + else + { + CorruptDataL(); // we were returned a string that was too long for a heirarchySeparator. + } + } + +/** +Extracts the mailbox name from the LIST/LSUB response. +@param aFolderInfo receives the mailbox name +*/ +void CImapListBase::ProcessMailboxL(CImapListFolderInfo& aFolderInfo) + { + iAtomWalker->WalkAcrossL(ETrue); + TPtrC8 mailboxNameUtf7 = iAtomWalker->CurrentDes(EFalse); // mailbox not an nstring. + + // Convert into ImapUtf7. + HBufC16* mailboxNameUnicode = CImapUtils::GetRef().Charconv().ConvertToUnicodeFromImapUtf7L(mailboxNameUtf7); + TPtr16 namePtr = mailboxNameUnicode->Des(); + + // Strip leading hierarchy separators + TPtrC16 stripName(namePtr); + while ((stripName.Length() > 0) && (stripName.Locate(aFolderInfo.iHierarchySeperator) == 0)) + { + stripName.Set(stripName.Mid(1)); + } + + TInt numFound = namePtr.Length() - stripName.Length(); + if (numFound > 0) + { + namePtr.Delete(0, numFound); + } + + // Strip trailing hierarchy separators + while ((namePtr.Length() > 0) && (namePtr.LocateReverse(aFolderInfo.iHierarchySeperator) == namePtr.Length() - 1)) + { + namePtr.Delete(namePtr.Length() - 1, 1); + } + + // If the first part of the path name is the inbox, make sure we use + // the uppercase version INBOX. This allows for case sensitive searches + // to be performed later. + TInt inboxLength = KIMAP_INBOX().Length(); + + // Check that the input folder name is long enough to contain INBOX and + // the hierarchy separator. + if (namePtr.Length() >= inboxLength + 1) + { + TPtrC16 inboxPart = namePtr.Left(inboxLength); + + if (inboxPart.CompareF(KIMAP_INBOX) == 0 && inboxPart.Compare(KIMAP_INBOX) != 0) + { + TPtrC16 separatorPart = namePtr.Mid(inboxLength, 1); + + if (separatorPart.Compare(iImapSettings.PathSeparator()) == 0) + { + namePtr.Replace(0, inboxLength, KIMAP_INBOX); + } + } + } + + aFolderInfo.SetFolderNameL(mailboxNameUnicode); + }