email/imap4mtm/imapsession/inc/cimapcommand.h
changeset 0 72b543305e3a
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/email/imap4mtm/imapsession/inc/cimapcommand.h	Thu Dec 17 08:44:11 2009 +0200
@@ -0,0 +1,321 @@
+// 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:
+//
+
+#ifndef __CIMAPCOMMAND_H__
+#define __CIMAPCOMMAND_H__
+
+#include <e32std.h>
+#include <mentact.h>
+#include <msvstd.h>
+
+// Typedefs
+typedef RArray<TPtrC8> RDesParts;
+
+// Forward Declaration
+class MOutputStream;
+class CImapFolderInfo;
+
+/**
+Abstract base class for sending IMAP commands and receiving and parsing IMAP responses.
+Each implementation of this class represents a single IMAP command together with its expected responses.
+Each implementation can use this base class to handle unsolicited responses.
+
+@internalTechnology
+@prototype
+*/
+class CImapCommand : public CBase
+	{
+public:
+	/**
+	Identifies the tagged response code that was received for this message.
+	*/
+	enum TResponseCode 
+		{
+		/** 
+		No tagged response has been received yet.
+		The command is not yet complete.
+		*/
+		EImapResponseNone,
+		/**
+		A tagged OK response has been received.
+		The command has completed successfully.
+		Note that receipt of an UNTAGGED OK response should not cause iResponse code to be updated to this value.
+		*/
+		EImapResponseOk,
+		/**
+		A tagged NO response has been received.
+		The server has completed the command by refusing to run it. 
+		*/
+		EImapResponseNo, 
+		/**
+		A tagged BAD response has been received.
+		The server has completed the command because it did not understand the command and was not able to run it.
+		*/
+		EImapResponseBad 
+		};
+	
+	/**
+	The result of parsing a block of data.  
+	This indicates how the block was parsed, and whether further data is expected.
+	*/
+	enum TParseBlockResult
+		{
+		/**
+		The block was not recognised, so we need to do generic handling.
+		*/
+		ENotRecognised,
+		/**
+		The block was parsed, but more data (e.g. a literal block) is needed for this response.
+		*/
+		EResponseIncomplete,
+		/**
+		The block was parsed and the whole of an untagged response has now been received.
+		No more data is expected for this response.
+		but the command is still expecting to receive a tagged response.
+		*/
+		ECompleteUntagged,
+		/**
+		The block was parsed and the whole of a tagged response has now been received.
+		No more data is expected for this command.
+		The result code can be accessed using CImapCommand::Result();
+		*/
+		ECompleteTagged,
+		};
+	
+	/**
+	Indicates what kind of data is expected next (if any) and how to handle it.
+	*/	
+	enum TParseState
+		{
+		/**
+		CImapCommand is waiting for the beginning of a new tagged or untagged response.
+		A line of data is expected, starting with a tag, * or + character.
+		*/
+		EWaitStartResponse,
+		/**
+		The subclass is in the middle of parsing a response.
+		It is expecting a block of literal data.
+		*/
+		EWaitLiteralParse,
+		/**
+		The subclass is in the middle of parsing a response.
+		It is expecting a line of data.
+		*/
+		EWaitLineParse,
+		/**
+		CImapCommand is in the middle of discarding a response, 
+		so that it can get to the start of the next response.
+		It is expecting a block of literal data.
+		*/
+		EWaitLiteralIngore,
+		/**
+		CImapCommand is in the middle of discarding a response, 
+		so that it can get to the start of the next response.
+		It is expecting a line of data.
+		*/
+		EWaitLineIgnore,
+		/**
+		The final tagged response for this command has been received.
+		No more data is expected.
+		*/
+		ECommandComplete
+		};
+		
+	enum { KMinPartsForIsLineTagged = 2	};
+	
+	enum TTagType 
+		{ 
+		ETagged,
+		EUntagged,
+		EContinuation 
+		};
+
+	~CImapCommand();
+	
+	/**
+	Sends the command represented by this object as a message to the IMAP server.
+	@param aTagId Used to generate the IMAP tag that identifies the message.
+	@param aStream The output stream on which the message will be sent.
+	The provided output stream should already be set up and ready to use.
+	*/
+	virtual void SendMessageL(TInt aTagId, MOutputStream& aStream)=0;
+	
+	virtual void SendDataCnfL();
+		
+	TParseState ParseBlockL(const TDesC8& aData);
+	
+	virtual void WaitingForMoreDataL();
+	
+	virtual void Cancel();
+	TBool Flushing() const;
+	virtual TBool CanCompleteFlushNow() const;
+	
+	TResponseCode ResponseCode() const;
+	TInt LiteralBytesExpected() const;
+	
+	static void CorruptDataL(TInt aLogId);
+	void CorruptDataL();
+	
+	static HBufC8* EncodeMailboxNameForSendL(const TDesC16& aMailboxName);
+	static TBool CheckForPrintableAtomSpecial(const TDesC8& aString, TInt& aCountQuotedSpecials);
+
+	// Utility methods for parsing
+	static TInt TagLength(TInt aTagId);
+	static void GetDelimitedPartsL(TChar aDelimiter, const TDesC8& aData, RDesParts& aOutDelimitedPartsList, TInt aMaxParts = 0);
+		
+	TInt GetTagId() ;
+	
+protected:
+	CImapCommand(CImapFolderInfo* aSelectedFolderData, TInt aLogId);
+
+	/**
+	This is called after whole line or literal block has been received.
+	An implementation of this method should parse the supplied data and store the results
+	in the subclass's data members.
+	@param aData The data to be parsed.  This will either be a single line or single block of literal data.
+			The first call to ParseMessageL() will always receive a line.
+			Subsequent calls will receive whatever was requested in the return value of the previous call to this method.
+	@return This indicates how the block was parsed, and whether further data is expected.
+	*/	
+	virtual TParseBlockResult DoParseBlockL(const TDesC8& aData) = 0;
+	
+	virtual TInt NumberOfTaggedResponsesExpected() const;
+	void ParseStartResponseFlushL(const TDesC8& aData);	
+
+	TTagType GetTagTypeL(TInt& aTagId);
+	TPtrC8 GetNextPart();
+	TPtrC8 PeekNextPart();
+	TPtrC8 Remainder();
+	TPtrC8 GetResponseTextCodeL();
+	TResponseCode GetResponseStateCode();
+
+	void EnterFlushingState();
+	
+	// Access Methods
+	void SetParseState(TParseState aParseState);
+	TParseState ParseState() const;
+	
+	void SetMessageFlagsChanged();
+		
+private:
+	void ParseLineL(const TDesC8& aLine);
+	void ParseLiteralL(const TDesC8& aLiteralBlock);
+
+	TParseBlockResult ParseUnhandledBlockL(const TDesC8& aLine);
+	TInt PeekLiteralRequest(const TDesC8& aLine);
+
+protected:
+	/**
+	Stores the tag id supplied by SendMessage()
+	Use iTagId to validate that tagged responses have the correct tag id.
+	*/
+	TInt iTagId;
+	/**
+	Holds the data to be sent on the output stream to the remote server.
+	*/
+	HBufC8* iOutputBuffer;
+	
+	TPtrC8 iUnparsedData;
+	/**
+	Pointer to the folder data object for the currently selected mailbox.
+	The pointer can be NULL if no mailbox is currently selected.
+	The pointer is NOT owned by this object.
+	*/
+	CImapFolderInfo* iSelectedFolderData;
+	
+	/**
+	Stores the tag completion code of the response message
+	*/
+	TResponseCode iResponseCode;
+	
+	/**
+	Most commands are complete only when the tagged response is received.
+	However there are some scenarios where receipt of any response is sufficient 
+	to complete the command - in which case this flag should be set to ETrue.
+	*/
+	TBool iCompleteOnAnyResponse;
+	
+	/**
+	If a literal block is expected in the next call to ParseBlockL(), then
+	the number of bytes expected is recorded here.
+	0 indicates that a literal block is not expected.
+	*/
+	TInt iLiteralBytesExpected;
+#if (defined SYMBIAN_EMAIL_CAPABILITY_SUPPORT)			
+	/**
+	If message body is downloaded using FETCH BINARY.
+	The number of bytes received for previous fetch is recorded here.
+	This valued is used to make sure that there are no extra body fetch command are issued 
+	*/
+	TInt iPreviousLiteralBytesReceived;
+#endif
+	
+	/**
+	The log id of the session that owns this command object.
+	*/
+	TInt iLogId;
+	
+private:
+	/**
+	Indicates what kind of data is expected next (if any) and how to handle it.
+	*/
+	TParseState iParseState;
+	
+	/**
+	When true, all incoming data is ignored until the last tagged response.
+	*/
+	TBool iFlushing;
+	
+	/**
+	Counts the number of tagged responses that need to be flushed.
+	Usually, this is just the one, but for pipelined commands many requests
+	are made at a time, so many tagged responses need to be flushed after a cancel.
+	*/
+	TInt iTaggedResponsesToFlush;
+	};
+
+/**
+Provides a migration path that replaces DoParseBlockL() with separate 
+subclass methods for different kinds of incoming data.
+*/
+class CImapCommandEx : public CImapCommand
+	{
+protected:
+	CImapCommandEx(CImapFolderInfo* aSelectedFolderData, TInt aLogId);
+	
+	void BaseParseTaggedResponseL(TInt aTagId);
+
+	/**
+	Called when a tagged response is received.
+	iUnparsed data contains the incoming line, excluding the tag.
+	@param aTagId The value of the incoming tag.
+	@return Whether this tags response completes the command.  
+			Unless multiple commands are being sent (e.g. in fetch body), this should return ETrue.
+	*/
+	virtual TBool ParseTaggedResponseL(TInt aTagId);
+	virtual void ParseContinuationResponseL();
+
+	virtual TParseBlockResult ParseUntaggedResponseL();
+	virtual void ParseLiteralBlockL();
+	virtual TBool ParseLineFollowingLiteralL();
+	
+private:
+	TParseBlockResult ParseStartResponseL();
+
+	// Implements CImapCommand
+	TParseBlockResult DoParseBlockL(const TDesC8& aData);
+	};
+
+#endif // __CIMAPCOMMAND_H__