email/pop3andsmtpmtm/popservermtm/src/POPSOP.CPP
changeset 0 72b543305e3a
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/email/pop3andsmtpmtm/popservermtm/src/POPSOP.CPP	Thu Dec 17 08:44:11 2009 +0200
@@ -0,0 +1,921 @@
+// Copyright (c) 2008-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 <e32std.h>
+#include "POPS.H"		//CImPop3Session
+#include "POPSOP.H"		//CImPop3Operation
+#include "POPS.PAN"		//IMPP panic codes
+
+#include <imcvrecv.h>	//CImRecvConvert
+#include <imcvutil.h>   //ImCheckDiskSpace utility class
+#include <msvapi.h>     //MessageServer utility class
+
+const TInt KTOPRequestSize = 18; // i.e. 'TOP nnnn 1\r\n' where nnnn can be a 32 bit integer
+const TInt KTOPBatchLimit = 100; // Pipelining limit of 100 TOP requests at a time
+
+// string constants used whilst parsing response from POP3 email server
+_LIT8(KAuthMatchString,"*SASL *");
+_LIT8(KAuthPlainMatchString,"* PLAIN*");
+_LIT8(KAuthLoginMatchString,"* LOGIN*");
+_LIT8(KAuthCramMD5MatchString,"* CRAM-MD5*");
+
+// Special case for non-compliant Domino servers 
+_LIT8(KAuthDominoMatchString,"*AUTH=*"); 
+_LIT8(KAuthDominoPlainMatchString,"*=PLAIN*"); 
+_LIT8(KAuthDominoLoginMatchString,"*=LOGIN*"); 
+_LIT8(KAuthDominoCramMD5MatchString,"*=CRAM-MD5*"); 
+
+// Utility functions declared in IMPP.CPP
+GLREF_C TBool CommandAccepted(TDesC8& aResponse);
+
+// IMPP Panic function
+GLREF_C void Panic(TPopsPanic aPanic);
+//
+// CImPop3Operation - an Abstract base for all the specific POP3 operations
+//
+CImPop3Operation::CImPop3Operation()
+	: CMsgActive(KImPopSessionPriority),iFullStopTerminator(_S8(".\r\n"))
+	{
+	_LIT(KPop3Operation,"CImPop3Operation");
+	__DECLARE_NAME(KPop3Operation());
+	}
+
+CImPop3Operation::~CImPop3Operation()
+	{
+	Cancel();
+	delete iImId;
+	}
+
+//
+// 2nd stage of construction
+//
+void CImPop3Operation::Construct(CImPop3Session *aPopSession)
+	{
+	iPopSession=aPopSession;
+	iTextServer=aPopSession->TextServerSession();
+	CActiveScheduler::Add(this); 
+	}
+
+void CImPop3Operation::Construct(CImPop3Session *aPopSession, CImRecvConvert* aRecvConverter)
+	{
+	Construct(aPopSession);
+	iRecvConverter=aRecvConverter;
+	}
+
+void CImPop3Operation::DoRunL()
+	{
+	iPopSession->SetOpNotPending();
+
+	__ASSERT_ALWAYS(iTextServer->GetCurrentTextLine(iTextServerResponse)==ECRLFTerminated,User::Leave(EImppBufferNotTerminated));
+	if(CommandAccepted(iTextServerResponse)==EFalse)
+		{
+		// Message has disapeared already
+		}
+	}
+
+void CImPop3Operation::DoCancel()
+	{
+	iTextServer->Cancel();
+	if (iRecvConverter != NULL)
+		{
+		iRecvConverter->Cancel();
+		}
+	CMsgActive::DoCancel();
+	}
+//
+// Queue a read operation to get next line of text
+//
+void CImPop3Operation::QueueReadNext()
+	{
+	iTextServer->QueueReceiveNextTextLine(iStatus);
+	SetActive();
+	}
+
+//
+// Return the Pop3 mailbox index no of a message with give Babel msg id
+//
+TInt CImPop3Operation::MessageNo(TMsvId aMsgId)
+	{
+	TInt msgNo=iPopSession->MessageNo(aMsgId);
+	return msgNo;
+	}
+
+//
+// Check if there's a poperation outstainding if so panic
+//
+void CImPop3Operation::CheckIfPending()
+	{
+	iPopSession->IsPending() ? Panic(EImppOperationAlreadyPending) : iPopSession->SetPending();
+	}
+
+//
+// Retrieve a full message or just the specified no of lines
+//
+void CImPop3Operation::RetrieveMessageL()
+	{
+	iPopSession->SetOpNotPending();
+	
+	iTextServer->GetCurrentTextLine(iTextServerResponse);
+
+	if(iFirstLine)
+		{ 
+		iParsedHeader=EFalse;
+		iCommandAccepted=CommandAccepted(iTextServerResponse);
+		iFirstLine=EFalse;
+		if(!iCommandAccepted)
+			{
+			return;
+			}
+		}
+	else
+		{ 
+		TBool fakeDot=EFalse;
+		if(iTextServerResponse.Compare(iFullStopTerminator)!=0)  // header + first n lines last line is a full stop
+			{
+			RemoveFirstDot();
+			if (iRecvConverter->ParseNextField( iTextServerResponse ) == KErrNoMemory)
+				{
+				User::Leave(KErrNoMemory);
+				}
+			}
+		else if(iParsedHeader==EFalse)
+			{
+			RemoveFirstDot();
+			_LIT8(KCrLfStr,"\r\n");
+			if (iRecvConverter->ParseNextField( KCrLfStr ) == KErrNoMemory)
+				{
+				User::Leave(KErrNoMemory);
+				}    
+			fakeDot=ETrue;
+			}
+		else
+			return;
+  
+		// test for comp header
+		if(iRecvConverter->ValidCompleteHeader())
+			{
+			iParsedHeader=ETrue;
+			// test for valid headers
+			const CImHeader& header = iRecvConverter->Header();
+			iEmptyHeaders=(   (header.From().Length()==0)
+							&&(header.ReplyTo().Length()==0)
+							&&(header.ToRecipients().Count()==0)
+							&&(header.CcRecipients().Count()==0)
+							&&(header.BccRecipients().Count()==0));
+		
+			// store id of new entry created by IMCV
+			iNewEntryId = iRecvConverter->EntryId();
+			// store internet msg id
+			HBufC8* imId = header.ImMsgId().AllocL();
+			delete iImId;
+			iImId = NULL;
+			iImId = imId;
+			}
+ 
+		if(fakeDot!=EFalse)
+			{
+			return;
+			}
+		}
+ 
+	QueueReadNext();
+	}
+
+//
+// What to do on completion
+//
+void CImPop3Operation::DoComplete(TInt& /*aCompleteRequest*/)
+	{
+	}
+
+TBool CImPop3Operation::PopCommandAccepted()
+	{
+	return iCommandAccepted;
+	}
+
+//
+// Remove first dot of a pair
+//
+void CImPop3Operation::RemoveFirstDot()
+	{
+	if(iTextServerResponse.Length()>2)
+		{
+		if( (iTextServerResponse[0]=='.') && (iTextServerResponse[1]=='.'))
+			{
+			iTextServerResponse.Delete(0,1);
+			}
+		}
+	}
+
+TPtrC8 CImPop3Operation::ImMsgId()
+	{ 
+	return (iImId ? TPtrC8(*iImId) : TPtrC8()); 
+	}
+
+TBool CImPop3Operation::SetMessage(TMsvId anId)
+	{
+	iMessageNo=MessageNo(anId);
+	return iMessageNo == KErrNotFound ? EFalse: ETrue;
+	}
+
+
+//
+// CImPop3Stat return no of messages and the mailbox size
+//
+CImPop3Stat* CImPop3Stat::NewL(CImPop3Session *aPopSession)
+	{
+	CImPop3Stat* self = new (ELeave) CImPop3Stat();
+	self->Construct(aPopSession);
+	return self;
+	}
+
+void CImPop3Stat::Start(TRequestStatus& aStatus, TUint &aNoMsg, TUint &aMboxSize)
+	{
+	CheckIfPending();
+
+	iNoMessages=&aNoMsg;
+	iMailboxSize=&aMboxSize;
+
+	_LIT8(KStatCrLfStr,"STAT\r\n");
+	iTextServer->SendQueueReceive(iStatus, KStatCrLfStr());
+	SetActive();
+	Queue(aStatus);
+	}
+
+// Got a response from the text server
+
+void CImPop3Stat::DoRunL()
+	{
+	iPopSession->SetOpNotPending();
+	__ASSERT_ALWAYS(iTextServer->GetCurrentTextLine(iTextServerResponse)==ECRLFTerminated,User::Leave(EImppBufferNotTerminated));
+		
+	if(CommandAccepted(iTextServerResponse))
+		{
+		TLex8 parseResponse(iTextServerResponse);
+		parseResponse.SkipCharacters();
+		parseResponse.SkipSpace();
+
+		if(parseResponse.Val(*iNoMessages)==KErrNone)
+			{
+			parseResponse.SkipSpace();
+			parseResponse.Val(*iMailboxSize);
+			}
+		else
+			*iNoMessages=0;
+		}
+	}
+
+//
+// CImPop3List list a specific message no  and size or all messages and sizes
+//
+CImPop3List* CImPop3List::NewL(CImPop3Session *aPopSession)
+	{
+	CImPop3List* self = new (ELeave) CImPop3List();
+	self->Construct(aPopSession);
+	return self;
+	}
+
+void CImPop3List::Start(TRequestStatus& aStatus, TUint* aSize)
+	{
+	CheckIfPending();
+	iSize=aSize;
+	iArrayPos=0;
+
+	if(iMessageNo!=0)
+		{
+		_LIT8(KListArgCrLfStr,"LIST %d\r\n");
+		iTextServer->SendQueueReceive(iStatus, KListArgCrLfStr, iMessageNo);
+		}
+	else
+		{
+		_LIT8(KListCrLfStr,"LIST\r\n");
+		iTextServer->SendQueueReceive(iStatus,KListCrLfStr());
+		iFirstLine=ETrue;
+		}
+
+	SetActive();
+	Queue(aStatus);
+	}
+
+void CImPop3List::DoRunL()
+	{
+	iPopSession->SetOpNotPending();
+	
+	__ASSERT_ALWAYS(iTextServer->GetCurrentTextLine(iTextServerResponse)==ECRLFTerminated,User::Leave(EImppBufferNotTerminated));
+	TLex8 parseResponse(iTextServerResponse);
+
+	if(iNoResponses > 0)
+		{
+		if(CommandAccepted(iTextServerResponse))
+		User::Leave(KErrNotFound);
+		}
+		
+	if(iMessageNo!=0)
+		{
+		if(CommandAccepted(iTextServerResponse))
+			{
+			parseResponse.SkipCharacters();
+			parseResponse.SkipSpace();
+			GetIndexAndSize(&parseResponse);
+			}
+		else
+			Panic(EImppBabelMsgDoesNotExist);
+		}
+	else
+		{
+		if(iFirstLine)
+			{
+			if(CommandAccepted(iTextServerResponse))
+				{
+				iFirstLine=EFalse;
+				}
+			else
+				{
+				return;
+				}
+			}
+		else
+			{
+			if(iTextServerResponse.Compare(iFullStopTerminator)==0)  // list of message info last line is a full stop
+				{
+				return;
+				}
+			else
+				{
+				if(GetIndexAndSize(&parseResponse)==KErrNone)
+					{
+					iArrayPos++;
+					iNoResponses++;
+					}
+				else
+					{
+					iSize[iArrayPos] = 0;
+					}
+				}
+			}
+		QueueReadNext();
+		}
+	}
+
+//
+// Get size of a specific message (folder view displays message sizes)
+//
+TInt CImPop3List::GetIndexAndSize(TLex8 *aLex)
+	{
+	aLex->SkipCharacters();
+	aLex->SkipSpace();
+	return(aLex->Val(iSize[iArrayPos]));
+	}
+
+//
+// CImPop3Retr Retrieve a specific message
+//
+CImPop3Retr* CImPop3Retr::NewL(CImPop3Session *aPopSession, CImRecvConvert* aRecvConverter, RFs& aFs)
+	{
+	CImPop3Retr* self = new (ELeave) CImPop3Retr(aFs);
+	CleanupStack::PushL(self);
+	self->ConstructL(aPopSession, aRecvConverter);
+	CleanupStack::Pop(self);
+	return self;
+	}
+void CImPop3Retr::ConstructL(CImPop3Session *aPopSession, CImRecvConvert* aRecvConverter)
+	{
+	Construct(aPopSession,aRecvConverter);
+	iCurrentDrive = MessageServer::CurrentDriveL(iFs);
+	}
+
+void CImPop3Retr::StartL(TRequestStatus& aStatus)
+	{
+	CheckIfPending();
+	iFirstLine=ETrue;
+	iNoBytesRetrieved=0;
+	iEmptyHeaders = EFalse;
+	ImCheckDiskSpace::LeaveIfLowDiskL(iFs, iCurrentDrive);
+
+	iRecvConverter->ResetL();
+	
+	_LIT8(KRetrArgCrLfStr,"RETR %d\r\n");
+	iTextServer->SendQueueReceive(iStatus, KRetrArgCrLfStr, iMessageNo);
+	SetActive();
+	Queue(aStatus);
+	}
+
+void CImPop3Retr::DoRunL()
+	{
+	RetrieveMessageL();
+	if(iFirstLine==EFalse)
+		{
+		iNoBytesRetrieved+=iTextServerResponse.Length();
+		}
+	}
+
+TUint CImPop3Retr::Progress()
+	{
+	return iNoBytesRetrieved;
+	}
+
+void CImPop3Retr::SetMessageIndex(TInt anIndex)
+	{
+	iMessageNo=anIndex;
+	}
+//
+// CImPop3Dele Delete a specified message
+//
+CImPop3Dele* CImPop3Dele::NewL(CImPop3Session *aPopSession)
+	{
+	CImPop3Dele* self = new (ELeave) CImPop3Dele();
+	self->Construct(aPopSession);
+	return self;
+	}
+
+void CImPop3Dele::Start(TRequestStatus& aStatus)
+	{
+	CheckIfPending();
+
+	_LIT8(KDeleArgCrLfStr,"DELE %d\r\n");
+	iTextServer->SendQueueReceive(iStatus, KDeleArgCrLfStr, iMessageNo);
+	SetActive();
+	Queue(aStatus);
+	}
+
+
+//
+// CImPop3Noop No operation (but I'm still here)
+//
+CImPop3Noop* CImPop3Noop::NewL(CImPop3Session *aPopSession)
+	{
+	CImPop3Noop* self = new (ELeave) CImPop3Noop();
+	self->Construct(aPopSession);
+	return self;
+	}
+
+void CImPop3Noop::Start(TRequestStatus& aStatus)
+	{
+	CheckIfPending();
+
+	_LIT8(KNoopCrLfStr,"NOOP\r\n");
+	iTextServer->SendQueueReceive(iStatus, KNoopCrLfStr());
+	SetActive();
+	Queue(aStatus);
+	}
+
+//
+// CImPop3Rset Reset
+//
+CImPop3Rset* CImPop3Rset::NewL(CImPop3Session *aPopSession)
+	{
+	CImPop3Rset* self = new (ELeave) CImPop3Rset();
+	self->Construct(aPopSession);
+	return self;
+	}
+
+void CImPop3Rset::Start(TRequestStatus& aStatus)
+	{
+	CheckIfPending();
+	_LIT8(KRsetCrLfStr,"RSET\r\n");
+	iTextServer->SendQueueReceive(iStatus, KRsetCrLfStr());
+	SetActive();
+	Queue(aStatus);
+	}
+
+//
+// Return specified header and top n lines of message.
+// If the POP server supports pipelining, TOP requests will be submitted in
+// batches. The batch size limit is 100 requests.
+//
+CImPop3Top* CImPop3Top::NewL(CImPop3Session *aPopSession, CImRecvConvert* aRecvConverter,TBool aHeaderOnly)
+	{
+	CImPop3Top* self = new (ELeave) CImPop3Top();
+	self->ConstructL(aPopSession,aRecvConverter,aHeaderOnly);
+	return self;
+	}
+
+void CImPop3Top::ConstructL(CImPop3Session *aPopSession, CImRecvConvert* aRecvConverter,TBool aHeaderOnly)
+	{
+	CImPop3Operation::Construct(aPopSession,aRecvConverter);
+	iHeadersOnly = aHeaderOnly;
+	}
+
+void CImPop3Top::StartL(TRequestStatus& aStatus)
+	{
+	CheckIfPending();
+	iFirstLine=ETrue;
+	iNoBytesRetrieved=0;
+	iEmptyHeaders = EFalse;
+
+	if (iHeadersOnly)
+		{
+		iRecvConverter->ResetForHeadersL();
+		}
+	else
+		{
+		iRecvConverter->ResetL();
+		}
+
+	if(iPipeliningSupported)
+		{
+		if(iMessageNo <= iLastMulti)
+			{
+			TInt numberToGet = iLastMulti - iStartMsg;
+			TInt tempStartPos(iStartMsg);
+			if (numberToGet > KTOPBatchLimit)
+				{
+				tempStartPos = iLastMulti - KTOPBatchLimit;
+				numberToGet = KTOPBatchLimit;
+				}
+			HBufC8* buffer = HBufC8::NewLC(numberToGet * KTOPRequestSize);
+			TPtr8 bufferPtr = buffer->Des();
+			for(; iLastMulti > tempStartPos; --iLastMulti)
+				{
+ 				if(iPopSession->MessageArray()[iLastMulti-1]==0)
+					{
+					_LIT8(KTopArgArgCrLfStr,"TOP %d %d\r\n");
+ 					bufferPtr.AppendFormat( KTopArgArgCrLfStr, iLastMulti, iNoLines );
+ 					}
+				}
+			iTextServer->SendQueueReceive(iStatus, bufferPtr);
+			CleanupStack::PopAndDestroy(buffer);
+			}
+		else
+			{
+			// These headers should be on their way already, queue another read
+            QueueReadNext(); // This calls SetActive() for us
+            Queue(aStatus);
+            return;
+			}
+		}
+	else // pipelining not supported by server
+		{
+		_LIT8(KTopArgArgCrLfStr,"TOP %d %d\r\n");
+		iTextServer->SendQueueReceive(iStatus, KTopArgArgCrLfStr, iMessageNo, iNoLines);
+		}
+	SetActive();
+	Queue(aStatus);
+	}
+
+void CImPop3Top::DoRunL()
+	{
+	RetrieveMessageL();
+	if(iFirstLine==EFalse)
+		{
+		iNoBytesRetrieved+=iTextServerResponse.Length();
+		}
+	}
+
+TBool CImPop3Top::SetMessageAndLines(TMsvId aId, TInt aNoLines)
+	{
+	iNoLines=aNoLines;
+	return SetMessage(aId);
+	}
+
+void CImPop3Top::SetMessageIndexAndLines(TInt anIndex, TInt aNoLines)
+	{
+	iMessageNo=anIndex;
+	iNoLines=aNoLines;
+	}
+	
+void CImPop3Top::SetStartAndEndMessageIndex(TInt aStart, TInt aEnd)
+	{
+	iPipeliningSupported = ETrue;
+	iStartMsg = aStart;
+	iLastMulti = aEnd + 1; // off by one 
+	}
+
+TUint CImPop3Top::Progress()
+	{
+	return iNoBytesRetrieved;
+	}
+
+// CImPop3UidlMap
+//
+CImPop3UidlMap* CImPop3UidlMap::NewL(TInt aMsgCount)
+	{
+	return new(ELeave) CImPop3UidlMap(aMsgCount);
+	}
+
+CImPop3UidlMap::~CImPop3UidlMap()
+	{}
+
+void CImPop3UidlMap::BindL(TInt aMsgIx,const TDesC8& aUidl)
+	{
+	// Insert mail Uidls into Uidl array including duplicated uidls.
+	TInt pos = iUid.InsertIsqAllowDuplicatesL(aUidl,ECmpNormal); 
+	iMsgNo.InsertL(pos,aMsgIx);
+	}
+
+
+TInt CImPop3UidlMap::MsgNo(const TDesC8& aUidl) const
+	{
+	TInt pos;
+	if (iUid.FindIsq(aUidl,pos,ECmpNormal)==0)
+		{
+		return iMsgNo[pos];
+		}
+	return -1;
+	}
+
+TPtrC8 CImPop3UidlMap::At(TInt aMsgIx) const
+	{
+	if (iMsgNo.Count())
+		{
+		const TInt* p=&iMsgNo[0];
+		for (TInt ii=iMsgNo.Count();--ii>=0;)
+			{
+			if (p[ii]==aMsgIx)
+				{
+				return iUid[ii];
+				}
+			}
+		}
+	return TPtrC8();
+	}
+
+CImPop3UidlMap::CImPop3UidlMap(TInt aMsgCount)
+	:iUid(aMsgCount),iMsgNo(aMsgCount)
+	{
+	__DECLARE_NAME(_S("CImPop3UidlMap"));
+	}
+
+//
+// CImPop3 Uidl return unique id for a specified message or all the messages
+//
+CImPop3Uidl* CImPop3Uidl::NewL(CImPop3Session *aPopSession)
+	{
+	CImPop3Uidl* self = new (ELeave) CImPop3Uidl();
+	self->Construct(aPopSession);
+	return self;
+	}
+
+void CImPop3Uidl::Start(TRequestStatus& aStatus, CImPop3UidlMap& anArray)
+	{
+	CheckIfPending();
+	iMsgUid=&anArray;
+	if(iMessageNo!=0)
+		{
+		_LIT8(KUidlArgCrLfStr,"UIDL %d\r\n");
+		iTextServer->SendQueueReceive(iStatus, KUidlArgCrLfStr, iMessageNo);
+		}
+	else
+		{
+		_LIT8(KUidlCrLfStr,"UIDL\r\n");
+		iTextServer->SendQueueReceive(iStatus, KUidlCrLfStr());
+		iFirstLine=ETrue;
+		}
+	SetActive();
+	Queue(aStatus);
+	}
+
+void CImPop3Uidl::DoRunL()
+	{
+	iPopSession->SetOpNotPending();
+	__ASSERT_ALWAYS(iTextServer->GetCurrentTextLine(iTextServerResponse)==ECRLFTerminated,User::Leave(EImppBufferNotTerminated));
+	TLex8 parseResponse(iTextServerResponse);
+
+	if(iMessageNo!=0) // one specific Uid
+		{
+		iCommandAccepted=CommandAccepted(iTextServerResponse);
+		if(iCommandAccepted)
+			{
+			parseResponse.SkipCharacters();
+			parseResponse.SkipSpace();
+			GetIndexAndUidL(&parseResponse);
+			}
+		else
+			Panic(EImppBabelMsgDoesNotExist);
+		}
+	else // list all Uids
+		{
+		if(iFirstLine)
+			{
+			iCommandAccepted=CommandAccepted(iTextServerResponse);
+			if(iCommandAccepted)
+				{
+				iFirstLine=EFalse;
+				}
+			else
+				{
+				return;
+				}
+			}
+		else
+			{
+			if(iTextServerResponse.Compare(iFullStopTerminator)==0) // list of message info last line is a full stop
+				{
+				return;
+				}
+			else
+				{
+				GetIndexAndUidL(&parseResponse);
+				}
+			}
+		QueueReadNext();
+		}
+	}
+
+//
+// Get index no and Pop id of a message
+//
+void CImPop3Uidl::GetIndexAndUidL(TLex8* aLex)
+	{
+	TInt msgNo;
+	TInt lexErr=aLex->Val(msgNo);
+	TLexMark8 uidMarker;
+
+	if(lexErr==KErrNone)
+		{
+		aLex->SkipSpace();
+		aLex->Mark(uidMarker);
+		aLex->SkipCharacters();
+		iMsgUid->BindL(msgNo-1,aLex->MarkedToken( uidMarker ));
+		}
+	}
+
+//
+// CImPop3Capa returns the list of capabilities supported by the server
+//
+CImPop3Capa* CImPop3Capa::NewL(CImPop3Session *aPopSession)
+	{
+	CImPop3Capa* self = new (ELeave) CImPop3Capa();
+	self->Construct(aPopSession);
+	return self;
+	}
+
+void CImPop3Capa::Start(TRequestStatus& aStatus)
+	{
+	CheckIfPending();
+	_LIT8(KCapaCrLfStr,"CAPA\r\n");
+	iTextServer->SendQueueReceive(iStatus, KCapaCrLfStr());
+	iFirstLine = ETrue;
+	SetActive();
+	Queue(aStatus);
+	}
+
+// Got a response from the text server
+void CImPop3Capa::DoRunL()
+	{
+	iPopSession->SetOpNotPending();
+
+	iTextServer->GetCurrentTextLine(iTextServerResponse);
+	if(iFirstLine)
+		{ 
+		iCommandAccepted = CommandAccepted(iTextServerResponse);
+		iFirstLine = EFalse;
+		if(!iCommandAccepted)
+			{
+			return;
+			}
+		}
+	else
+		{
+		if(iTextServerResponse.Compare(iFullStopTerminator) != 0)
+			{
+			TInt crPos = iTextServerResponse.Find(KImcvCRLF);
+			if(crPos>0)
+				{
+				TPtrC8 ptr;
+				ptr.Set(iTextServerResponse.Left(crPos));
+				_LIT8(KPipelining, "PIPELINING");
+				
+				if(ptr.CompareF(KPipelining) == 0)
+					{
+					iPipeliningSupported = ETrue;
+					}
+					
+#if (defined SYMBIAN_EMAIL_CAPABILITY_SUPPORT)				
+				if (iTextServerResponse.Match(KAuthMatchString) != KErrNotFound || 
+    					iTextServerResponse.Match(KAuthDominoMatchString) != KErrNotFound)
+					{
+					SetSaslAuthExtensionFlag();
+					}
+#endif					
+				}
+			else
+				return;
+			}
+		else
+			return;
+		}
+	QueueReadNext();
+	}
+
+TBool CImPop3Capa::PipeliningSupport()
+	{
+	return iPipeliningSupported;
+	}
+	
+#if (defined SYMBIAN_EMAIL_CAPABILITY_SUPPORT)
+
+/**
+To check the Server Response for CAPABILITY command and set iSupportedAuthProfiles accordingly.
+*/
+void CImPop3Capa::SetSaslAuthExtensionFlag()
+	{
+	// check for each supported profile
+	if (iTextServerResponse.Match(KAuthMatchString) != KErrNotFound)
+		{
+		if (iTextServerResponse.Match(KAuthPlainMatchString) != KErrNotFound)
+			{
+			iSupportedAuthProfiles|=CPopAuthMechanismHelper::EPlain;
+			}
+			
+		if (iTextServerResponse.Match(KAuthLoginMatchString) != KErrNotFound)
+			{
+			iSupportedAuthProfiles|=CPopAuthMechanismHelper::ELogin;
+			}
+			
+		if (iTextServerResponse.Match(KAuthCramMD5MatchString) != KErrNotFound)
+			{
+			iSupportedAuthProfiles|=CPopAuthMechanismHelper::ECramMD5;
+			}
+		}
+		
+	// Special case for Domino servers tagging "=" after "AUTH" 
+	if (iTextServerResponse.Match(KAuthDominoMatchString) != KErrNotFound)	
+		{
+		if (iTextServerResponse.Match(KAuthDominoPlainMatchString) != KErrNotFound) 
+			{
+			iSupportedAuthProfiles|=CPopAuthMechanismHelper::EPlain; 
+			}
+    		
+   		if (iTextServerResponse.Match(KAuthDominoLoginMatchString) != KErrNotFound) 
+   			{
+   			iSupportedAuthProfiles|=CPopAuthMechanismHelper::ELogin; 
+   			}
+    		
+   		if (iTextServerResponse.Match(KAuthDominoCramMD5MatchString) != KErrNotFound) 
+   			{
+   			iSupportedAuthProfiles|=CPopAuthMechanismHelper::ECramMD5;
+   			}
+   		}
+   	}
+
+/**
+To get iSupportedAuthProfiles value.
+*/	
+TUint CImPop3Capa::SaslAuthExtensionFlag()
+	{
+	return iSupportedAuthProfiles;
+	}
+#endif
+
+// Function will return Index of message(if unique UIDL) Or KErrAlreadyExists(if Duplicate UIdl)
+//Or KErrNotFound if UIdl not present..
+TInt CImPop3UidlMap::MsgUidlNo(const TDesC8& aUidl,TInt& aPos) const
+	{
+	if (iUid.FindIsq(aUidl,aPos,ECmpNormal) == 0)
+		{
+		if(aPos > 0 )
+			{
+			//To Check that the index does not exceed size of the iUid array.
+		 	if(aPos == (iMsgNo.Count() - 1))
+		 		{
+		  		if ((iUid[aPos-1]) == aUidl) 
+		 			{
+					return KErrAlreadyExists;
+					}
+				 }
+			 else
+			 	{
+			 	if ((iUid[aPos-1]) == aUidl || (iUid[aPos+1]) == aUidl) 
+			 		{
+			 		return KErrAlreadyExists;
+			 		}
+			 		
+			 	}	 
+			}
+			return iMsgNo[aPos];
+			
+		}
+	return KErrNotFound;
+	}
+
+
+// To return the Index of the UIDL corresponding to a UIDL position.
+TInt CImPop3UidlMap::MsgIndex(TInt aPos) const
+	{
+	return iMsgNo[aPos];
+	}
+
+// To get the no. of UIDLs in the server..
+TInt CImPop3UidlMap::MsgCount() const
+	{
+	return iMsgNo.Count();
+	}
+
+//Return the UIDL at aPos.
+TPtrC8  CImPop3UidlMap::MsgUidl(TInt aPos) const
+	{
+	return iUid[aPos];
+	}