email/imap4mtm/imapsession/src/cimapsession.cpp
changeset 0 72b543305e3a
child 19 7e4e4bcc75b6
equal deleted inserted replaced
-1:000000000000 0:72b543305e3a
       
     1 // Copyright (c) 2006-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 //
       
    15 
       
    16 
       
    17 #include "cimapsession.h"
       
    18 
       
    19 #include "moutputstream.h"
       
    20 #include "minputstream.h"
       
    21 
       
    22 #include "cimapsessionconsts.h"
       
    23 
       
    24 #include "cimapidle.h"
       
    25 #include "cimapservereventwait.h"
       
    26 #include "cimapservergreeting.h"
       
    27 #include "cimapservergreetinginfo.h"
       
    28 #include "cimapcapability.h"
       
    29 #include "cimapcapabilityinfo.h"
       
    30 #include "cimapnoop.h"
       
    31 #include "cimaplogout.h"
       
    32 #include "cimaplogin.h"
       
    33 #include "cimapstarttls.h"
       
    34 #include "cimapselect.h"
       
    35 #include "cimapexamine.h"
       
    36 #include "cimapcreate.h"
       
    37 #include "cimapdelete.h"
       
    38 #include "cimaprename.h"
       
    39 #include "cimapsubscribe.h"
       
    40 #include "cimapunsubscribe.h"
       
    41 #include "cimaplist.h"
       
    42 #include "cimaplsub.h"
       
    43 #include "cimapstatus.h"
       
    44 #include "cimapappend.h"
       
    45 #include "cimapsearch.h"
       
    46 #include "cimapclose.h"
       
    47 #include "cimapstore.h"
       
    48 #include "cimapcopy.h"
       
    49 #include "cimapexpunge.h"
       
    50 #include "cimapfetchflags.h"
       
    51 #include "cimapfetchbody.h"
       
    52 #include "cimapfetchsinglebodystructure.h"
       
    53 #include "cimapfetchmultibodystructures.h"
       
    54 #include "cimapfetchbodyresponse.h"
       
    55 #include "cimaplogger.h"
       
    56 #include "imappaniccodes.h"
       
    57 
       
    58 #if (defined SYMBIAN_EMAIL_CAPABILITY_SUPPORT)
       
    59 	#include "cimapauthhelpers.h"
       
    60 #endif
       
    61 /**
       
    62 An RBuf buffer is used to create the sequence set string.
       
    63 This specifies by how the buffer should grow each time it needs to be expanded.
       
    64 */
       
    65 const TInt KSequenceSetGranularity = 32;
       
    66 /**
       
    67 A CBufFlat buffer is used to store incoming string data whenever incoming data needs to be spliced
       
    68 together in order to form a contiguous line or literal block.
       
    69 This specifies by how the buffer should grow each time it needs to be expanded.
       
    70 */
       
    71 const TInt KInputCacheGranularity = 1024;
       
    72 /**
       
    73 During a flush (after cancelling a command),
       
    74 time out if data is not received within 10 seconds of requesting it.
       
    75 */
       
    76 const TInt KFlushTimeoutPeriod = 10*1000*1000;
       
    77 
       
    78 #ifdef __IMAP_LOGGING
       
    79 _LIT(KLogFileName, "imlog%d");
       
    80 #endif //__IMAP_LOGGING
       
    81 
       
    82 /**
       
    83 The factory constructor. Part of two phased construction.
       
    84 */
       
    85 EXPORT_C CImapSession* CImapSession::NewL(CImapSettings& aImapSettings, CImapMailStore& aImapMailStore, MInputStream& aInputStream, MOutputStream& aOutputStream)
       
    86 // static method
       
    87 	{
       
    88 	CImapSession* self = new(ELeave) CImapSession(aImapSettings, aImapMailStore, aInputStream, aOutputStream);
       
    89 	CleanupStack::PushL(self);
       
    90 	self->ConstructL();
       
    91 	CleanupStack::Pop(self);
       
    92 	return self;
       
    93 	}
       
    94 
       
    95 CImapSession::CImapSession(CImapSettings& aImapSettings, CImapMailStore& aImapMailStore, MInputStream& aInputStream, MOutputStream& aOutputStream)
       
    96 	: iImapSettings(aImapSettings), iImapMailStore(aImapMailStore) 
       
    97 	, iInputStream(&aInputStream), iOutputStream(&aOutputStream)
       
    98 	{}
       
    99 
       
   100 void CImapSession::ConstructL()
       
   101 	{
       
   102 	__ASSERT_DEBUG(iInputStream != NULL, TImapServerPanic::ImapPanic(TImapServerPanic::ESessionNullInputStream));
       
   103 	__ASSERT_DEBUG(iOutputStream != NULL, TImapServerPanic::ImapPanic(TImapServerPanic::ESessionNullOutputStream));
       
   104 
       
   105 #ifdef __IMAP_LOGGING	
       
   106 	//Getting the server port number for creating the IMAP log file
       
   107 	TInt portNum = 143;
       
   108 	TBuf<10> fileName;
       
   109 	fileName.AppendFormat(KLogFileName, portNum);
       
   110 	__LOG_CREATE_STANDARD(fileName, iLogId);
       
   111 #endif //__IMAP_LOGGING	
       
   112 
       
   113 	iServerGreetingInfo = CImapServerGreetingInfo::NewL();
       
   114 	iCapabilityInfo = CImapCapabilityInfo::NewL();
       
   115 	iInputCache = CBufFlat::NewL(KInputCacheGranularity);
       
   116 
       
   117 	TCallBack callBack(CImapSession::AsyncCallBack, this);
       
   118 	iAsyncCallBack = new(ELeave)CAsyncCallBack(callBack, CActive::EPriorityStandard);
       
   119 	
       
   120 	iFlushCommandTimeout = CImapObservableTimer::NewL(*this);
       
   121 	
       
   122 	iInputStream->Bind(*this, iLogId);
       
   123 	iOutputStream->Bind(*this, iLogId);
       
   124 	}
       
   125 	
       
   126 CImapSession::~CImapSession()
       
   127 	{
       
   128 	Cancel();
       
   129 
       
   130 	// Close the streams if they are not already closed. Just closing the
       
   131 	// output stream will also close the input stream.
       
   132 	if (iOutputStream != NULL)
       
   133 		{
       
   134 		iOutputStream->Close();
       
   135 		}
       
   136 
       
   137 	delete iFlushCommandTimeout;
       
   138 	delete iAsyncCallBack;
       
   139 	
       
   140 	delete iCurrentCommand;
       
   141 	
       
   142 	delete iSelectedFolderInfo;
       
   143 	delete iCapabilityInfo;	
       
   144 	delete iServerGreetingInfo;
       
   145 	
       
   146 	delete iInputCache;
       
   147 
       
   148 	__LOG_CLOSE(iLogId);
       
   149 	}
       
   150 
       
   151 /**
       
   152 Returns the current server state.
       
   153 EServerStateNone indicates that the server greeting has not yet been received.
       
   154 CImapSession will panic if an attempt is made to call invoke an IMAP command when the IMAP server is 
       
   155 not in the correct state for the command.
       
   156 This method can be called to check the state before invoking such a command.
       
   157 @return The current server state.
       
   158 */
       
   159 EXPORT_C CImapSession::TImapServerState CImapSession::ServerState()
       
   160 	{
       
   161 	return iServerState;
       
   162 	}
       
   163 
       
   164 /**
       
   165 Returns inforamtion about the currently selected folder.
       
   166 If no folder is currently selected, then NULL will be returned.
       
   167 @return information about the currently selected folder or NULL if no folder is currently selected.
       
   168 */
       
   169 EXPORT_C CImapFolderInfo* CImapSession::SelectedFolderInfo()
       
   170 	{
       
   171 	return iSelectedFolderInfo;
       
   172 	}
       
   173 
       
   174 /** 
       
   175 Returns the server greeting information object.
       
   176 The data in the object will only be valid after a greeting has been received from the server.
       
   177 This must be requested using the ReadServerGreetingL() method immediately after connection has been made.
       
   178 @return The server greeting information object.
       
   179 */
       
   180 EXPORT_C const CImapServerGreetingInfo& CImapSession::ServerGreetingInfo()
       
   181 	{
       
   182 	return *iServerGreetingInfo;
       
   183 	}
       
   184 
       
   185 /** 
       
   186 Returns the server capability information object.
       
   187 The data in the object will only be valid after a capability response has been received from the server.
       
   188 This can be requested using the CapabilityL() method.
       
   189 @return The server capability information object.
       
   190 */
       
   191 EXPORT_C const CImapCapabilityInfo& CImapSession::CapabilityInfo()
       
   192 	{
       
   193 	return *iCapabilityInfo;
       
   194 	}
       
   195 
       
   196 /** 
       
   197 @return ETrue if IMAP IDLE mode is supported by the server.
       
   198 */
       
   199 EXPORT_C TBool CImapSession::ImapIdleSupported() const
       
   200 	{
       
   201 	return iCapabilityInfo->QueryFlag(CImapCapabilityInfo::EIdle);
       
   202 	}
       
   203 
       
   204 /** 
       
   205 Request to enter IMAP IDLE mode.
       
   206 This method will complete when confirmation of entering IDLE mode has been received 
       
   207 from the server, via the '+' continuation response.
       
   208 The server may send untagged status information BEFORE sending the continuation response.
       
   209 This will be recorded and can be accessed via SelectedFolderInfo().
       
   210 Upon completion of EnterIdleL(), 
       
   211 WaitForIdleEvent() should be called in order to wait for the next status information event, 
       
   212 or DoneIdle() should be called to stop receiving further status information.
       
   213 @param aStatus Signals the receipt of the continuation response.
       
   214 */
       
   215 EXPORT_C void CImapSession::EnterIdleL(TRequestStatus& aStatus)
       
   216 	{
       
   217 	__LOG_TEXT(iLogId, "CImapSession::EnterIdleL()");
       
   218 	__ASSERT_DEBUG(iServerState >= EServerStateAuthenticated, TImapServerPanic::ImapPanic(TImapServerPanic::EIdleWhenServerUnAuthenticated));
       
   219 	__ASSERT_DEBUG(iPendingOperation == EOpNone, TImapServerPanic::ImapPanic(TImapServerPanic::EIdleWhenInvalidOperationPending));
       
   220 	if (CompleteIfStreamsClosed(aStatus)) 
       
   221 		{
       
   222 		return;
       
   223 		}
       
   224 	
       
   225 	StartCommandL(aStatus, CImapIdle::NewL(iSelectedFolderInfo, iLogId));
       
   226 	
       
   227 	SetPendingOperation(EOpIdleEnter);
       
   228 	}
       
   229 	
       
   230 /**
       
   231 Request to be notified of an IMAP IDLE event.
       
   232 This method will complete when the next line of status information is received.
       
   233 The updated information can be accessed via SelectedFolderInfo().
       
   234 However, the information might not be complete as further lines of status information may 
       
   235 have been sent but not yet received.
       
   236 Upon completion of WaitForIdleEvent(), 
       
   237 WaitForIdleEvent() should be called again in order to receive the next event
       
   238 or DoneIdle() should be called to receive complete status information 
       
   239 and to stop receiving further information.
       
   240 This method will panic if the session is not currently in IDLE mode.
       
   241 Use EnterIdleL() to enter IDLE mode.
       
   242 @param aStatus Signals the receipt of a line of status information.
       
   243 */
       
   244 EXPORT_C void CImapSession::WaitForIdleEvent(TRequestStatus& aStatus)
       
   245 	{
       
   246 	__LOG_TEXT(iLogId, "CImapSession::WaitForIdleEvent()");
       
   247 	__ASSERT_DEBUG(iServerState >= EServerStateAuthenticated, TImapServerPanic::ImapPanic(TImapServerPanic::EIdleWaitWhenServerUnAuthenticated));
       
   248 	__ASSERT_DEBUG(iPendingOperation == EOpIdleEnter || iPendingOperation == EOpIdleWait, TImapServerPanic::ImapPanic(TImapServerPanic::EIdleWaitWhenOperationPendingNotIdle));
       
   249 	__ASSERT_DEBUG(iSessionState == ESessionNormal, TImapServerPanic::ImapPanic(TImapServerPanic::EIdleWaitWhenSessionNonNormal));
       
   250 	if (CompleteIfStreamsClosed(aStatus)) 
       
   251 		{
       
   252 		return;
       
   253 		}
       
   254 	
       
   255 	SetPendingOperation(EOpIdleWait);
       
   256 		
       
   257 	Queue(aStatus);
       
   258 	
       
   259 	// Restart the ProcessInputBufferL() loop asynchronously
       
   260 	ProcessInputBufferAsync();
       
   261 	}
       
   262 	
       
   263 /** 
       
   264 Request to exit IMAP IDLE mode.
       
   265 This will cause the session to send a DONE message to the server.
       
   266 The method will complete when a tagged response is received.
       
   267 Upon completion, up-to-date status information can be accessed via SelectedFolderInfo().
       
   268 This method will panic if the session is not currently in IDLE mode.
       
   269 Use EnterIdleL() to enter IDLE mode.
       
   270 @param aStatus Signals completion of the request.
       
   271 */
       
   272 EXPORT_C void CImapSession::DoneIdle(TRequestStatus& aStatus)
       
   273 	{
       
   274 	__LOG_TEXT(iLogId, "CImapSession::DoneIdle()");
       
   275 	__ASSERT_DEBUG(iServerState >= EServerStateAuthenticated, TImapServerPanic::ImapPanic(TImapServerPanic::EIdleDoneWhenServerUnAuthenticated));
       
   276 	__ASSERT_DEBUG(iPendingOperation == EOpIdleEnter || iPendingOperation == EOpIdleWait, TImapServerPanic::ImapPanic(TImapServerPanic::EIdleDoneWhenWhenInvalidOperationPending));
       
   277 	__ASSERT_DEBUG(iSessionState == ESessionNormal, TImapServerPanic::ImapPanic(TImapServerPanic::EIdleDoneWhenSessionNonNormal));
       
   278 	__ASSERT_DEBUG(iCurrentCommand != NULL, TImapServerPanic::ImapPanic(TImapServerPanic::ESessionNullCurrentCommand));
       
   279 	if (CompleteIfStreamsClosed(aStatus)) 
       
   280 		{
       
   281 		return;
       
   282 		}
       
   283 	
       
   284 	CImapIdle* idleCommand = static_cast<CImapIdle*>(iCurrentCommand);
       
   285 
       
   286 	SetPendingOperation(EOpIdleDone); // Treat as a normal command.
       
   287 	SetSessionState(ESessionNormal); // If called after cancel, then set the session back to normal state.
       
   288 	
       
   289 	// iOutputStream must be non-null because CompleteIfStreamsClosed() returned EFalse.
       
   290 	idleCommand->SendDone(*iOutputStream);
       
   291 	
       
   292 	Queue(aStatus);
       
   293 	
       
   294 	// Restart the ProcessInputBufferL() loop asynchronously
       
   295 	ProcessInputBufferAsync();
       
   296 	}
       
   297 
       
   298 /**
       
   299 This method does not send a command to the server, 
       
   300 but simply waits on the input stream for any unsolicited response message
       
   301 that the server might decide to send.  See section 5.3 of RFC3501.
       
   302 This method should be used in place of the IDLE methods when no command is
       
   303 being processed.
       
   304 To cancel this method, call Cancel() followed by FlushCancelledCommand() to 
       
   305 ensure that partial responses are not left on the input stream before 
       
   306 the issuing the next command
       
   307 @param aStatus Signals that an unsolicited response has been received.
       
   308 */
       
   309 EXPORT_C void CImapSession::WaitForServerEventL(TRequestStatus& aStatus)
       
   310 	{
       
   311 	__LOG_TEXT(iLogId, "CImapSession::WaitForServerEventL()");
       
   312 	__ASSERT_DEBUG(iServerState >= EServerStateAuthenticated, TImapServerPanic::ImapPanic(TImapServerPanic::EWaitForServerEventWhenServerUnAuthenticated));
       
   313 	__ASSERT_DEBUG(iPendingOperation == EOpNone, TImapServerPanic::ImapPanic(TImapServerPanic::EWaitForServerEventWhenInvalidOperationPending));
       
   314 	if (CompleteIfStreamsClosed(aStatus)) 
       
   315 		{
       
   316 		return;
       
   317 		}
       
   318 	
       
   319 	StartCommandL(aStatus, CImapServerEventWait::NewL(iSelectedFolderInfo, iLogId));
       
   320 	}
       
   321 
       
   322 /** 
       
   323 Reads and parses the server greeting from the input stream.
       
   324 This method must (and must only) be called immediately after making a connection to the server.
       
   325 Once this method has completed succesfully, the server greeting information will be accessible 
       
   326 from the ServerGreetingInfo() method of this object.
       
   327 @return The server greeting information object.
       
   328 */
       
   329 EXPORT_C void CImapSession::ReadServerGreetingL(TRequestStatus& aStatus)
       
   330 	{
       
   331 	__LOG_TEXT(iLogId, "CImapSession::ReadServerGreetingL()");
       
   332 	__ASSERT_DEBUG(iServerState == EServerStateNone, TImapServerPanic::ImapPanic(TImapServerPanic::EReadServerGreetingWhenServerUnAuthenticated));
       
   333 	__ASSERT_DEBUG(iPendingOperation == EOpNone, TImapServerPanic::ImapPanic(TImapServerPanic::EReadServerGreetingWhenInvalidOperationPending));
       
   334 	if (CompleteIfStreamsClosed(aStatus)) 
       
   335 		{
       
   336 		return;
       
   337 		}
       
   338 	
       
   339 	SetPendingOperation(EOpServerGreeting); // Next server state depends on ServerGreeting result: could be PreAuth
       
   340 	StartCommandL(aStatus, CImapServerGreeting::NewL(iSelectedFolderInfo, iLogId, *iServerGreetingInfo));
       
   341 	}
       
   342 
       
   343 /** 
       
   344 Issue the IMAP capability command to gather IMAP capability information from the remote server.
       
   345 Once this method has completed successfully, the capability information will be accessible 
       
   346 from the CapabilityInfo() method of this object.
       
   347 @param aStatus Signals completion of the request
       
   348 @see CapabilityInfo()
       
   349 */
       
   350 EXPORT_C void CImapSession::CapabilityL(TRequestStatus& aStatus)
       
   351 	{
       
   352 	__LOG_TEXT(iLogId, "CImapSession::CapabilityL()");
       
   353 	__ASSERT_DEBUG(iServerState != EServerStateNone, TImapServerPanic::ImapPanic(TImapServerPanic::ECapabilityWhenServerStateUnknown));
       
   354 	__ASSERT_DEBUG(iPendingOperation == EOpNone, TImapServerPanic::ImapPanic(TImapServerPanic::ECapabilityWhenInvalidOperationPending));
       
   355 	if (CompleteIfStreamsClosed(aStatus)) 
       
   356 		{
       
   357 		return;
       
   358 		}
       
   359 	
       
   360 	StartCommandL(aStatus, CImapCapability::NewL(iSelectedFolderInfo, iLogId, *iCapabilityInfo));
       
   361 	}
       
   362 /** 
       
   363 Issue the IMAP noop command.
       
   364 When in selected state, and upon completions, the caller should 
       
   365 check SelectedFolderInfo() for any updates.
       
   366 @param aStatus 		Signals completion of the request
       
   367 */
       
   368 EXPORT_C void CImapSession::NoopL(TRequestStatus& aStatus)
       
   369 	{
       
   370 	__LOG_TEXT(iLogId, "CImapSession::NoopL()");
       
   371 	__ASSERT_DEBUG(iServerState != EServerStateNone, TImapServerPanic::ImapPanic(TImapServerPanic::ENoopWhenServerStateUnknown));
       
   372 	__ASSERT_DEBUG(iPendingOperation == EOpNone, TImapServerPanic::ImapPanic(TImapServerPanic::ENoopWhenInvalidOperationPending));
       
   373 	if (CompleteIfStreamsClosed(aStatus)) 
       
   374 		{
       
   375 		return;
       
   376 		}
       
   377 	
       
   378 	StartCommandL(aStatus, CImapNoop::NewL(iSelectedFolderInfo, iLogId));
       
   379 	}
       
   380 
       
   381 /**
       
   382 Issue the IMAP logout command.
       
   383 @param aStatus Signals completion of the request
       
   384 */
       
   385 EXPORT_C void CImapSession::LogoutL(TRequestStatus& aStatus)
       
   386 	{
       
   387 	__LOG_TEXT(iLogId, "CImapSession::LogoutL()");
       
   388 	__ASSERT_DEBUG(iServerState != EServerStateNone, TImapServerPanic::ImapPanic(TImapServerPanic::ELogOutWhenNotSelected));
       
   389 	__ASSERT_DEBUG(iPendingOperation == EOpNone, TImapServerPanic::ImapPanic(TImapServerPanic::ELogOutWhenInvalidOperationPending));
       
   390 	if (CompleteIfStreamsClosed(aStatus)) 
       
   391 		{
       
   392 		return;
       
   393 		}
       
   394 	
       
   395 	SetPendingOperation(EOpLogout); // Server state becomes None (i.e. disconnected)
       
   396 	StartCommandL(aStatus, CImapLogout::NewL(iSelectedFolderInfo, iLogId));
       
   397 	}
       
   398 	
       
   399 /**
       
   400 Issue the IMAP login command.
       
   401 @param aStatus Signals completion of the request
       
   402 @param aUserName A user name supplied by the user
       
   403 @param aPassword A password supplied by the user
       
   404 */
       
   405 EXPORT_C void CImapSession::LoginL(TRequestStatus& aStatus, const TDesC8& aUserName, const TDesC8& aPassword)
       
   406 	{
       
   407 	__LOG_TEXT(iLogId, "CImapSession::LoginL()");
       
   408 	__ASSERT_DEBUG(iServerState == EServerStateNotAuthenticated, TImapServerPanic::ImapPanic(TImapServerPanic::ELoginWhenServerStateUnknown));
       
   409 	__ASSERT_DEBUG(iPendingOperation == EOpNone, TImapServerPanic::ImapPanic(TImapServerPanic::ELoginWhenInvalidOperationPending));
       
   410 	if (CompleteIfStreamsClosed(aStatus)) 
       
   411 		{
       
   412 		return;
       
   413 		}
       
   414 	
       
   415 	SetPendingOperation(EOpLogin); // << Server state becomes Authenticated
       
   416 	StartCommandL(aStatus, CImapLogin::NewL(iSelectedFolderInfo, iLogId, aUserName, aPassword, *iCapabilityInfo));
       
   417 	}
       
   418 	
       
   419 /** 
       
   420 Issue the IMAP StartTLS command
       
   421 @param aStatus Signals completion of the request
       
   422 */
       
   423 EXPORT_C void CImapSession::StartTlsL(TRequestStatus& aStatus)
       
   424 	{
       
   425 	__LOG_TEXT(iLogId, "CImapSession::StartTlsL()");
       
   426 	__ASSERT_DEBUG(iServerState == EServerStateNotAuthenticated, TImapServerPanic::ImapPanic(TImapServerPanic::EStartTLSWhenServerUnAuthenticated));
       
   427 	__ASSERT_DEBUG(iPendingOperation == EOpNone, TImapServerPanic::ImapPanic(TImapServerPanic::EStartTLSWhenInvalidOperationPending));
       
   428 	if (CompleteIfStreamsClosed(aStatus)) 
       
   429 		{
       
   430 		return;
       
   431 		}
       
   432 	
       
   433 	StartCommandL(aStatus, CImapStartTls::NewL(iSelectedFolderInfo, iLogId));
       
   434 	}
       
   435 
       
   436 /**
       
   437 Issue the IMAP select command.
       
   438 Opens the folder identified by aFolderInfo.Name() for read-write operations.
       
   439 @param aStatus Signals completion of the request
       
   440 @param aFolderInfo The folder object that represents the mailbox.  CImapSession takes ownership of this object.
       
   441 The folder object initially contains the name of the folder to select.
       
   442 The folder object will be updated upon successful completion of the command.
       
   443 The folder object will be updated when any subsequent command receives folder information from the server.
       
   444 */
       
   445 EXPORT_C void CImapSession::SelectL(TRequestStatus& aStatus, CImapFolderInfo* aFolderInfo, TBool aSelectBox)
       
   446 	{
       
   447 	__LOG_TEXT(iLogId, "CImapSession::SelectL()");
       
   448 	__ASSERT_DEBUG(iServerState >= EServerStateAuthenticated, TImapServerPanic::ImapPanic(TImapServerPanic::ESelectWhenServerUnAuthenticated));
       
   449 	__ASSERT_DEBUG(iPendingOperation == EOpNone, TImapServerPanic::ImapPanic(TImapServerPanic::ESelectWhenInvalidOperationPending));
       
   450 	__ASSERT_DEBUG(aFolderInfo != NULL, TImapServerPanic::ImapPanic(TImapServerPanic::ESessionImapFolderInfoIsNull));
       
   451 	
       
   452 	if (CompleteIfStreamsClosed(aStatus)) 
       
   453 		{
       
   454 		// Attempt to select while the stream is closed.
       
   455 		// This failed select effectively puts us into the authenticated server state, 
       
   456 		// where iSelectedFolderInfo should be NULL.
       
   457 		delete iSelectedFolderInfo;
       
   458 		iSelectedFolderInfo = NULL;		
       
   459 
       
   460 		delete aFolderInfo; // No need to set to NULL as we're returning.
       
   461 		return;
       
   462 		}
       
   463 			// Folder is already SELECTed so dont select again.. Hope this saves users bandwidth 
       
   464 	if(aSelectBox)		
       
   465 	{
       
   466 		if(iSelectedFolderInfo && iSelectedFolderInfo->MsvId() == aFolderInfo->MsvId())
       
   467 			{
       
   468 			Queue(aStatus);
       
   469 			Complete(KErrNone);
       
   470 			delete aFolderInfo;
       
   471 			return;
       
   472 			}	
       
   473 	}
       
   474 	CleanupStack::PushL(aFolderInfo); // Take ownership but don't assign as a data member yet
       
   475 	
       
   476 	SetPendingOperation(EOpSelect); // Server state becomes Selected if successful, otherwise becomes Authenticated - and selected folder info becomes NULL
       
   477 	StartCommandL(aStatus, CImapSelect::NewL(aFolderInfo, iLogId));
       
   478 	
       
   479 	// Overwrite any existing folder info, prior to performing the select
       
   480 	// If select succeeds, iSelectedFolderInfo will be correct.
       
   481 	// If select fails then iSelectedFolderInfo will be deleted and set to NULL later, as the state will 
       
   482 	//   revert from Selected to Authenticated.
       
   483 	
       
   484 	CleanupStack::Pop(aFolderInfo); // Now we can assign aFolderInfo as a data member
       
   485 	
       
   486 	delete iSelectedFolderInfo;
       
   487 	iSelectedFolderInfo = aFolderInfo;
       
   488 	}
       
   489 
       
   490 /**
       
   491 Issue the IMAP examine command.
       
   492 Opens the folder identified by aFolderInfo.Name() for read-only operations.
       
   493 @param aStatus Signals completion of the request
       
   494 @param aFolderInfo The folder object that represents the mailbox.  CImapSession takes ownership of this object.
       
   495 The folder object initially contains the name of the folder to examine.
       
   496 The folder object will be updated upon successful completion of the command.
       
   497 The folder object will be updated when any subsequent command receives folder information from the server.
       
   498 */
       
   499 EXPORT_C void CImapSession::ExamineL(TRequestStatus& aStatus, CImapFolderInfo* aFolderInfo)
       
   500 	{
       
   501 	__LOG_TEXT(iLogId, "CImapSession::ExamineL()");
       
   502 	__ASSERT_DEBUG(iServerState >= EServerStateAuthenticated, TImapServerPanic::ImapPanic(TImapServerPanic::EExamineWhenServerUnAuthenticated));
       
   503 	__ASSERT_DEBUG(iPendingOperation == EOpNone, TImapServerPanic::ImapPanic(TImapServerPanic::EExamineWhenInvalidOperationPending));
       
   504 	__ASSERT_DEBUG(aFolderInfo != NULL, TImapServerPanic::ImapPanic(TImapServerPanic::ESessionImapFolderInfoIsNull));
       
   505 
       
   506 	if (CompleteIfStreamsClosed(aStatus)) 
       
   507 		{
       
   508 		// Attempt to select while the stream is closed.
       
   509 		// This failed select effectively puts us into the authenticated server state, 
       
   510 		// where iSelectedFolderInfo should be NULL.
       
   511 		delete iSelectedFolderInfo;
       
   512 		iSelectedFolderInfo = NULL;		
       
   513 		
       
   514 		delete aFolderInfo; // No need to set to NULL as we're returning.		
       
   515 		return;
       
   516 		}
       
   517 	
       
   518 	CleanupStack::PushL(aFolderInfo); // Take ownership but don't assign as a data member yet
       
   519 	
       
   520 	SetPendingOperation(EOpSelect); // Server state becomes Selected if successful, otherwise becomes Authenticated - and selected folder info becomes NULL
       
   521 	StartCommandL(aStatus, CImapExamine::NewL(aFolderInfo, iLogId));
       
   522 	
       
   523 	// Overwrite any existing folder info, prior to performing the select
       
   524 	// If select succeeds, iSelectedFolderInfo will be correct.
       
   525 	// If select fails then iSelectedFolderInfo will be deleted and set to NULL later, as the state will 
       
   526 	//   revert from Selected to Authenticated.
       
   527 	
       
   528 	CleanupStack::Pop(aFolderInfo); // Now we can assign aFolderInfo as a data member
       
   529 	
       
   530 	delete iSelectedFolderInfo;
       
   531 	iSelectedFolderInfo = aFolderInfo;
       
   532 	}
       
   533 
       
   534 /**
       
   535 Issue the IMAP create command
       
   536 Creates a remote mailbox with the name given by aMailboxName
       
   537 @param aStatus Signals completion of the request
       
   538 @param aMailboxName The name to be given to the new mailbox.
       
   539 					This is the FULL PATH to the mailbox, as understood by the remote server.
       
   540 */
       
   541 EXPORT_C void CImapSession::CreateL(TRequestStatus& aStatus, const TDesC& aMailboxName)
       
   542 	{
       
   543 	__LOG_TEXT(iLogId, "CImapSession::CreateL()");
       
   544 	__ASSERT_DEBUG(iServerState >= EServerStateAuthenticated, TImapServerPanic::ImapPanic(TImapServerPanic::ECreateWhenServerUnAuthenticated));
       
   545 	__ASSERT_DEBUG(iPendingOperation == EOpNone, TImapServerPanic::ImapPanic(TImapServerPanic::ECreateWhenInvalidOperationPending));
       
   546 	if (CompleteIfStreamsClosed(aStatus)) 
       
   547 		{
       
   548 		return;
       
   549 		}
       
   550 	
       
   551 	StartCommandL(aStatus, CImapCreate::NewL(iSelectedFolderInfo, iLogId, aMailboxName));
       
   552 	}
       
   553 
       
   554 /** 
       
   555 Issue the IMAP delete command
       
   556 Deletes the folder identified by aMailboxName.
       
   557 @param aStatus Signals completion of the request.
       
   558 @param aMailboxName The name of the mailbox that is to be selected.
       
   559 					This is the FULL PATH to the mailbox, as understood by the remote server.
       
   560 */
       
   561 EXPORT_C void CImapSession::DeleteL(TRequestStatus& aStatus, const TDesC& aMailboxName)
       
   562 	{
       
   563 	__LOG_TEXT(iLogId, "CImapSession::DeleteL()");
       
   564 	__ASSERT_DEBUG(iServerState >= EServerStateAuthenticated, TImapServerPanic::ImapPanic(TImapServerPanic::EDeleteWhenServerUnAuthenticated));
       
   565 	__ASSERT_DEBUG(iPendingOperation == EOpNone, TImapServerPanic::ImapPanic(TImapServerPanic::EDeleteWhenInvalidOperationPending));
       
   566 	if (CompleteIfStreamsClosed(aStatus)) 
       
   567 		{
       
   568 		return;
       
   569 		}
       
   570 		
       
   571 	StartCommandL(aStatus, CImapDelete::NewL(iSelectedFolderInfo, iLogId, aMailboxName));
       
   572 	}
       
   573 
       
   574 /**
       
   575 Issue the IMAP rename command.
       
   576 Renames the folder identified by aExistingMailboxName to aNewMailboxName.
       
   577 @param aStatus Signals completion of the request.
       
   578 @param aExistingMailboxName The current name of the mailbox that is to be renamed
       
   579 @param aNewMailboxName The new name to be given to the mailbox
       
   580 */
       
   581 EXPORT_C void CImapSession::RenameL(TRequestStatus& aStatus, const TDesC& aExistingMailboxName, const TDesC& aNewMailboxName)
       
   582 	{
       
   583 	__LOG_TEXT(iLogId, "CImapSession::RenameL()");
       
   584 	__ASSERT_DEBUG(iServerState >= EServerStateAuthenticated, TImapServerPanic::ImapPanic(TImapServerPanic::ERenameWhenServerUnAuthenticated));
       
   585 	__ASSERT_DEBUG(iPendingOperation == EOpNone, TImapServerPanic::ImapPanic(TImapServerPanic::ERenameWhenInvalidOperationPending));
       
   586 	if (CompleteIfStreamsClosed(aStatus)) 
       
   587 		{
       
   588 		return;
       
   589 		}
       
   590 		
       
   591 	StartCommandL(aStatus, CImapRename::NewL(iSelectedFolderInfo, iLogId, aExistingMailboxName, aNewMailboxName));
       
   592 	}
       
   593 
       
   594 /** 
       
   595 Issue the IMAP subscribe command.
       
   596 Subscribes to the folder identified by aMailboxName.
       
   597 @param aStatus Signals completion of the request.
       
   598 @param aMailboxName The name of the mailbox that is to be subscribed to.
       
   599 					This is the FULL PATH to the mailbox, as understood by the remote server.
       
   600 */
       
   601 EXPORT_C void CImapSession::SubscribeL(TRequestStatus& aStatus, const TDesC& aMailboxName)
       
   602 	{
       
   603 	__LOG_TEXT(iLogId, "CImapSession::SubscribeL()");
       
   604 	__ASSERT_DEBUG(iServerState >= EServerStateAuthenticated, TImapServerPanic::ImapPanic(TImapServerPanic::ESubscribeWhenServerUnAuthenticated));
       
   605 	__ASSERT_DEBUG(iPendingOperation == EOpNone, TImapServerPanic::ImapPanic(TImapServerPanic::ESubscribeWhenInvalidOperationPending));
       
   606 	if (CompleteIfStreamsClosed(aStatus)) 
       
   607 		{
       
   608 		return;
       
   609 		}
       
   610 		
       
   611 	StartCommandL(aStatus, CImapSubscribe::NewL(iSelectedFolderInfo, iLogId, aMailboxName));
       
   612 	}
       
   613 
       
   614 /**
       
   615 Issue the IMAP unsubscribe command
       
   616 Unsubscribes from the folder identified by aMailboxName.
       
   617 @param aStatus Signals completion of the request.
       
   618 @param aMailboxName The name of the mailbox that is to be unsubscribed from.
       
   619 					This is the FULL PATH to the mailbox, as understood by the remote server.
       
   620 */
       
   621 EXPORT_C void CImapSession::UnsubscribeL(TRequestStatus& aStatus, const TDesC& aMailboxName)
       
   622 	{
       
   623 	__LOG_TEXT(iLogId, "CImapSession::UnsubscribeL()");
       
   624 	__ASSERT_DEBUG(iServerState >= EServerStateAuthenticated, TImapServerPanic::ImapPanic(TImapServerPanic::EUnSubscribeWhenServerUnAuthenticated));
       
   625 	__ASSERT_DEBUG(iPendingOperation == EOpNone, TImapServerPanic::ImapPanic(TImapServerPanic::EUnSubscribeWhenInvalidOperationPending));
       
   626 	if (CompleteIfStreamsClosed(aStatus)) 
       
   627 		{
       
   628 		return;
       
   629 		}
       
   630 		
       
   631 	StartCommandL(aStatus, CImapUnsubscribe::NewL(iSelectedFolderInfo, iLogId, aMailboxName));
       
   632 	}
       
   633 
       
   634 /**
       
   635 Issue the IMAP list command
       
   636 Populates aFolderList with information about the requested mailbox.
       
   637 @param aStatus Signals completion of the request.
       
   638 @param aReferenceName	The reference name can be used to qualify the path of the mailbox.  See section 6.3.8 of RFC 3501
       
   639 @param aMailboxName		Specifies which mailbox to list.  Only subfolders of the specified mailbox will be listed.
       
   640 						This is the FULL PATH to the mailbox, as understood by the remote server.
       
   641 @param aFolderList An array which will be populated with the list of folders upon successful completion of the command.
       
   642 */
       
   643 EXPORT_C void CImapSession::ListL(TRequestStatus& aStatus, const TDesC& aReferenceName, const TDesC& aMailboxName, RArrayImapListFolderInfo& aFolderList)
       
   644 	{
       
   645 	__LOG_TEXT(iLogId, "CImapSession::ListL()");
       
   646 	__ASSERT_DEBUG(iServerState >= EServerStateAuthenticated, TImapServerPanic::ImapPanic(TImapServerPanic::EListWhenServerUnAuthenticated));
       
   647 	__ASSERT_DEBUG(iPendingOperation == EOpNone, TImapServerPanic::ImapPanic(TImapServerPanic::EListWhenInvalidOperationPending));
       
   648 	if (CompleteIfStreamsClosed(aStatus)) 
       
   649 		{
       
   650 		return;
       
   651 		}
       
   652 		
       
   653 	StartCommandL(aStatus, CImapList::NewL(iSelectedFolderInfo, iLogId, aReferenceName, aMailboxName, aFolderList, iImapSettings));
       
   654 	}
       
   655 
       
   656 /**
       
   657 Issue the IMAP lsub command
       
   658 Populates aFolderList with information about the requested remotely subscribed mailbox.
       
   659 @param aStatus Signals completion of the request.
       
   660 @param aReferenceName	The reference name can be used to qualify the path of the mailbox.  See section 6.3.9 of RFC 3501
       
   661 @param aMailboxName		Specifies which mailbox to list.  Only subscribed subfolders of the specified mailbox will be listed.
       
   662 						This is the FULL PATH to the mailbox, as understood by the remote server.
       
   663 @param aFolderList		An array which will be populated with the list of folders upon successful completion of the command.
       
   664 */
       
   665 EXPORT_C void CImapSession::LsubL(TRequestStatus& aStatus, const TDesC& aReferenceName, const TDesC& aMailboxName, RArrayImapListFolderInfo& aFolderList)
       
   666 	{
       
   667 	__LOG_TEXT(iLogId, "CImapSession::LsubL()");
       
   668 	__ASSERT_DEBUG(iServerState >= EServerStateAuthenticated, TImapServerPanic::ImapPanic(TImapServerPanic::ELsubWhenServerUnAuthenticated));
       
   669 	__ASSERT_DEBUG(iPendingOperation == EOpNone, TImapServerPanic::ImapPanic(TImapServerPanic::ELsubWhenInvalidOperationPending));
       
   670 	if (CompleteIfStreamsClosed(aStatus)) 
       
   671 		{
       
   672 		return;
       
   673 		}
       
   674 		
       
   675 	StartCommandL(aStatus, CImapLsub::NewL(iSelectedFolderInfo, iLogId, aReferenceName, aMailboxName, aFolderList, iImapSettings));
       
   676 	}
       
   677 
       
   678 /**
       
   679 Issue the IMAP status command
       
   680 Populates aFolderInfo with information about the folder identified by aMailboxName
       
   681 This method SHOULD NOT be used to access information on this session's currently selected mailbox.
       
   682 @param aStatus Signals completion of the request.
       
   683 @param aMailboxName The name of the mailbox whose status information is to be fetched.
       
   684 					This is the FULL PATH to the mailbox, as understood by the remote server.
       
   685 @param aDataItemNames Specifies what information about the folder to request.
       
   686 @param aFolderInfo The folder object that represents the mailbox that whose status information is to be fetched.
       
   687 The folder object will be updated upon successful completion of the command.
       
   688 Ownership of aFolderInfo will NOT be taken by CImapSession.
       
   689 */
       
   690 EXPORT_C void CImapSession::StatusL(TRequestStatus& aStatus, const TDesC& aMailboxName, const TDesC8& aDataItemNames, CImapFolderInfo& aFolderInfo)
       
   691 	{
       
   692 	__LOG_TEXT(iLogId, "CImapSession::StatusL()");
       
   693 	__ASSERT_DEBUG(iServerState >= EServerStateAuthenticated, TImapServerPanic::ImapPanic(TImapServerPanic::EStatusWhenServerUnAuthenticated));
       
   694 	__ASSERT_DEBUG(iPendingOperation == EOpNone, TImapServerPanic::ImapPanic(TImapServerPanic::EStatusWhenInvalidOperationPending));
       
   695 	if (CompleteIfStreamsClosed(aStatus)) 
       
   696 		{
       
   697 		return;
       
   698 		}
       
   699 		
       
   700 	StartCommandL(aStatus, CImapStatus::NewL(iSelectedFolderInfo, iLogId, aMailboxName, aDataItemNames, aFolderInfo));
       
   701 	}
       
   702 
       
   703 /**
       
   704 Issue the IMAP append command
       
   705 @param aStatus Signals completion of the request.
       
   706 @param aSource An object from which the message source can be obtained
       
   707 @param aDestinationMailboxName The name of the mailbox to which the message is to be appended
       
   708 */
       
   709 EXPORT_C void CImapSession::AppendL(TRequestStatus& aStatus, CImSendMessage& aSource, const TDesC& aDestinationMailboxName)
       
   710 	{
       
   711 	__LOG_TEXT(iLogId, "CImapSession::AppendL()");
       
   712 	__ASSERT_DEBUG(iServerState >= EServerStateAuthenticated, TImapServerPanic::ImapPanic(TImapServerPanic::EAppendWhenServerUnAuthenticated));
       
   713 	__ASSERT_DEBUG(iPendingOperation == EOpNone, TImapServerPanic::ImapPanic(TImapServerPanic::EAppendWhenInvalidOperationPending));
       
   714 	if (CompleteIfStreamsClosed(aStatus)) 
       
   715 		{
       
   716 		return;
       
   717 		}
       
   718 
       
   719 	StartCommandL(aStatus, CImapAppend::NewL(iSelectedFolderInfo, iLogId, aSource, aDestinationMailboxName, *this));
       
   720 	}
       
   721 
       
   722 /**
       
   723 Issue the IMAP close command
       
   724 @param aStatus Signals completion of the request.
       
   725 */
       
   726 EXPORT_C void CImapSession::CloseL(TRequestStatus& aStatus)
       
   727 	{
       
   728 	__LOG_TEXT(iLogId, "CImapSession::CloseL()");
       
   729 	__ASSERT_DEBUG(iServerState == EServerStateSelected, TImapServerPanic::ImapPanic(TImapServerPanic::ECloseWhenNotSelected));
       
   730 	__ASSERT_DEBUG(iPendingOperation == EOpNone, TImapServerPanic::ImapPanic(TImapServerPanic::ECloseWhenInvalidOperationPending));
       
   731 	if (CompleteIfStreamsClosed(aStatus)) 
       
   732 		{
       
   733 		return;
       
   734 		}
       
   735 		
       
   736 	SetPendingOperation(EOpClose); // Server state becomes Authenticated, iSelectedFolderInfo becomes NULL
       
   737 	StartCommandL(aStatus, CImapClose::NewL(iSelectedFolderInfo, iLogId));
       
   738 	}
       
   739 
       
   740 /**
       
   741 Issue the IMAP search command
       
   742 This returns a list of id's of messages that match the specified search critera.
       
   743 @param aStatus Signals completion of the request.
       
   744 @param aSearchCriteria Specifies the set of message id's to return.
       
   745 @param aMatchingMessageIds An array of message id's that will receive the result of the search.
       
   746 The array will be populated upon successful completion of the command.
       
   747 */
       
   748 EXPORT_C void CImapSession::SearchL(TRequestStatus& aStatus, const TDesC8& aSearchCriteria, RArray<TUint>& aMatchingMessageIds)
       
   749 	{
       
   750 	__LOG_TEXT(iLogId, "CImapSession::SearchL()");
       
   751 	__ASSERT_DEBUG(iServerState == EServerStateSelected, TImapServerPanic::ImapPanic(TImapServerPanic::ESearchWhenNotSelected));
       
   752 	__ASSERT_DEBUG(iPendingOperation == EOpNone, TImapServerPanic::ImapPanic(TImapServerPanic::ESearchInvalidOperationPending));
       
   753 	if (CompleteIfStreamsClosed(aStatus)) 
       
   754 		{
       
   755 		return;
       
   756 		}
       
   757 		
       
   758 	StartCommandL(aStatus, CImapSearch::NewL(iSelectedFolderInfo, iLogId, aSearchCriteria, aMatchingMessageIds));
       
   759 	}
       
   760 
       
   761 /**
       
   762 Issues the IMAP fetch command with FLAGS as the only message data item.
       
   763 The flags for a range of messages may be asked for in a single request.
       
   764 @param aStatus Signals completion of the request.
       
   765 @param aSequenceSet Specifies the messages to fetch
       
   766 @param aOutFlagInfo An array which will be populated with the list of messages and their flags upon successful completion of the command.
       
   767 */
       
   768 EXPORT_C void CImapSession::FetchFlagsL(TRequestStatus& aStatus, const TDesC8& aSequenceSet, RArrayMessageFlagInfo& aOutFlagInfo)
       
   769 	{
       
   770 	__LOG_TEXT(iLogId, "CImapSession::FetchFlagsL()");
       
   771 	__ASSERT_DEBUG(iServerState == EServerStateSelected, TImapServerPanic::ImapPanic(TImapServerPanic::EFetchFlagsWhenNotSelected));
       
   772 	__ASSERT_DEBUG(iPendingOperation == EOpNone, TImapServerPanic::ImapPanic(TImapServerPanic::EFetchFlagsInvalidOperationPending));
       
   773 	if (CompleteIfStreamsClosed(aStatus)) 
       
   774 		{
       
   775 		return;
       
   776 		}
       
   777 		
       
   778 	StartCommandL(aStatus, CImapFetchFlags::NewL(iSelectedFolderInfo, iLogId, aSequenceSet, aOutFlagInfo));
       
   779 	}
       
   780 	
       
   781 /**
       
   782 Issues the IMAP fetch command with a BODY (or BODY.PEEK) as the only message data item.
       
   783 Only one message body may be fetched at a time, although the implementaton may transparently pipeline the fetch.
       
   784 The caller only provides the <section> information for the BODY.  The rest of the request is built up by the method.
       
   785 The BODY response data will be stored in the mailstore by the session.
       
   786 The sessison will use the supplied TMsvId to instruct the mailstore which entry to populate.
       
   787 @param aStatus Signals completion of the request.
       
   788 @param aMessageUid Specifies the message to fetch.  This is the IMAP message UID.
       
   789 @param aPeek Whether the \\Seen flag of the message should be updated by the IMAP server.
       
   790 @param aFetchBodyInfo container class with extra information about the part being fetched. 
       
   791 */	
       
   792 EXPORT_C void CImapSession::FetchBodyL(TRequestStatus& aStatus, TUint aMessageUid, TBool aPeek, CFetchBodyInfo& aFetchBodyInfo, CImapFetchBodyResponse& aFetchBodyResponse)
       
   793 	{
       
   794 	__LOG_TEXT(iLogId, "CImapSession::FetchBodyL()");
       
   795 	__ASSERT_DEBUG(iServerState == EServerStateSelected, TImapServerPanic::ImapPanic(TImapServerPanic::EFetchBodyWhenNotSelected));
       
   796 	__ASSERT_DEBUG(iPendingOperation == EOpNone, TImapServerPanic::ImapPanic(TImapServerPanic::EFetchBodyWhenInvalidOperationPending));
       
   797 	if (CompleteIfStreamsClosed(aStatus)) 
       
   798 		{
       
   799 		return;
       
   800 		}
       
   801 	
       
   802 	SetPendingOperation(EOpWaitForBodyOperationComplete);
       
   803 	StartCommandL(aStatus, CImapFetchBody::NewL(iSelectedFolderInfo, iLogId, aMessageUid, aPeek, aFetchBodyInfo, aFetchBodyResponse, iImapSettings, iImapMailStore, *this));
       
   804 	}
       
   805 	
       
   806 /**
       
   807 Issues the IMAP fetch command with the FLAGS, BODYSTRUCTURE and BODY.PEEK[HEADER.FIELDS(<fields>)] data items set.
       
   808 Only one message may be fetched with this method.  An override exists for a range of messages.
       
   809 @param aStatus Signals completion of the request.
       
   810 @param aMessageUid Specifies the message to fetch.  This is the IMAP message UID.
       
   811 @param aFieldNames A space separated list of header fields that are to be fetched by this method.
       
   812 @param aOutFetchResponse An object that will be populated with all requested structural information upon successful completion of the command.
       
   813 */	
       
   814 EXPORT_C void CImapSession::FetchBodyStructureAndHeadersL(TRequestStatus& aStatus, TUint aMessageUid, const TDesC8& aFieldNames, CImapFetchResponse& aOutFetchResponse)
       
   815 	{
       
   816 	__LOG_TEXT(iLogId, "CImapSession::FetchBodyStructureAndHeadersL()-single");
       
   817 	__ASSERT_DEBUG(iServerState == EServerStateSelected, TImapServerPanic::ImapPanic(TImapServerPanic::FetchBodyStructureSingleWhenNotSelected));
       
   818 	__ASSERT_DEBUG(iPendingOperation == EOpNone, TImapServerPanic::ImapPanic(TImapServerPanic::FetchBodyStructureSingleWhenInvalidOperationPending));
       
   819 	if (CompleteIfStreamsClosed(aStatus)) 
       
   820 		{
       
   821 		return;
       
   822 		}
       
   823 	
       
   824 	StartCommandL(aStatus, CImapFetchSingleBodyStructure::NewL(iSelectedFolderInfo, iLogId, aMessageUid, aFieldNames, aOutFetchResponse));
       
   825 	}
       
   826 
       
   827 /**
       
   828 Issues the IMAP fetch command with the FLAGS, BODYSTRUCTURE and BODY.PEEK[HEADER.FIELDS(<fields>)] data items set.
       
   829 A range of messages can be fetched with this method.  An override exists for single message fetches.
       
   830 @param aStatus Signals completion of the request.
       
   831 @param aMessageUid Specifies the message to fetch.  This is the IMAP message UID.
       
   832 @param aFieldNames A space separated list of header fields that are to be fetched by this method.
       
   833 @param aObserver The implementor of this interface will be called each time a fetch response has been received and parsed.
       
   834 */	
       
   835 EXPORT_C void CImapSession::FetchBodyStructureAndHeadersL(TRequestStatus& aStatus, const TDesC8& aSequenceSet, const TDesC8& aFieldNames, MImapFetchStructureObserver& aObserver)
       
   836 	{
       
   837 	__LOG_TEXT(iLogId, "CImapSession::FetchBodyStructureAndHeadersL()-multi");
       
   838 	__ASSERT_DEBUG(iServerState == EServerStateSelected, TImapServerPanic::ImapPanic(TImapServerPanic::FetchBodyStructureMultiWhenNotSelected));
       
   839 	__ASSERT_DEBUG(iPendingOperation == EOpNone, TImapServerPanic::ImapPanic(TImapServerPanic::FetchBodyStructureMultiWhenInvalidOperationPending));
       
   840 	if (CompleteIfStreamsClosed(aStatus)) 
       
   841 		{
       
   842 		return;
       
   843 		}
       
   844 	
       
   845 	StartCommandL(aStatus, CImapFetchMultiBodyStructures::NewL(iSelectedFolderInfo, iLogId, aSequenceSet, aFieldNames, aObserver));
       
   846 	}
       
   847 
       
   848 /**
       
   849 Issues the IMAP store command
       
   850 aSequenceSet, aMessageDataItem and aValue are the STORE parameters defined in RFC3501 - see section 6.4.6
       
   851 If aUseSilent is true, then the .SILENT is appended to end of the aMessageDataItem specifier.
       
   852 @param aStatus Signals completion of the request.
       
   853 @param aSequenceSet Specifies the range of messages to modify.
       
   854 @param aMessageDataItem Specifies the name of the message data item to be stored.
       
   855 @param aValue Provides the new value of the message item.
       
   856 @param aUseSilent Whether the server should return the updated data value.  
       
   857 If ETrue, then .SILENT is appended to end of the aMessageDataItem specifier.
       
   858 */
       
   859 EXPORT_C void CImapSession::StoreL(TRequestStatus& aStatus, const TDesC8& aSequenceSet, const TDesC8& aMessageDataItem, const TDesC8& aValue, TBool aUseSilent, RArrayMessageFlagInfo& aOutMessageFlagInfo)
       
   860 	{
       
   861 	__LOG_TEXT(iLogId, "CImapSession::StoreL()");
       
   862 	__ASSERT_DEBUG(iServerState == EServerStateSelected, TImapServerPanic::ImapPanic(TImapServerPanic::EStoreWhenNotSelected));
       
   863 	__ASSERT_DEBUG(iPendingOperation == EOpNone, TImapServerPanic::ImapPanic(TImapServerPanic::EStoreWhenInvalidOperationPending));
       
   864 	if (CompleteIfStreamsClosed(aStatus)) 
       
   865 		{
       
   866 		return;
       
   867 		}
       
   868 	
       
   869 	StartCommandL(aStatus, CImapStore::NewL(iSelectedFolderInfo, iLogId, aSequenceSet, aMessageDataItem, aValue, aUseSilent, aOutMessageFlagInfo));
       
   870 	}
       
   871 
       
   872 /**
       
   873 Issue the IMAP copy command
       
   874 This instructs the server to copy the messages identified by aSequence from the currently 
       
   875 selected folder to the folder identified by aDestinationMailbox.
       
   876 @param aStatus Signals completion of the request.
       
   877 @param aSequenceSet Specifies the range of messages to copy.
       
   878 @param aDestinationMailboxName The name of the mailbox to which the message(s) is(are) to be copied.
       
   879 */
       
   880 EXPORT_C void CImapSession::CopyL(TRequestStatus& aStatus, const TDesC8& aSequenceSet, const TDesC& aDestinationMailboxName)
       
   881 	{
       
   882 	__LOG_TEXT(iLogId, "CImapSession::CopyL()");
       
   883 	__ASSERT_DEBUG(iServerState == EServerStateSelected, TImapServerPanic::ImapPanic(TImapServerPanic::ECopyWhenNotSelected));
       
   884 	__ASSERT_DEBUG(iPendingOperation == EOpNone, TImapServerPanic::ImapPanic(TImapServerPanic::ECopyWhenInvalidOperationPending));
       
   885 	if (CompleteIfStreamsClosed(aStatus)) 
       
   886 		{
       
   887 		return;
       
   888 		}
       
   889 	
       
   890 	StartCommandL(aStatus, CImapCopy::NewL(iSelectedFolderInfo, iLogId, aSequenceSet, aDestinationMailboxName));
       
   891 	}
       
   892 
       
   893 /**
       
   894 Issues the IMAP expunge command.
       
   895 @param aStatus Signals completion of the request.
       
   896 */
       
   897 EXPORT_C void CImapSession::ExpungeL(TRequestStatus& aStatus)
       
   898 	{
       
   899 	__LOG_TEXT(iLogId, "CImapSession::ExpungeL()");
       
   900 	__ASSERT_DEBUG(iServerState == EServerStateSelected, TImapServerPanic::ImapPanic(TImapServerPanic::EExpungeWhenNotSelected));
       
   901 	__ASSERT_DEBUG(iPendingOperation == EOpNone, TImapServerPanic::ImapPanic(TImapServerPanic::EExpungeWhenInvalidOperationPending));
       
   902 	if (CompleteIfStreamsClosed(aStatus)) 
       
   903 		{
       
   904 		return;
       
   905 		}
       
   906 	
       
   907 	StartCommandL(aStatus, CImapExpunge::NewL(iSelectedFolderInfo, iLogId));
       
   908 	}
       
   909 
       
   910 /**
       
   911 Produces an efficient sequence-set string for the given set of message uids.
       
   912 For instance, the set (3 4 5 6 21) would produce the string 3:6,21
       
   913 Methods that take the aSequenceSet parameter can also accept wildcard sequence sets such as "24:*"
       
   914 which cannot be produced by this method (it would make no sense from finite set of uids).
       
   915 @param aMessageUids the set of messages to include in the sequence set
       
   916 @return the sequence set that represents the message uids.  The caller takes ownership of the returned object.
       
   917 */
       
   918 EXPORT_C HBufC8* CImapSession::CreateSequenceSetLC(RArray<TUint>& aMessageUids)
       
   919 // static method
       
   920 	{
       
   921 	_LIT8(KFormatFirstUid, "%d");
       
   922 	_LIT8(KFormatEndRangeAndNextUid, ":%d,%d");
       
   923 	_LIT8(KFormatNextUid, ",%d");
       
   924 	_LIT8(KFormatFinalEndRangeUid, ":%d");
       
   925 	
       
   926 	aMessageUids.Sort();
       
   927 	
       
   928 	TBool inRange = EFalse;
       
   929 	TUint prevUid = 0;
       
   930 	
       
   931 	TImapOverflowDetector overflowHandler;
       
   932 	
       
   933 	RBuf8 sequenceSet;
       
   934 	sequenceSet.CleanupClosePushL();
       
   935 	sequenceSet.CreateL(KSequenceSetGranularity);
       
   936 	
       
   937 	TInt countUids = aMessageUids.Count();
       
   938 	for (TInt i=0; i<countUids; i++)
       
   939 		{
       
   940 		// First (and lowest) uid always gets written
       
   941 		if (i==0)
       
   942 			{
       
   943 			prevUid = aMessageUids[0];
       
   944 			AppendAndGrowFormatL(sequenceSet, KFormatFirstUid(), &overflowHandler, prevUid);
       
   945 			}
       
   946 		// Avoid duplicate uids
       
   947 		else if (aMessageUids[i] > prevUid)
       
   948 			{
       
   949 			if (inRange && aMessageUids[i] > prevUid + 1 )
       
   950 				{
       
   951 				// Next uid is more than 1 greater than the last.  The range has ended.
       
   952 				AppendAndGrowFormatL(sequenceSet, KFormatEndRangeAndNextUid(), &overflowHandler, prevUid, aMessageUids[i]);
       
   953 				inRange = EFalse;
       
   954 				}
       
   955 			else if (!inRange)
       
   956 				{
       
   957 				if (aMessageUids[i] == prevUid + 1)
       
   958 					{
       
   959 					// One greater than the last uid means a range has started.  
       
   960 					// Wait until the end of the range before outputing anything.
       
   961 					inRange = ETrue;
       
   962 					}
       
   963 				else
       
   964 					{
       
   965 					// This one is on its own.
       
   966 					AppendAndGrowFormatL(sequenceSet, KFormatNextUid(), &overflowHandler, aMessageUids[i]);
       
   967 					}			
       
   968 				}
       
   969 			}
       
   970 			
       
   971 		prevUid = aMessageUids[i];
       
   972 		}
       
   973 	
       
   974 	// Output the final (range ending) value as it was skipped earlier.
       
   975 	if (inRange)
       
   976 		{
       
   977 		AppendAndGrowFormatL(sequenceSet, KFormatFinalEndRangeUid(), &overflowHandler, prevUid);
       
   978 		}
       
   979 	
       
   980 	// Allocate on the heap.
       
   981 	HBufC8* sequenceSetOnHeap = sequenceSet.AllocL();
       
   982 	// Rbuf no longer needed...
       
   983 	CleanupStack::PopAndDestroy(&sequenceSet);
       
   984 	
       
   985 	// But heap version needs to be put onto the cleanup stack.
       
   986 	CleanupStack::PushL(sequenceSetOnHeap);
       
   987 	return sequenceSetOnHeap;
       
   988 	}
       
   989 
       
   990 /**
       
   991 @return A pointer to the input stream
       
   992 @internalComponent
       
   993 */
       
   994 MInputStream* CImapSession::InputStream()
       
   995 	{
       
   996 	return iInputStream;
       
   997 	}
       
   998 
       
   999 /**
       
  1000 @return A pointer to the output stream
       
  1001 @internalComponent
       
  1002 */
       
  1003 MOutputStream* CImapSession::OutputStream()
       
  1004 	{
       
  1005 	return iOutputStream;
       
  1006 	}
       
  1007 
       
  1008 void CImapSession::StartCommandL(TRequestStatus& aStatus, CImapCommand* aCommand)
       
  1009 	{
       
  1010 	__ASSERT_DEBUG(iCurrentCommand == NULL, TImapServerPanic::ImapPanic(TImapServerPanic::ESessionNotNullCurrentCommand));
       
  1011 	__ASSERT_DEBUG(iOutputStream != NULL, TImapServerPanic::ImapPanic(TImapServerPanic::ESessionNullOutputStream));
       
  1012 	__ASSERT_DEBUG(iInputStream != NULL, TImapServerPanic::ImapPanic(TImapServerPanic::ESessionNullInputStream));
       
  1013 	__ASSERT_DEBUG(!iInputStream->IsReading(), TImapServerPanic::ImapPanic(TImapServerPanic::ESessionBadInputStreamState));
       
  1014 	__ASSERT_DEBUG(iSessionState == ESessionNormal, TImapServerPanic::ImapPanic(TImapServerPanic::ESessionInvalidSessionState));
       
  1015 	
       
  1016 	iCurrentCommand = aCommand; // Take ownership immediately before there's a chance of leaving...
       
  1017 		
       
  1018 	iCurrentCommand->SendMessageL(++iNextTagId, *iOutputStream);
       
  1019 	
       
  1020 	// Start supplying Imap Server data to the command.
       
  1021 	if (iInputBuffer.Length() > 0)
       
  1022 		{
       
  1023 		// Use data that was previously delivered by the input stream
       
  1024 		// but which has not yet been consumed.
       
  1025 		ProcessInputBufferAsync();
       
  1026 		}
       
  1027 	else
       
  1028 		{
       
  1029 		RequestReadData();
       
  1030 		}
       
  1031 			
       
  1032 	// Queue should always be the last method, so as to avoid leaving!
       
  1033 	Queue(aStatus);
       
  1034 	}
       
  1035 
       
  1036 /**
       
  1037 Requests data from the input stream
       
  1038 */
       
  1039 void CImapSession::RequestReadData()
       
  1040 	{
       
  1041 	// Check that there is no asynchronous call to ProcessInputBuffer outstanding
       
  1042 	__ASSERT_DEBUG(iAsyncCallBackOpCode != EAsyncCallBackOpProcessInputBuffer, TImapServerPanic::ImapPanic(TImapServerPanic::ESessionAsyncCallBackOpInvalid));
       
  1043 	__ASSERT_DEBUG(iInputStream!=NULL, TImapServerPanic::ImapPanic(TImapServerPanic::ESessionNullInputStream));
       
  1044 	
       
  1045 	__LOG_TEXT(iLogId, "CImapSession::RequestReadData()");
       
  1046 	
       
  1047 	if (iInputStream != NULL)
       
  1048 		{
       
  1049 		if( iPendingOperation == EOpIdleDone)
       
  1050 			{
       
  1051 			__LOG_TEXT(iLogId, "CImapSession iInputStream->ReadReq() for DONE");
       
  1052 			SetPendingOperation(EOpNone);
       
  1053 			iInputStream->ReadReq(10);
       
  1054 			}
       
  1055 		else 
       
  1056 			{
       
  1057 			__LOG_TEXT(iLogId, "CImapSession iInputStream->ReadReq()");
       
  1058 			iInputStream->ReadReq();
       
  1059 			}
       
  1060 		
       
  1061 		if (iSessionState == ESessionFlushing)
       
  1062 			{
       
  1063 			__LOG_TEXT(iLogId, "CImapSession Start FlushTimeout");
       
  1064 			iFlushCommandTimeout->After(KFlushTimeoutPeriod);
       
  1065 			}
       
  1066 		}
       
  1067 	}
       
  1068 
       
  1069 /**
       
  1070 Stops reading server data and completes any Queued operation with KErrCancel.
       
  1071 Call FlushCancelledCommand() to read and discard any data associated with the command
       
  1072 Or call DoneIdle() to complete an idle command.
       
  1073 */
       
  1074 EXPORT_C void CImapSession::Cancel()
       
  1075 	{
       
  1076 	__LOG_TEXT(iLogId, "CImapSession::Cancel() - START");
       
  1077 	DoCancel();
       
  1078 	__LOG_TEXT(iLogId, "CImapSession::Cancel() - done DoCancel");
       
  1079 	Complete(KErrCancel);
       
  1080 	__LOG_TEXT(iLogId, "CImapSession::Cancel() - END");
       
  1081 	}
       
  1082 
       
  1083 /**
       
  1084 Stops reading server data, but does not complete any Queued operation.
       
  1085 This should either be called by Cancel() itself - which will complete the queued operation with KErrCancel
       
  1086 or from methods internal to CImapSession.  
       
  1087 Internal methods that call DoCancel() are reponsible for ensuring that any queued operation will get completed.
       
  1088  - either by completing with some error code just before or after calling this method.
       
  1089  - or by initiating a new async step that will complete the queued operation later
       
  1090 */
       
  1091 void CImapSession::DoCancel()
       
  1092 	{
       
  1093 	__LOG_FORMAT((iLogId, "CImapSession::DoCancel() - START - iSessionState: %d, iPendingOperation: %d, iCurrentCommand: 0x%08x", iSessionState, iPendingOperation, iCurrentCommand ));
       
  1094 	// Stop processing server data
       
  1095 	if (iInputStream != NULL)
       
  1096 		{
       
  1097 		__LOG_TEXT(iLogId, "CImapSession::DoCancel() - iInputStream->CancelReadReq()");
       
  1098 		iInputStream->CancelReadReq();
       
  1099 		__LOG_TEXT(iLogId, "CImapSession::DoCancel() - iInputStream->CancelReadReq() cancelled");
       
  1100 		}
       
  1101 		
       
  1102 	iAsyncCallBack->Cancel();
       
  1103 	iAsyncCallBackOpCode = EAsyncCallBackOpNone;
       
  1104 	__LOG_TEXT(iLogId, "CImapSession::DoCancel() - iAsyncCallBackOpCode = EAsyncCallBackOpNone");
       
  1105 	
       
  1106 	iFlushCommandTimeout->Cancel();
       
  1107 	__LOG_TEXT(iLogId, "CImapSession::DoCancel() - iFlushCommandTimeout cancelled");
       
  1108 	
       
  1109 	if (iSessionState == ESessionNormal && iCurrentCommand != NULL)
       
  1110 		{
       
  1111 		__LOG_TEXT(iLogId, "CImapSession::DoCancel() - cancelling the current command");
       
  1112 		
       
  1113 		iCurrentCommand->Cancel();
       
  1114 		DoPendingOperationForCancel();
       
  1115 		
       
  1116 		// Most commands need to flush after cancel, but commands such as Idle may have different behaviours.
       
  1117 		if (iCurrentCommand->Flushing())
       
  1118 			{
       
  1119 			SetSessionState(ESessionFlushing);
       
  1120 			}
       
  1121 		}
       
  1122 	__LOG_FORMAT((iLogId, "CImapSession::DoCancel() - END - iSessionState: %d, iCurrentCommand: 0x%08x", iSessionState, iCurrentCommand ));
       
  1123 	}
       
  1124 
       
  1125 /**
       
  1126 This method reads and discards incoming data from the IMAP server until 
       
  1127 no more data is expected.
       
  1128 It can be called after calling Cancel() on any asynchronous method other 
       
  1129 than EnterIdleL() or WaitForIdleEvent().
       
  1130 It usually will complete when all the data for the cancelled command has been received.
       
  1131 The method will also complete after a 10 second timeout - indicating that the 
       
  1132 expected data has not been received from the server.
       
  1133 @param aStatus Signals completion of the request or a timeout.
       
  1134 */
       
  1135 EXPORT_C void CImapSession::FlushCancelledCommand(TRequestStatus& aStatus)
       
  1136 	{
       
  1137 	__LOG_TEXT(iLogId, "CImapSession::FlushCancelledCommand()");
       
  1138 	
       
  1139 	// Complete immediately if the streams are closed.
       
  1140 	// The caller receives the KErrImapClosed status code.
       
  1141 	if (CompleteIfStreamsClosed(aStatus))
       
  1142 		{
       
  1143 		return;
       
  1144 		}
       
  1145 	
       
  1146 	Queue(aStatus);
       
  1147 		
       
  1148 	// Complete immediately if there is no command to flush.
       
  1149 	// The caller will receive the KErrNone status code - so will know that the streams are open.
       
  1150 	// This makes it possible to call Cancel() followed by FlushCancelledCommand() when there is no command operating.
       
  1151 	if (iCurrentCommand == NULL)
       
  1152 		{
       
  1153 		__ASSERT_DEBUG(iSessionState == ESessionNormal, TImapServerPanic::ImapPanic(TImapServerPanic::ESessionInvalidSessionState));
       
  1154 		__ASSERT_DEBUG(iPendingOperation == EOpNone, TImapServerPanic::ImapPanic(TImapServerPanic::ESessionInvalidPendingOp));
       
  1155 		
       
  1156 		__LOG_TEXT(iLogId, "CImapSession No command to flush");
       
  1157 		Complete(KErrNone);
       
  1158 		return;
       
  1159 		}
       
  1160 		
       
  1161 	// If we got this far, then a command is in progress.
       
  1162 	// The following ASSERTS ensure that it is approriate to be Flushing the command at this time.
       
  1163 	__ASSERT_DEBUG(iCurrentCommand->Flushing(), TImapServerPanic::ImapPanic(TImapServerPanic::ESessionCommandNotFlushing));
       
  1164 	__ASSERT_DEBUG(iSessionState == ESessionFlushing, TImapServerPanic::ImapPanic(TImapServerPanic::ESessionInvalidSessionState));
       
  1165 
       
  1166 	// Complete immediately if the command can be closed early
       
  1167 	if (iCurrentCommand->CanCompleteFlushNow())
       
  1168 		{
       
  1169 		CompleteAndDestroyCommand(KErrNone, EFalse);
       
  1170 		SetSessionState(ESessionNormal);
       
  1171 		return;
       
  1172 		}
       
  1173 	
       
  1174 	// Continue supplying Imap Server data to the command.
       
  1175 	if (iInputBuffer.Length() > 0)
       
  1176 		{
       
  1177 		// Use data that was previously delivered by the input stream
       
  1178 		// but which has not yet been consumed.
       
  1179 		ProcessInputBufferAsync();
       
  1180 		}
       
  1181 	else
       
  1182 		{
       
  1183 		RequestReadData();
       
  1184 		}
       
  1185 	}
       
  1186 
       
  1187 /**
       
  1188 This is called when the FlushCancelledCommand() operation times out.
       
  1189 It cancels the operation and completes with the code KErrImapFlushTimeout.
       
  1190 @param aSourceTimer a referecne to the iFlushCommandTimeout object.
       
  1191 */
       
  1192 #ifdef _DEBUG
       
  1193 void CImapSession::OnTimerL(const CImapObservableTimer& aSourceTimer)
       
  1194 #else // _DEBUG
       
  1195 void CImapSession::OnTimerL(const CImapObservableTimer& /*aSourceTimer*/)
       
  1196 #endif // _DEBUG
       
  1197 	{
       
  1198 	__LOG_TEXT(iLogId, "CImapSession::OnTimerL()");
       
  1199 	__ASSERT_DEBUG(&aSourceTimer == iFlushCommandTimeout, TImapServerPanic::ImapPanic(TImapServerPanic::ESessionUnknownTimer));
       
  1200 	
       
  1201 	__ASSERT_DEBUG(iCurrentCommand->Flushing(), TImapServerPanic::ImapPanic(TImapServerPanic::ESessionCommandNotFlushing));
       
  1202 	__ASSERT_DEBUG(iSessionState == ESessionFlushing, TImapServerPanic::ImapPanic(TImapServerPanic::ESessionInvalidSessionState));
       
  1203 	
       
  1204 	DoCancel();	
       
  1205 	Complete(KErrImapFlushTimeout);
       
  1206 	}
       
  1207 
       
  1208 /**
       
  1209 Commands (such as CImapAppend) that send their data asynchronously
       
  1210 should call this method if the send fails (e.g. due to lack of resources)
       
  1211 */
       
  1212 void CImapSession::AsyncSendFailed(TInt aErr)
       
  1213 	{
       
  1214 	__LOG_FORMAT((iLogId, "CImapSession::AsyncSendFailed(%d)", aErr));
       
  1215 	// Report the error.  
       
  1216 	// Assert that there is a TRequestStatus to report to.
       
  1217 	// This should always be the case, a command's send/receive is always paired with a call to Queue.
       
  1218 	__ASSERT_DEBUG(iReport != NULL, TImapServerPanic::ImapPanic(TImapServerPanic::ESessionNullReportStatus));
       
  1219 	CompleteAndDestroyCommand(aErr, ETrue);
       
  1220 	
       
  1221 	SetSessionState(ESessionUnrecoverable);
       
  1222 	}
       
  1223 
       
  1224 /**
       
  1225 Call this last when an asynch operation has been requested.
       
  1226 @param aStatus	The request status of an active object that will be notified 
       
  1227 				when the async operation has completed.
       
  1228 */
       
  1229 void CImapSession::Queue(TRequestStatus& aStatus)
       
  1230     {
       
  1231     if(iReport !=NULL)
       
  1232     	return;
       
  1233 	__ASSERT_DEBUG(iReport==NULL, TImapServerPanic::ImapPanic(TImapServerPanic::ESessionReportStatusAlreadyQueued));
       
  1234     aStatus=KRequestPending;
       
  1235     iReport=&aStatus;
       
  1236     }
       
  1237 
       
  1238 /**
       
  1239 Call this last when an asynch operation has been completed.
       
  1240 @param aStatus the return error/status code for the completed operation.
       
  1241 */
       
  1242 void CImapSession::Complete(TInt aStatus)
       
  1243 	{
       
  1244 	__LOG_FORMAT((iLogId, "CImapSession::Complete() - aStatus: %d, iReport: 0x%08x", aStatus, iReport));
       
  1245 	if (iReport)
       
  1246 	    {
       
  1247 	    // only complete properly once.
       
  1248 	    // this allows a derived class to complete and then cancel, reporting the desired state instead of KErrCancel
       
  1249 	    DoComplete(aStatus);
       
  1250 	    User::RequestComplete(iReport,aStatus);
       
  1251 		}
       
  1252 	}
       
  1253 
       
  1254 /**
       
  1255 Implements CMsgActive::DoComplete()
       
  1256 Does nothing except logging the call.
       
  1257 */
       
  1258 #ifdef __IMAP_LOGGING
       
  1259 void CImapSession::DoComplete(TInt& aStatus)
       
  1260 #else //__IMAP_LOGGING
       
  1261 void CImapSession::DoComplete(TInt& /*aStatus*/)
       
  1262 #endif //__IMAP_LOGGING
       
  1263 	{
       
  1264 	__LOG_FORMAT((iLogId, "CImapSession::DoComplete() - completing observers status with error: %d", aStatus));
       
  1265 	}
       
  1266 
       
  1267 TInt CImapSession::AsyncCallBack(TAny* aSelf)
       
  1268 // static method
       
  1269 	{
       
  1270 	CImapSession* self = static_cast<CImapSession*>(aSelf);
       
  1271 	self->AsyncCallBack();
       
  1272 	
       
  1273 	return EFalse; // Tell the OS not to call this method again without being requested.
       
  1274 	}
       
  1275 
       
  1276 void CImapSession::AsyncCallBack()
       
  1277 	{
       
  1278 	TRAPD(err, DoAsyncCallBackL());
       
  1279 	if (err != KErrNone)
       
  1280 		{
       
  1281 		__LOG_FORMAT((iLogId, "CImapSession Leave in DoAsyncCallBackL(): %d", err));
       
  1282 		// Report the error.  
       
  1283 		// Assert that there is a TRequestStatus to report to.
       
  1284 		// This should always be the case, as async callbacks requests are paired with calls to Queue.
       
  1285 		__ASSERT_DEBUG(iReport != NULL, TImapServerPanic::ImapPanic(TImapServerPanic::ESessionNullReportStatus));
       
  1286 		CompleteAndDestroyCommand(err, ETrue);
       
  1287 		
       
  1288 		SetSessionState(ESessionUnrecoverable);
       
  1289 		}
       
  1290 	}
       
  1291 	
       
  1292 void CImapSession::DoAsyncCallBackL()
       
  1293 	{
       
  1294 	__LOG_TEXT(iLogId, "CImapSession::DoAsyncCallBackL()");
       
  1295 	
       
  1296 	// Allow methods called below to check that no async operation is queued,
       
  1297 	// and even to queue one up, by caching the current op code and nulling it.
       
  1298 	TAsyncCallBackOpCode cachedOpCode = iAsyncCallBackOpCode;
       
  1299 	iAsyncCallBackOpCode = EAsyncCallBackOpNone;
       
  1300 	
       
  1301 	__LOG_TEXT(iLogId, "CImapSession::iAsyncCallBackOpCode = EAsyncCallBackOpNone");
       
  1302 	
       
  1303 	switch (cachedOpCode)
       
  1304 		{
       
  1305 		case EAsyncCallBackOpProcessInputBuffer:
       
  1306 			{
       
  1307 			__LOG_TEXT(iLogId, "CImapSession cachedOpCode = EAsyncCallBackOpNone");
       
  1308 			ProcessInputBufferL();
       
  1309 			}	
       
  1310 			break;
       
  1311 		case EAsyncCallBackOpNone:
       
  1312 		default:
       
  1313 			{
       
  1314 			// No valid op code was specified.
       
  1315 			__ASSERT_DEBUG(EFalse, TImapServerPanic::ImapPanic(TImapServerPanic::ESessionAsyncCallBackOpInvalid));
       
  1316 			break;
       
  1317 			}			
       
  1318 		}
       
  1319 	}
       
  1320 
       
  1321 /**
       
  1322 Calls ProcessInputBufferL() at a later stage.
       
  1323 */
       
  1324 void CImapSession::ProcessInputBufferAsync()
       
  1325 	{
       
  1326 	__LOG_TEXT(iLogId, "CImapSession::ProcessInputBufferAsync()");
       
  1327 	
       
  1328 	// if we have an input stream, assert that it is not reading.
       
  1329 	__ASSERT_DEBUG((iInputStream == NULL) ? !iInputStream->IsReading() : ETrue, TImapServerPanic::ImapPanic(TImapServerPanic::ESessionBadInputStreamState));
       
  1330 	__ASSERT_DEBUG(iAsyncCallBackOpCode == EAsyncCallBackOpNone, TImapServerPanic::ImapPanic(TImapServerPanic::ESessionAsyncCallBackOpInvalid));
       
  1331 		
       
  1332 	iAsyncCallBack->CallBack();	
       
  1333 	iAsyncCallBackOpCode = EAsyncCallBackOpProcessInputBuffer;
       
  1334 	__LOG_TEXT(iLogId, "CImapSession::iAsyncCallBackOpCode = EAsyncCallBackOpProcessInputBuffer");
       
  1335 	}
       
  1336 
       
  1337 /**
       
  1338 Notifies the observer that data has been received from the 
       
  1339 connected host.The supplied buffer will remain valid until 
       
  1340 the input stream is notified that it is no longer needed.
       
  1341 
       
  1342 @param	aBuffer	A buffer containing the received data.
       
  1343 @see MInputStreamObserver
       
  1344 */
       
  1345 void CImapSession::ReceivedDataIndL(const TDesC8& aBuffer)
       
  1346 // Implements MInputStreamObserver
       
  1347 	{	
       
  1348 	__LOG_TEXT(iLogId, "CImapSession::ReceivedDataIndL()");
       
  1349 	
       
  1350 	// Should not be requesting an async callback and data from the transport handler at the same time.
       
  1351 	__ASSERT_DEBUG(iAsyncCallBackOpCode != EAsyncCallBackOpProcessInputBuffer, TImapServerPanic::ImapPanic(TImapServerPanic::ESessionAsyncCallBackOpInvalid));
       
  1352 
       
  1353 	// Should not have any data remaining in the input buffer.
       
  1354 	// If we have then the stream was restarted too soon.
       
  1355 	__ASSERT_DEBUG(iInputBuffer.Length()==0, TImapServerPanic::ImapPanic(TImapServerPanic::ESessionInputBufferNotEmpty));
       
  1356 
       
  1357 	iInputBuffer.Set(aBuffer);
       
  1358 	
       
  1359 	iFlushCommandTimeout->Cancel();
       
  1360 	
       
  1361 	ProcessInputBufferL();
       
  1362 	}
       
  1363 	
       
  1364 /**
       
  1365 Processes data in iInputBuffer
       
  1366 */
       
  1367 void CImapSession::ProcessInputBufferL()
       
  1368 	{
       
  1369 	// Should have a command ready to process the input buffer.
       
  1370 	__ASSERT_DEBUG(iCurrentCommand != NULL, TImapServerPanic::ImapPanic(TImapServerPanic::ESessionNullCurrentCommand));
       
  1371 	__ASSERT_DEBUG(iSessionState == ESessionNormal || iSessionState == ESessionFlushing, TImapServerPanic::ImapPanic(TImapServerPanic::ESessionInvalidSessionState));
       
  1372 
       
  1373 	TPtrC8 dataToDeliver(KNullDesC8());
       
  1374 	
       
  1375 	TBool continueReadingData = ETrue;	
       
  1376 	TBool commandComplete = EFalse;
       
  1377 	TBool deliveredSomeData = EFalse;
       
  1378 	CImapCommand::TParseState commandParseState = CImapCommand::EWaitStartResponse;
       
  1379 				
       
  1380 	while(iInputBuffer.Length() > 0 && continueReadingData)
       
  1381 		{
       
  1382 		// The following TryFindXxx methods will remove data from iInputBuffer,
       
  1383 		//   returning it to dataToDeliver
       
  1384 		//   and/or copying it the iInputCache
       
  1385 			
       
  1386 		TBool foundBlock = EFalse;	
       
  1387 		if (iCommandLiteralRequestSize == 0)
       
  1388 			{
       
  1389 			foundBlock = TryFindLineL(dataToDeliver);
       
  1390 			}
       
  1391 		else
       
  1392 			{
       
  1393 			foundBlock = TryFindLiteralBlockL(dataToDeliver);
       
  1394 			}
       
  1395 			
       
  1396 		if (foundBlock)
       
  1397 			{
       
  1398 			// Reset expected command literal size, now that we are delivering a whole block.
       
  1399 			iCommandLiteralRequestSize = 0;
       
  1400 			
       
  1401 			// Deliver the data to the command
       
  1402 			TRAPD(err, 
       
  1403 				commandParseState = iCurrentCommand->ParseBlockL(dataToDeliver);
       
  1404 				);
       
  1405 				
       
  1406 			// Record that at least one block of data was delivered
       
  1407 			deliveredSomeData = ETrue;
       
  1408 				
       
  1409 			// Cleanup the cache
       
  1410 			iInputCache->Reset();
       
  1411 			dataToDeliver.Set(KNullDesC8()); // defensive: dataToDeliver might be invalid if it was pointing at the cache
       
  1412 				
       
  1413 			if (err != KErrNone)
       
  1414 				{
       
  1415 				// As well as completing, destroy the command to help free up resources.
       
  1416 				CompleteAndDestroyCommand(err, ETrue);
       
  1417 
       
  1418 				// Don't allow the session to be called again.
       
  1419 				SetSessionState(ESessionUnrecoverable);
       
  1420 				
       
  1421 				return;
       
  1422 				}
       
  1423 				
       
  1424 			// If a literal block is expected next, then find out how big it is expected to be.
       
  1425 			switch (commandParseState)
       
  1426 				{
       
  1427 				case CImapCommand::EWaitStartResponse:
       
  1428 					{
       
  1429 					// This state means that a response been completely parsed,
       
  1430 					// but another response is expected.for this command.
       
  1431 					// Usually this means the last response was untagged * or +,
       
  1432 					// but it can also happen during multi-fetch where more than one tagged OK is expected.
       
  1433 
       
  1434 					continueReadingData = DoPendingOperationForIntermediateResponse();
       
  1435 					}
       
  1436 					break;
       
  1437 				case CImapCommand::EWaitLiteralParse:
       
  1438 				case CImapCommand::EWaitLiteralIngore:
       
  1439 					{
       
  1440 					iCommandLiteralRequestSize = iCurrentCommand->LiteralBytesExpected();
       
  1441 					__ASSERT_DEBUG(iCommandLiteralRequestSize > 0, TImapServerPanic::ImapPanic(TImapServerPanic::ESessionLiteralSizeZero));
       
  1442 					}
       
  1443 					break;
       
  1444 				case CImapCommand::ECommandComplete:
       
  1445 					{
       
  1446 					commandComplete = ETrue;
       
  1447 					continueReadingData = EFalse;
       
  1448 					}
       
  1449 					break;
       
  1450 				default:
       
  1451 					break;
       
  1452 				}				
       
  1453 			}
       
  1454 		else // block not found
       
  1455 			{
       
  1456 			// All the data should have been added to the cache
       
  1457 			__ASSERT_DEBUG(iInputBuffer.Length() == 0, TImapServerPanic::ImapPanic(TImapServerPanic::ESessionInputBufferNotEmpty));
       
  1458 			}
       
  1459 			
       
  1460 		} // end of while loop
       
  1461 		
       
  1462 	// The current block of data has been parsed.  Do we need any more, or are we finished?
       
  1463 	if (commandComplete)
       
  1464 		{
       
  1465 		CommandComplete();
       
  1466 		}
       
  1467 	else if (continueReadingData)
       
  1468 		{
       
  1469 		RequestReadData();
       
  1470 		
       
  1471 		if (deliveredSomeData)
       
  1472 			{
       
  1473 			// Inform the command that no more data is available from the input buffer.
       
  1474 			// This allows the command to commit any bulk operations while waiting for the next set of data.
       
  1475 			__ASSERT_DEBUG(iCurrentCommand != NULL, TImapServerPanic::ImapPanic(TImapServerPanic::ESessionNullCurrentCommand));
       
  1476 			iCurrentCommand->WaitingForMoreDataL();
       
  1477 			}
       
  1478 		}
       
  1479 	}
       
  1480 
       
  1481 void CImapSession::CommandComplete()
       
  1482 	{
       
  1483 	switch (iCurrentCommand->ResponseCode())
       
  1484 		{
       
  1485 		case CImapCommand::EImapResponseOk:
       
  1486 			{
       
  1487 			if (iSessionState == ESessionNormal)
       
  1488 				{
       
  1489 				// Complete unless deferred by pending operation.
       
  1490 				if (DoPendingOperationForOk())
       
  1491 					{
       
  1492 					// Command has completed successfully
       
  1493 					CompleteAndDestroyCommand(KErrNone, EFalse);
       
  1494 					}
       
  1495 				}
       
  1496 			else
       
  1497 				{
       
  1498 				// We're flushing the command, so always complete straight away.
       
  1499 				__ASSERT_DEBUG(iSessionState == ESessionFlushing, TImapServerPanic::ImapPanic(TImapServerPanic::ESessionInvalidSessionState));
       
  1500 				CompleteAndDestroyCommand(KErrNone, EFalse);
       
  1501 				SetSessionState(ESessionNormal);
       
  1502 				}				
       
  1503 						
       
  1504 			// NOTE: No need to request more data here.  The next StartCommandL will do that for us.
       
  1505 			}
       
  1506 			break;
       
  1507 		case CImapCommand::EImapResponseNo:
       
  1508 			{
       
  1509 			DoPendingOperationForFail();			
       
  1510 			CompleteAndDestroyCommand(KErrImapNo, EFalse);
       
  1511 			SetSessionState(ESessionNormal);
       
  1512 			}
       
  1513 			break;
       
  1514 		case CImapCommand::EImapResponseBad:
       
  1515 			{
       
  1516 			DoPendingOperationForFail();			
       
  1517 			CompleteAndDestroyCommand(KErrImapBad, EFalse);
       
  1518 			SetSessionState(ESessionNormal);
       
  1519 			}
       
  1520 			break;
       
  1521 		default:
       
  1522 			{
       
  1523 			// No other result codes should be returned.
       
  1524 			__ASSERT_DEBUG(EFalse, TImapServerPanic::ImapPanic(TImapServerPanic::ESessionInvalidCommandResponseCode));
       
  1525 			}
       
  1526 			break;
       
  1527 		}
       
  1528 	}
       
  1529 
       
  1530 /**
       
  1531 Destroys the current command object and completes any outstanding asynchronous request with the supplied completion code
       
  1532 The input and output streams are optionally closed too - this should be done when we are completing because an unexpected error has just occured.
       
  1533 @param aCompletionCode the return error/status code for the completed operation
       
  1534 @param aCloseStreams whether to close the input and output streams
       
  1535 */
       
  1536 void CImapSession::CompleteAndDestroyCommand(TInt aCompletionCode, TBool aCloseStreams)
       
  1537 	{
       
  1538 	__LOG_FORMAT((iLogId, "CImapSession::CompleteAndDestroyCommand() - START - iSessionState: %d, iPendingOperation: %d, iCurrentCommand: 0x%08x, aCompletionCode: %d, aCloseStreams: %d", iSessionState, iPendingOperation, iCurrentCommand, aCompletionCode, aCloseStreams ));
       
  1539 	// Complete must happen BEFORE closing the stream so that the correct error code is returned to the async caller.
       
  1540 	// If we allowed iOutputStream->Close() to be called first, then KErrImapClosed would be returned - which is not what we want.
       
  1541 	Complete(aCompletionCode);
       
  1542 	
       
  1543 	//	Pipelining commands can increment the tag-id internally, so we need to find the 
       
  1544 	// latest value for the next command.And before closing the command object, fetch the current command tag Id.
       
  1545 	if( iCurrentCommand != NULL )	
       
  1546 		{
       
  1547 		iNextTagId = iCurrentCommand->GetTagId();
       
  1548 		}
       
  1549 
       
  1550 	// iOutputStream->Close() must be called BEFORE iCurrentCommand is destroyed.
       
  1551 	// This is because iCurrentCommand might have initiated an async write operation on the stream 
       
  1552 	// which may not have completed yet, in which case the stream will still be referencing output buffer
       
  1553 	// the descriptor owned by the iCurrentCommand.
       
  1554 	// Calling Close() will cancel the async write, making it safe to destroy the command.
       
  1555 	// This helps avoid an ESOCK 14 panic (bad descriptor)
       
  1556 	if (aCloseStreams && iOutputStream != NULL)
       
  1557 		{
       
  1558 		iOutputStream->Close();
       
  1559 		}
       
  1560 		
       
  1561 	// Finished with this command object...
       
  1562 	delete iCurrentCommand;
       
  1563 	iCurrentCommand = NULL;
       
  1564 	
       
  1565 	SetPendingOperation(EOpNone);
       
  1566 	__LOG_FORMAT((iLogId, "CImapSession::CompleteAndDestroyCommand() - END - iSessionState: %d, iPendingOperation: %d, iCurrentCommand: 0x%08x, aCompletionCode: %d, aCloseStreams: %d", iSessionState, iPendingOperation, iCurrentCommand, aCompletionCode, aCloseStreams ));
       
  1567 	}
       
  1568 
       
  1569 /**
       
  1570 Perform any extra operations upon reciept of the command's tagged OK response
       
  1571 @return Whether it is OK to CompleteAndDestroyCommand() straight away.  
       
  1572 		Some commands may continue to run asynchronusly after receiving the tagged OK response
       
  1573 		CompleteAndDestroyCommand() after receving further notification that the command has completed.
       
  1574 */
       
  1575 TBool CImapSession::DoPendingOperationForOk()
       
  1576 	{
       
  1577 	TBool completeNow = ETrue;
       
  1578 	
       
  1579 	switch (iPendingOperation)
       
  1580 		{
       
  1581 		case EOpServerGreeting:
       
  1582 			{
       
  1583 			if (iServerGreetingInfo->ResponseTag() == CImapServerGreetingInfo::ETagOk)
       
  1584 				{
       
  1585 				SetServerState(EServerStateNotAuthenticated);
       
  1586 				}
       
  1587 			else if (iServerGreetingInfo->ResponseTag() == CImapServerGreetingInfo::ETagPreAuth)
       
  1588 				{
       
  1589 				SetServerState(EServerStateAuthenticated);
       
  1590 				}					
       
  1591 			}
       
  1592 			break;
       
  1593 			
       
  1594 		case EOpSelect:
       
  1595 			{
       
  1596 			SetServerState(EServerStateSelected);
       
  1597 			}
       
  1598 			break;
       
  1599 		case EOpClose:
       
  1600 			{
       
  1601 			SetServerState(EServerStateAuthenticated);
       
  1602 			
       
  1603 			delete iSelectedFolderInfo;
       
  1604 			iSelectedFolderInfo = NULL;
       
  1605 			}
       
  1606 			break;
       
  1607 		case EOpLogin:
       
  1608 			{
       
  1609 			SetServerState(EServerStateAuthenticated);
       
  1610 			
       
  1611 			__ASSERT_DEBUG(iSelectedFolderInfo == NULL, TImapServerPanic::ImapPanic(TImapServerPanic::ESessionNullSelectedFolderInfo));
       
  1612 			}
       
  1613 			break;
       
  1614 #if (defined SYMBIAN_EMAIL_CAPABILITY_SUPPORT)
       
  1615 		case EOpAuthenticate:
       
  1616 			{
       
  1617 			SetServerState(EServerStateAuthenticated);
       
  1618 			
       
  1619 			__ASSERT_DEBUG(iSelectedFolderInfo == NULL, TImapServerPanic::ImapPanic(TImapServerPanic::ESessionNullSelectedFolderInfo));
       
  1620 			}
       
  1621 			break;
       
  1622 #endif
       
  1623 		case EOpLogout:
       
  1624 			{
       
  1625 			SetServerState(EServerStateNone);
       
  1626 			
       
  1627 			delete iSelectedFolderInfo;
       
  1628 			iSelectedFolderInfo = NULL;
       
  1629 			}
       
  1630 			break;
       
  1631 		case EOpWaitForBodyOperationComplete:
       
  1632 			{
       
  1633 			// Wait for FetchBodyOperationComplete() to complete.
       
  1634 			CImapFetchBody* fetchBodyCommand = static_cast<CImapFetchBody*>(iCurrentCommand);
       
  1635 			completeNow = fetchBodyCommand->IsStoreOperationComplete();
       
  1636 			}			
       
  1637 			break;
       
  1638 		default:
       
  1639 			break;
       
  1640 		}
       
  1641 		
       
  1642 	return completeNow;
       
  1643 	}
       
  1644 	
       
  1645 /**
       
  1646 Called when the IMAP server returns with a tagged NO or tagged BAD response.
       
  1647 */
       
  1648 void CImapSession::DoPendingOperationForFail()
       
  1649 	{
       
  1650 	switch (iPendingOperation)
       
  1651 		{
       
  1652 		case EOpSelect:
       
  1653 			{
       
  1654 			SetServerState(EServerStateAuthenticated);
       
  1655 			
       
  1656 			delete iSelectedFolderInfo;
       
  1657 			iSelectedFolderInfo = NULL;
       
  1658 			}
       
  1659 			break;
       
  1660 		default:
       
  1661 			break;
       
  1662 		}
       
  1663 	}
       
  1664 
       
  1665 /**
       
  1666 Called when cancelling a command.
       
  1667 If an operation can change the server state, assume that the server is in the lowest
       
  1668 state for that operation.
       
  1669 */
       
  1670 void CImapSession::DoPendingOperationForCancel()
       
  1671 	{
       
  1672 	switch (iPendingOperation)
       
  1673 		{
       
  1674 		case EOpSelect:
       
  1675 		case EOpClose:
       
  1676 			{
       
  1677 			SetServerState(EServerStateAuthenticated);
       
  1678 			
       
  1679 			delete iSelectedFolderInfo;
       
  1680 			iSelectedFolderInfo = NULL;
       
  1681 			}
       
  1682 			break;
       
  1683 		case EOpLogout:
       
  1684 			{
       
  1685 			SetServerState(EServerStateNone);
       
  1686 			
       
  1687 			delete iSelectedFolderInfo;
       
  1688 			iSelectedFolderInfo = NULL;
       
  1689 			}
       
  1690 			break;
       
  1691 		default:
       
  1692 			break;
       
  1693 		}
       
  1694 	}
       
  1695 
       
  1696 /**
       
  1697 This is called after any resopnse other than the final response has been parsed.
       
  1698 @return whether to continue reading data from the output stream
       
  1699 */
       
  1700 TBool CImapSession::DoPendingOperationForIntermediateResponse()
       
  1701 	{
       
  1702 	TBool continueParsing = ETrue;
       
  1703 	
       
  1704 	switch (iPendingOperation)
       
  1705 		{
       
  1706 		case EOpIdleEnter:
       
  1707 		case EOpIdleWait:
       
  1708 			{
       
  1709 			CImapIdle* idleCommand = static_cast<CImapIdle*>(iCurrentCommand);
       
  1710 			if (idleCommand->IdleState() == CImapIdle::EIdleWaitResponse)
       
  1711 				{
       
  1712 				// EOpIdleEnter: The continuation response has been received.
       
  1713 				// EOpIdleWait:  The next response has been received.
       
  1714 				//	
       
  1715 				// Notify the caller and exit the parse loop.
       
  1716 				// We expect the caller to call either WaitForIdleEvent() or DoneIdle()
       
  1717 				
       
  1718 				Complete(KErrNone);
       
  1719 				continueParsing = EFalse;
       
  1720 				}
       
  1721 			}
       
  1722 			break;
       
  1723 		default:
       
  1724 			break;
       
  1725 		}
       
  1726 	
       
  1727 	return continueParsing;
       
  1728 	}
       
  1729 	
       
  1730 /**
       
  1731 Takes data from iInputBuffer in order to build a literal block.
       
  1732 If not enough data is available, then the whole of iInputBuffer is added to the cache.
       
  1733 iInputBuffer will be updated so that it only points at unconsumed data.
       
  1734 @param aDataToDeliver Output parameter that receives the literal block.
       
  1735 @return 			  If enough data is available, then this parameter is set to point to the whole literal block.
       
  1736 					  Otherwise it points at KNullDesC8.
       
  1737 @return Whether enough data was available to return a whole literal block in the output parameter.
       
  1738 */
       
  1739 TBool CImapSession::TryFindLiteralBlockL(TPtrC8& aDataToDeliver)
       
  1740 	{
       
  1741 	TInt inputCacheLength = iInputCache->Size();
       
  1742 	TBool foundLiteralBlock = EFalse;
       
  1743 	aDataToDeliver.Set(KNullDesC8());
       
  1744 	
       
  1745 	// Is there enough data to send a complete block?
       
  1746 	if (iInputBuffer.Length() + inputCacheLength >= iCommandLiteralRequestSize)
       
  1747 		{
       
  1748 		foundLiteralBlock = ETrue;
       
  1749 		
       
  1750 		// Either send it in directly or use the cache
       
  1751 		TInt lengthToConsume = 0;
       
  1752 		if (inputCacheLength > 0)
       
  1753 			{			
       
  1754 			// Some of the block is in the cache.  So append the rest of the block to the cache and return the cache.
       
  1755 			lengthToConsume = iCommandLiteralRequestSize - inputCacheLength;
       
  1756 			iInputCache->InsertL(iInputCache->Size(), iInputBuffer.Left(lengthToConsume));
       
  1757 			
       
  1758 			aDataToDeliver.Set(iInputCache->Ptr(0));
       
  1759 			}
       
  1760 		else
       
  1761 			{
       
  1762 			// The whole of the block is in iInput buffer.  So just return that.
       
  1763 			lengthToConsume = iCommandLiteralRequestSize;
       
  1764 			aDataToDeliver.Set(iInputBuffer.Left(iCommandLiteralRequestSize));
       
  1765 			}		
       
  1766 			
       
  1767 		// Consume the input buffer
       
  1768 		if (iInputBuffer.Length() > lengthToConsume)
       
  1769 			{
       
  1770 			iInputBuffer.Set(iInputBuffer.Mid(lengthToConsume));
       
  1771 			}
       
  1772 		else
       
  1773 			{
       
  1774 			iInputBuffer.Set(KNullDesC8());
       
  1775 			}
       
  1776 		}
       
  1777 	else
       
  1778 		{
       
  1779 		// Not enough data is available yet.  So cache all of it and wait for more
       
  1780 		iInputCache->InsertL(iInputCache->Size(), iInputBuffer);
       
  1781 		iInputBuffer.Set(KNullDesC8());
       
  1782 		}
       
  1783 	
       
  1784 	return foundLiteralBlock;
       
  1785 	}
       
  1786 	
       
  1787 /**
       
  1788 Takes data from iInputBuffer in order to build a line.
       
  1789 If not enough data is available, then whole of iInputBuffer is added to the cache.
       
  1790 iInputBuffer will be updated so that it only points at unconsumed data.
       
  1791 @param aDataToDeliver Output parameter that receives the line of data.
       
  1792 	   				  If enough data is available, then this parameter is set to point to the whole line (without the CRLF).
       
  1793 					  Otherwise it points at KNullDesC8.
       
  1794 @return Whether enough data was available to return a whole line in the output parameter.
       
  1795 */
       
  1796 TBool CImapSession::TryFindLineL(TPtrC8& aDataToDeliver)
       
  1797 	{
       
  1798 	TInt inputCacheLength = iInputCache->Size();
       
  1799 	TBool foundLine = EFalse;
       
  1800 	aDataToDeliver.Set(KNullDesC8());
       
  1801 	
       
  1802 
       
  1803 	// Need to check for a Special Case first: 
       
  1804 	//   End of cache has the Cr, start of iInputBuffer has the Lf
       
  1805 	//
       
  1806 	// Check for Lf first
       
  1807 	if (iInputBuffer[0] == '\n')
       
  1808 		{
       
  1809 		// Check for Cr
       
  1810 		if (inputCacheLength > 0 && iInputCache->Ptr(inputCacheLength-1)[0] == '\r')
       
  1811 			{
       
  1812 			foundLine = ETrue;
       
  1813 			
       
  1814 			// Point at the line in the cache (but not the Cr)
       
  1815 			aDataToDeliver.Set(iInputCache->Ptr(0).Left(inputCacheLength-1));
       
  1816 			
       
  1817 			// Consume the Lf
       
  1818 			if (iInputBuffer.Length() > 1)
       
  1819 				{
       
  1820 				iInputBuffer.Set(iInputBuffer.Mid(1));
       
  1821 				}
       
  1822 			else
       
  1823 				{
       
  1824 				iInputBuffer.Set(KNullDesC8());
       
  1825 				}
       
  1826 			}
       
  1827 		}
       
  1828 			
       
  1829 	// Usually, the Special Case will fail, so aDataToDeliver will still be empty at this point.
       
  1830 	if (aDataToDeliver.Size() == 0)
       
  1831 		{
       
  1832 		// Try to find a whole CRLF
       
  1833 		
       
  1834 		// In some cases server sends the FETCH header data in the following manner(Eg: Lukku server)
       
  1835 		// *43 FETCH (FLAGS (\Seen $LuukkuClean $NotJunk JunkRecorded) UID 6285 BODYSTRUCTURE (("TEXT" "PLAIN" ("CHARSET" "ISO-8859-1") NIL NIL "7BIT" 4 0 NIL NIL NIL)("APPLICATION" "PDF" ("NAME" {25}
       
  1836 		// Kopio_paperikirjeestä.pdf) NIL NIL "BASE64" 187346 NIL ("ATTACHMENT" ("FILENAME" {25} 
       
  1837 		// Kopio_paperikirjeestä.pdf)) NIL) "MIXED" ("BOUNDARY" "----=_Part_7226_1401000605.1221158570821") NIL NIL) BODY[HEADER.FIELDS (Received Date Subject From Priority X-MSMail-Priority X-Priority Importance)] {977}
       
  1838 		
       
  1839 		TInt posCrlf =0;
       
  1840 		posCrlf = iInputBuffer.Find(KImapTxtCrlf());
       
  1841 		TInt pos1= iInputBuffer.LocateReverse('\n');
       
  1842 		TInt len=iInputBuffer.Length();
       
  1843 		
       
  1844 		if(pos1>0)  // => posCrlf>0 
       
  1845 			{	
       
  1846 			if((iInputBuffer[pos1-1] == '\r') )
       
  1847 				{
       
  1848 				 if(posCrlf != pos1-1)  // Checking if there are more than 1 CRLF(\r\n) in InputBuffer
       
  1849 				 	{
       
  1850 				 	 if((posCrlf> 0) && (iInputBuffer[posCrlf-1] == '}') )
       
  1851 				 	 	{
       
  1852 			 	 		_LIT8(KImapTxt1, "]");
       
  1853 			 	 		TInt pos2= iInputBuffer.Find(KImapTxt1());
       
  1854 						// Checking for out of boundary condition
       
  1855 			 	 		if(((pos2+2) <= (len-1)) && (iInputBuffer[pos2+2] == '{'))
       
  1856 				 	 		{
       
  1857 				 	 		TInt pos3=pos2+2;
       
  1858 				 	 		
       
  1859 				 	 		// Checking for out of boundary condition
       
  1860 				 	 		while(((pos3+1) <= (len-1)) && (iInputBuffer[pos3] != '}'))
       
  1861 				 	 			{
       
  1862 				 	 			pos3++;
       
  1863 			 	 				}
       
  1864 			 	 				
       
  1865 							if((pos3+2) <= (len-1)) // Checking for out of boundary condition
       
  1866 								{
       
  1867 								if((iInputBuffer[pos3+1] == '\r') && (iInputBuffer[pos3+2] == '\n'))
       
  1868 									{
       
  1869 									if((pos2>0) && (iInputBuffer[pos2-1] == ')'))
       
  1870 										{
       
  1871 										posCrlf = pos3+1;
       
  1872 										}
       
  1873 									}
       
  1874 								}
       
  1875 			 		 		}
       
  1876 				 	 	}
       
  1877 				 	}
       
  1878 				}
       
  1879 			}
       
  1880 
       
  1881 		if (posCrlf == KErrNotFound)
       
  1882 			{
       
  1883 			// Append all the data to the cache
       
  1884 			iInputCache->InsertL(iInputCache->Size(), iInputBuffer);
       
  1885 			iInputBuffer.Set(KNullDesC8());
       
  1886 			}
       
  1887 		else if(posCrlf >= 0)
       
  1888 			{
       
  1889 			foundLine = ETrue;
       
  1890 			
       
  1891 			// Fetch the line and consume it from iInputBuffer
       
  1892 			aDataToDeliver.Set(iInputBuffer.Left(posCrlf));
       
  1893 			if (iInputBuffer.Length() > posCrlf + KImapTxtCrlf.iTypeLength)
       
  1894 				{
       
  1895 				iInputBuffer.Set(iInputBuffer.Mid(posCrlf + KImapTxtCrlf.iTypeLength));
       
  1896 				}
       
  1897 			else
       
  1898 				{
       
  1899 				iInputBuffer.Set(KNullDesC8());
       
  1900 				}
       
  1901 			
       
  1902 			// Prepend any cached data
       
  1903 			if (inputCacheLength > 0)
       
  1904 				{
       
  1905 				iInputCache->InsertL(iInputCache->Size(), aDataToDeliver);
       
  1906 				aDataToDeliver.Set(iInputCache->Ptr(0));
       
  1907 				}
       
  1908 			}
       
  1909 		else
       
  1910 			{
       
  1911 			// Unexpected error from Find()
       
  1912 			User::Leave(posCrlf);
       
  1913 			}
       
  1914 		}
       
  1915 		
       
  1916 	return foundLine;	
       
  1917 	}
       
  1918 
       
  1919 /**
       
  1920 This method is called by the transport handler upon completion of a request to 
       
  1921 upgrade to a secure connection, using MInputStream::SecureClientReq().
       
  1922 But as CImapSession never makes such a request, the method should never be called here.
       
  1923 */
       
  1924 void CImapSession::SecureServerCnf()
       
  1925 // Implements MInputStreamObserver
       
  1926 	{
       
  1927 	// CImapSessionManager uses MInputStream::SecureClientReq() and should have its own version of this method called.
       
  1928 	__ASSERT_DEBUG(EFalse, TImapServerPanic::ImapPanic(TImapServerPanic::ESessionReceivedSecureServerCnf));
       
  1929 	}
       
  1930 	
       
  1931 void CImapSession::InputStreamCloseInd(TInt /*aError*/)
       
  1932 // Implements MInputStreamObserver
       
  1933 	{
       
  1934 	__LOG_TEXT(iLogId, "CImapSession::InputStreamCloseInd() - START");
       
  1935 	// Input stream has been closed. Transport handler is about to delete it
       
  1936 	// and the output stream too.
       
  1937 	iInputStream = NULL;
       
  1938 	iOutputStream = NULL;
       
  1939 
       
  1940 	// DoCancel() must be called after CompleteAndDestroyCommand(), to prevent attempt 
       
  1941 	// by DoCancel() to call Cancel on the command.
       
  1942 	CompleteAndDestroyCommand(KErrImapClosed, EFalse);
       
  1943 	DoCancel(); 
       
  1944 	__LOG_TEXT(iLogId, "CImapSession::InputStreamCloseInd() - END");
       
  1945 	}
       
  1946 
       
  1947 void CImapSession::SendDataCnf()
       
  1948 // Implements MOutputStreamObserver
       
  1949 	{
       
  1950 	if (iCurrentCommand != NULL)
       
  1951 		{
       
  1952 		TRAPD(err, 
       
  1953 			iCurrentCommand->SendDataCnfL();
       
  1954 			);
       
  1955 			
       
  1956 		if (err != KErrNone)
       
  1957 			{
       
  1958 			CompleteAndDestroyCommand(err, ETrue);
       
  1959 			DoCancel();
       
  1960 			
       
  1961 			SetSessionState(ESessionUnrecoverable);
       
  1962 			}		
       
  1963 		}
       
  1964 	}
       
  1965 void CImapSession::OutputStreamCloseInd(TInt /*aError*/)
       
  1966 // Implements MOutputStreamObserver
       
  1967 	{
       
  1968 	__LOG_TEXT(iLogId, "CImapSession::OutputStreamCloseInd() - START");
       
  1969 	// Output stream has been closed. Transport handler is about to delete it
       
  1970 	// and the input stream too.
       
  1971 	iInputStream = NULL;
       
  1972 	iOutputStream = NULL;
       
  1973 
       
  1974 	// DoCancel() must be called after CompleteAndDestroyCommand(), to prevent attempt 
       
  1975 	// by DoCancel() to call Cancel on the command.
       
  1976 	CompleteAndDestroyCommand(KErrImapClosed, EFalse);
       
  1977 	DoCancel();
       
  1978     __LOG_TEXT(iLogId, "CImapSession::OutputStreamCloseInd() - END");
       
  1979 	}
       
  1980 	
       
  1981 /**
       
  1982 Checks whether the input and output streams are closed.
       
  1983 If they are closed, then aStatus is completed immediately with the completion code KErrImapClosed.
       
  1984 @param aStatus The request status that will may be completed immediately if the streams are closed.
       
  1985 @return ETrue if aStatus was completed immediately, otherwise EFalse.
       
  1986 */
       
  1987 TBool CImapSession::CompleteIfStreamsClosed(TRequestStatus& aStatus)
       
  1988 	{
       
  1989 	TBool completed = EFalse;
       
  1990 	
       
  1991 	if (iInputStream == NULL || iOutputStream == NULL)
       
  1992 		{
       
  1993 		// If one stream is NULL then so should the other
       
  1994 		__ASSERT_DEBUG(iInputStream==NULL && iOutputStream==NULL, TImapServerPanic::ImapPanic(TImapServerPanic::ESessionStreamsNotBothNull));
       
  1995 		
       
  1996 		Queue(aStatus);
       
  1997 		Complete(KErrImapClosed);
       
  1998 		
       
  1999 		completed = ETrue;
       
  2000 		}
       
  2001 		
       
  2002 	return completed;
       
  2003 	}
       
  2004 
       
  2005 /**
       
  2006 Appends a formatted string to the supplied buffer.  If the buffer is too small to append 
       
  2007 the string, then the buffer is expanded and another attempt is made to perform the append operation.
       
  2008 @param aBuffer 			The buffer that will have formatted string appended to it.
       
  2009 @param aFormat 			Specifies the format of the string to be appended.
       
  2010 @param aOverflowHandler An object that helps detect when the buffer needs to be expanded.  
       
  2011 						Despite this object being a pointer, it may not be NULL, and no 
       
  2012 						transference of ownership occurs.
       
  2013 */	
       
  2014 void CImapSession::AppendAndGrowFormatL(RBuf8& aBuffer, TRefByValue<const TDesC8> aFormat, TImapOverflowDetector* aOverflowHandler, ...)
       
  2015 // static 
       
  2016 	{
       
  2017 	__ASSERT_DEBUG(aOverflowHandler != NULL, TImapServerPanic::ImapPanic(TImapServerPanic::ESessionInvalidOverFlowHandler));
       
  2018 	
       
  2019 	VA_LIST list;
       
  2020 	VA_START(list, aOverflowHandler); // Note that VA_START() does not accept reference parameters.
       
  2021 	
       
  2022 	TInt bufferLength = aBuffer.Length();
       
  2023 	
       
  2024 	while (ETrue)
       
  2025 		{
       
  2026 		aBuffer.AppendFormatList(aFormat, list, aOverflowHandler);
       
  2027 		
       
  2028 		if (aOverflowHandler->OverflowDetected())
       
  2029 			{
       
  2030 			// Invalidate any data that was added in the previous attempt to append, by reseting its length.
       
  2031 			aBuffer.SetLength(bufferLength);
       
  2032 		
       
  2033 			// Make some more space for the next attempt.	
       
  2034 		 	TInt newSize = aBuffer.MaxLength() + KSequenceSetGranularity;
       
  2035 			User::LeaveIfError(aBuffer.ReAlloc(newSize));
       
  2036 			}
       
  2037 		else
       
  2038 			{
       
  2039 			break;
       
  2040 			}
       
  2041 		}
       
  2042 	}
       
  2043 	
       
  2044 /**
       
  2045 Called by the CImapFetchBody command when a body part has been stored.
       
  2046 @param aErrorCode the result of the store operation.
       
  2047 */
       
  2048 void CImapSession::FetchBodyOperationComplete(TInt aErrorCode)
       
  2049 	{
       
  2050 	__ASSERT_DEBUG(iPendingOperation == EOpWaitForBodyOperationComplete, TImapServerPanic::ImapPanic(TImapServerPanic::ESessionInvalidPendingOp));
       
  2051 	__ASSERT_DEBUG(iSessionState == ESessionNormal, TImapServerPanic::ImapPanic(TImapServerPanic::ESessionInvalidSessionState));
       
  2052 
       
  2053 	// Check for unrecoverable errors
       
  2054 	if (aErrorCode < 0 || aErrorCode == KErrImapCorrupt)
       
  2055 		{
       
  2056 		// Finished with this command object...	
       
  2057 		CompleteAndDestroyCommand(aErrorCode, ETrue);
       
  2058 		
       
  2059 		// This unexpected error cannot be recovered from as we no longer know our state
       
  2060 		SetSessionState(ESessionUnrecoverable);
       
  2061 		}
       
  2062 	else
       
  2063 		{
       
  2064 		// Finished with this command object...	
       
  2065 		CompleteAndDestroyCommand(aErrorCode, EFalse);
       
  2066 		}	
       
  2067 	}
       
  2068 
       
  2069 /**
       
  2070 Sets the session state, and logs the transision.
       
  2071 All assignments to iSessionState should occur through this method.
       
  2072 */
       
  2073 void CImapSession::SetSessionState(TSessionState aSessionState)
       
  2074 	{
       
  2075 #ifdef __IMAP_LOGGING
       
  2076 
       
  2077 	_LIT8(KTxtSessionNormal, "ESessionNormal");
       
  2078 	_LIT8(KTxtSessionFlushing, "ESessionFlushing");
       
  2079 	_LIT8(KTxtSessionUnrecoverable, "ESessionUnrecoverable");
       
  2080 	_LIT8(KTxtSessionStateUnknown, "Unknown");
       
  2081 	
       
  2082 	TPtrC8 ptrOldState(KTxtSessionStateUnknown);
       
  2083 	TPtrC8 ptrNewState(KTxtSessionStateUnknown);
       
  2084 	
       
  2085 	switch(iSessionState)
       
  2086 		{
       
  2087 		case ESessionNormal: 		ptrOldState.Set(KTxtSessionNormal); 		break;
       
  2088 		case ESessionFlushing: 		ptrOldState.Set(KTxtSessionFlushing); 		break;
       
  2089 		case ESessionUnrecoverable:	ptrOldState.Set(KTxtSessionUnrecoverable);	break;
       
  2090 		}
       
  2091 	switch(aSessionState)
       
  2092 		{
       
  2093 		case ESessionNormal: 		ptrNewState.Set(KTxtSessionNormal); 		break;
       
  2094 		case ESessionFlushing: 		ptrNewState.Set(KTxtSessionFlushing); 		break;
       
  2095 		case ESessionUnrecoverable:	ptrNewState.Set(KTxtSessionUnrecoverable);	break;
       
  2096 		}
       
  2097 	
       
  2098 	_LIT8(KLogFormat, "CImapSession::iSessionState %S ==> %S");
       
  2099 	__LOG_FORMAT((iLogId, KLogFormat, &ptrOldState, &ptrNewState));
       
  2100 	
       
  2101 #endif //__IMAP_LOGGING
       
  2102 	
       
  2103 	iSessionState = aSessionState;	
       
  2104 	}
       
  2105 
       
  2106 /**
       
  2107 Sets the current pending operation, and logs the transision.
       
  2108 All assignments to iPendingOperation should occur through this method.
       
  2109 */
       
  2110 void CImapSession::SetPendingOperation(TPendingOperation aPendingOperation)
       
  2111 	{
       
  2112 #ifdef __IMAP_LOGGING
       
  2113 
       
  2114 	_LIT8(KTxtOpNone, "EOpNone");
       
  2115 	_LIT8(KTxtOpServerGreeting, "EOpServerGreeting");
       
  2116 	_LIT8(KTxtOpSelect, "EOpSelect");
       
  2117 	_LIT8(KTxtOpLogin, "EOpLogin");
       
  2118 	_LIT8(KTxtOpLogout, "EOpLogout");
       
  2119 	_LIT8(KTxtOpClose, "EOpClose");
       
  2120 	_LIT8(KTxtOpWaitForBodyOperationComplete, "EOpWaitForBodyOperationComplete");
       
  2121 	_LIT8(KTxtOpIdleEnter, "EOpIdleEnter");
       
  2122 	_LIT8(KTxtOpIdleWait, "EOpIdleWait");
       
  2123 	_LIT8(KTxtOpUnknown, "Unknown");
       
  2124 	_LIT8(KTxtOpIdleDone, "EOpIdleDone");
       
  2125 #if (defined SYMBIAN_EMAIL_CAPABILITY_SUPPORT)
       
  2126 	_LIT8(KTxtOpAuthenticate, "EOpAuthenticate");
       
  2127 #endif
       
  2128 	TPtrC8 ptrOldOperation(KTxtOpUnknown);
       
  2129 	TPtrC8 ptrNewOperation(KTxtOpUnknown);
       
  2130 	
       
  2131 	switch(iPendingOperation)
       
  2132 		{
       
  2133 		case EOpNone:				ptrOldOperation.Set(KTxtOpNone);			break;
       
  2134 		case EOpServerGreeting:		ptrOldOperation.Set(KTxtOpServerGreeting);	break;
       
  2135 		case EOpSelect:				ptrOldOperation.Set(KTxtOpSelect);			break;
       
  2136 		case EOpLogin:				ptrOldOperation.Set(KTxtOpLogin);			break;
       
  2137 		case EOpLogout:				ptrOldOperation.Set(KTxtOpLogout);			break;
       
  2138 		case EOpClose:				ptrOldOperation.Set(KTxtOpClose);			break;
       
  2139 		case EOpWaitForBodyOperationComplete:
       
  2140 									ptrOldOperation.Set(KTxtOpWaitForBodyOperationComplete);	break;
       
  2141 		case EOpIdleEnter:			ptrOldOperation.Set(KTxtOpIdleEnter);		break;
       
  2142 		case EOpIdleWait:			ptrOldOperation.Set(KTxtOpIdleWait);		break;
       
  2143 		case EOpIdleDone:			ptrOldOperation.Set(KTxtOpIdleDone);		break;
       
  2144 #if (defined SYMBIAN_EMAIL_CAPABILITY_SUPPORT)
       
  2145 		case EOpAuthenticate:		ptrOldOperation.Set(KTxtOpAuthenticate);	break;
       
  2146 #endif
       
  2147 		}
       
  2148 		
       
  2149 	switch(aPendingOperation)
       
  2150 		{
       
  2151 		case EOpNone:				ptrNewOperation.Set(KTxtOpNone);			break;
       
  2152 		case EOpServerGreeting:		ptrNewOperation.Set(KTxtOpServerGreeting);	break;
       
  2153 		case EOpSelect:				ptrNewOperation.Set(KTxtOpSelect);			break;
       
  2154 		case EOpLogin:				ptrNewOperation.Set(KTxtOpLogin);			break;
       
  2155 		case EOpLogout:				ptrNewOperation.Set(KTxtOpLogout);			break;
       
  2156 		case EOpClose:				ptrNewOperation.Set(KTxtOpClose);			break;
       
  2157 		case EOpWaitForBodyOperationComplete:
       
  2158 									ptrNewOperation.Set(KTxtOpWaitForBodyOperationComplete);	break;
       
  2159 		case EOpIdleEnter:			ptrNewOperation.Set(KTxtOpIdleEnter);		break;
       
  2160 		case EOpIdleWait:			ptrNewOperation.Set(KTxtOpIdleWait);		break;
       
  2161 		case EOpIdleDone:			ptrNewOperation.Set(KTxtOpIdleDone);		break;
       
  2162 #if (defined SYMBIAN_EMAIL_CAPABILITY_SUPPORT)
       
  2163 		case EOpAuthenticate:		ptrNewOperation.Set(KTxtOpAuthenticate);	break;
       
  2164 #endif
       
  2165 		}
       
  2166 	
       
  2167 	_LIT8(KLogFormat, "CImapSession::iPendingOperation %S ==> %S");
       
  2168 	__LOG_FORMAT((iLogId, KLogFormat, &ptrOldOperation, &ptrNewOperation));
       
  2169 	
       
  2170 #endif //__IMAP_LOGGING
       
  2171 	
       
  2172 	iPendingOperation = aPendingOperation;	
       
  2173 	}
       
  2174 
       
  2175 /**
       
  2176 Sets the state we believe the IMAP Server is in, and logs the transision.
       
  2177 All assignments to iServerState should occur through this method.
       
  2178 */
       
  2179 void CImapSession::SetServerState(TImapServerState aServerState)
       
  2180 	{
       
  2181 	
       
  2182 #ifdef __IMAP_LOGGING
       
  2183 
       
  2184 	_LIT8(KTxtServerStateNone, "EServerStateNone");
       
  2185 	_LIT8(KTxtServerStateNotAuthenticated, "EServerStateNotAuthenticated");
       
  2186 	_LIT8(KTxtServerStateAuthenticated, "EServerStateAuthenticated");
       
  2187 	_LIT8(KTxtServerStateSelected, "EServerStateSelected");
       
  2188 	_LIT8(KTxtServerStateUnknown, "Unknown");
       
  2189 
       
  2190 	TPtrC8 ptrOldState(KTxtServerStateUnknown);
       
  2191 	TPtrC8 ptrNewState(KTxtServerStateUnknown);
       
  2192 	
       
  2193 	switch(iServerState)
       
  2194 		{
       
  2195 		case EServerStateNone: 				ptrOldState.Set(KTxtServerStateNone); 				break;
       
  2196 		case EServerStateNotAuthenticated: 	ptrOldState.Set(KTxtServerStateNotAuthenticated); 	break;
       
  2197 		case EServerStateAuthenticated: 	ptrOldState.Set(KTxtServerStateAuthenticated); 		break;
       
  2198 		case EServerStateSelected: 			ptrOldState.Set(KTxtServerStateSelected); 			break;
       
  2199 		}
       
  2200 		
       
  2201 	switch(aServerState)
       
  2202 		{
       
  2203 		case EServerStateNone: 				ptrNewState.Set(KTxtServerStateNone); 				break;
       
  2204 		case EServerStateNotAuthenticated: 	ptrNewState.Set(KTxtServerStateNotAuthenticated); 	break;
       
  2205 		case EServerStateAuthenticated: 	ptrNewState.Set(KTxtServerStateAuthenticated); 		break;
       
  2206 		case EServerStateSelected: 			ptrNewState.Set(KTxtServerStateSelected); 			break;
       
  2207 		}
       
  2208 	
       
  2209 	_LIT8(KLogFormat, "CImapSession::iServerState %S ==> %S");
       
  2210 	__LOG_FORMAT((iLogId, KLogFormat, &ptrOldState, &ptrNewState));
       
  2211 	
       
  2212 #endif //__IMAP_LOGGING
       
  2213 	
       
  2214 	iServerState = aServerState;	
       
  2215 	}
       
  2216 
       
  2217 /**
       
  2218 Returns the logger file identifier
       
  2219 @return Logger file identifier
       
  2220 */
       
  2221 EXPORT_C TInt CImapSession::LogId() const
       
  2222 	{
       
  2223 	return iLogId;
       
  2224 	}
       
  2225 
       
  2226 TImapOverflowDetector::TImapOverflowDetector()
       
  2227 	: iOverflowDetected(EFalse)
       
  2228 	{}
       
  2229 
       
  2230 /**
       
  2231 Returns whether Overflow() has been called.
       
  2232 This method resets the object's overflow flag, so that subsequent calls to this method
       
  2233 will return EFalse until the next time Overflow is called.
       
  2234 @return whether Overflow() has been called.
       
  2235 */
       
  2236 TBool TImapOverflowDetector::OverflowDetected()
       
  2237 	{
       
  2238 	if (iOverflowDetected)
       
  2239 		{
       
  2240 		iOverflowDetected = EFalse;
       
  2241 		return ETrue;
       
  2242 		}
       
  2243 	return EFalse;
       
  2244 	}
       
  2245 
       
  2246 /**
       
  2247 Implements TDes8Overflow by recording that an overflow has been detected.
       
  2248 */
       
  2249 void TImapOverflowDetector::Overflow(TDes8& /*aDes*/)
       
  2250 	{
       
  2251 	iOverflowDetected = ETrue;
       
  2252 	}
       
  2253 
       
  2254 
       
  2255 /**
       
  2256 Issue the IMAP AuthenticateL command.
       
  2257 @param aStatus Signals completion of the request
       
  2258 @param  iCurrentAuthProfile  indicates which authenticate(cram-md5,plain,login)method to use
       
  2259 @param aStatus 		Signals completion of the request
       
  2260 */
       
  2261 #if (defined SYMBIAN_EMAIL_CAPABILITY_SUPPORT)
       
  2262 EXPORT_C void CImapSession::AuthenticateL(TRequestStatus& aStatus,CImapAuthMechanismHelper::TImapAuthProfileFlag iCurrentAuthProfile)
       
  2263 	{
       
  2264 	
       
  2265 	__LOG_TEXT(iLogId, "CImapSession::AuthenticateL()");
       
  2266 	__ASSERT_DEBUG(iServerState == EServerStateNotAuthenticated, TImapServerPanic::ImapPanic(TImapServerPanic::ELoginWhenServerStateUnknown));
       
  2267 	__ASSERT_DEBUG(iPendingOperation == EOpNone, TImapServerPanic::ImapPanic(TImapServerPanic::ELoginWhenInvalidOperationPending));
       
  2268 	if (CompleteIfStreamsClosed(aStatus)) 
       
  2269 		{
       
  2270 		return;
       
  2271 		}
       
  2272 	
       
  2273 	SetPendingOperation(EOpAuthenticate); // << Server state becomes Authenticated
       
  2274 	switch(iCurrentAuthProfile)
       
  2275 		{
       
  2276 		case CImapAuthMechanismHelper::EPlain:
       
  2277 			{
       
  2278 			StartCommandL(aStatus, CImapAuthPlainMechanismHelper::NewL(iImapSettings, iSelectedFolderInfo, iLogId));
       
  2279 			}
       
  2280 			break;
       
  2281 		case CImapAuthMechanismHelper::ELogin:
       
  2282 			{
       
  2283 			StartCommandL(aStatus, CImapAuthLoginMechanismHelper::NewL(iImapSettings,iSelectedFolderInfo,iLogId));
       
  2284 			}
       
  2285 			break;
       
  2286 		case CImapAuthMechanismHelper::ECramMD5:
       
  2287 			{
       
  2288 			StartCommandL(aStatus, CImapAuthCramMd5MechanismHelper::NewL(iImapSettings,iSelectedFolderInfo,iLogId));
       
  2289 			}
       
  2290 			break;
       
  2291 		default:
       
  2292 			{
       
  2293 			User::Leave(KErrNotSupported);
       
  2294 			break;	
       
  2295 			}	
       
  2296 	    }
       
  2297 	}
       
  2298 #endif