email/imap4mtm/imapsession/src/cimapappend.cpp
changeset 0 72b543305e3a
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 #include "cimapappend.h"
       
    17 
       
    18 #include <imcvsend.h>
       
    19 
       
    20 #include "cimapsessionconsts.h"
       
    21 #include "moutputstream.h"
       
    22 #include "cimaplogger.h"
       
    23 #include "cimapsession.h"
       
    24 
       
    25 _LIT8(KTxtAppendFormat, "%d APPEND %S {%d}\r\n");
       
    26 
       
    27 // TCallBack return values
       
    28 static const TInt KDontCallAgain = 0;
       
    29 static const TInt KCallAgain = 1;
       
    30 
       
    31 /**
       
    32 The factory constructor. Part of two phased construction
       
    33 */
       
    34 CImapAppend* CImapAppend::NewL(CImapFolderInfo* aSelectedFolderData, TInt aLogId, CImSendMessage& aSource, const TDesC& aDestinationMailboxName, CImapSession& aParentSession)
       
    35 // static method
       
    36 	{
       
    37 	CImapAppend* self = new(ELeave) CImapAppend(aSelectedFolderData, aLogId, aSource, aParentSession);
       
    38 	CleanupStack::PushL(self);
       
    39 	self->ConstructL(aDestinationMailboxName);
       
    40 	CleanupStack::Pop(self);
       
    41 	return self;
       
    42 	}
       
    43 
       
    44 void CImapAppend::ConstructL( const TDesC& aDestinationMailboxName)
       
    45 	{
       
    46 	iLineBufferForSend = HBufC8::NewL(KImMailMaxBufferSize);
       
    47 	iDestinationMailboxName = EncodeMailboxNameForSendL(aDestinationMailboxName);
       
    48 	iBackgroundCalculationStepper = CIdle::NewL(CActive::EPriorityIdle);
       
    49 	}
       
    50 
       
    51 /**
       
    52 Constructor.
       
    53 */
       
    54 CImapAppend::CImapAppend(CImapFolderInfo* aSelectedFolderData, TInt aLogId, CImSendMessage& aSource, CImapSession& aParentSession)
       
    55 	: CImapCommandEx(aSelectedFolderData, aLogId)
       
    56 	, iSource(aSource)
       
    57 	, iParentSession(aParentSession)
       
    58 	, iAppendCommandSendState(EAppendWaitingToStart)
       
    59 	{	
       
    60 	}
       
    61 
       
    62 /**
       
    63 Destructor.
       
    64 */
       
    65 CImapAppend::~CImapAppend()
       
    66 	{
       
    67 	delete iBackgroundCalculationStepper;
       
    68 	delete iLineBufferForSend;
       
    69 	delete iDestinationMailboxName;
       
    70 	}
       
    71 	
       
    72 /**
       
    73 Formats and sends the IMAP APPEND command.
       
    74 @param aTagId Command sequence id which will be sent along with the IMAP command.
       
    75 @param aStream A wrapper for the outbound stream of a connected socket, using which
       
    76 the command will be send to the server
       
    77 */	
       
    78 void CImapAppend::SendMessageL(TInt aTagId, MOutputStream& aStream)
       
    79 	{
       
    80 	// From RFC3501
       
    81 	//	append = "APPEND" SP mailbox [SP flag-list] [SP date-time] SP literal
       
    82 	//	
       
    83 	// we have chosen not to supply the optional flag-list or date-time
       
    84 
       
    85 	__ASSERT_DEBUG(iAppendCommandSendState==EAppendWaitingToStart, TImapServerPanic::ImapPanic(TImapServerPanic::EAppendInvalidState));
       
    86 
       
    87 	iTagId = aTagId;
       
    88 	iStream = &aStream;
       
    89 				
       
    90 	// Calculate the size of the message
       
    91 	__LOG_TEXT(iLogId, "CImapAppend::SendMessageL() - Start calculating message size");
       
    92 	iAppendCommandSendState = EAppendCalculatingSize;
       
    93 	iBackgroundCalculationStepper->Start(TCallBack(MessageSizeCalculationStep, this));
       
    94 	}
       
    95 
       
    96 /**
       
    97 Static callback method that was requested through iBackgroundCalculationStepper.
       
    98 It calls the equivalent MessageSizeCalculationStep on the supplied CImapAppend object
       
    99 which performs a single step of the message size calculation.
       
   100 @param aSelf The CImapAppend object that requested the asynchronous callback.
       
   101 @return Wheher this method needs to be called again, to calculate the next step.
       
   102 */
       
   103 TInt CImapAppend::MessageSizeCalculationStep(TAny* aSelf)
       
   104 // static method
       
   105 	{
       
   106 	CImapAppend* self = reinterpret_cast<CImapAppend*>(aSelf);
       
   107 	TInt callAgain = KDontCallAgain;
       
   108 	TRAPD(err, callAgain = self->MessageSizeCalculationStepL());
       
   109 	
       
   110 	if (err)
       
   111 		{
       
   112 		self->iParentSession.AsyncSendFailed(err);
       
   113 		}
       
   114 	
       
   115 	return callAgain;
       
   116 	}
       
   117 	
       
   118 /**
       
   119 Performs a single step of the message size calculation.
       
   120 @return whether this method needs to be called again, to calculate the next step.
       
   121 */
       
   122 TInt CImapAppend::MessageSizeCalculationStepL()
       
   123 	{
       
   124 	__ASSERT_DEBUG(iAppendCommandSendState==EAppendCalculatingSize, TImapServerPanic::ImapPanic(TImapServerPanic::EAppendInvalidState));
       
   125 	
       
   126 	TInt callAgain = KDontCallAgain;
       
   127 	
       
   128 	TPtr8 nextLine = iLineBufferForSend->Des();	
       
   129 	TInt status = iSource.NextLineL(nextLine, iPadCount);
       
   130 	
       
   131 	iTotalMessageSize += iLineBufferForSend->Length();
       
   132 
       
   133 #ifdef __IMAP_LOGGING
       
   134 	{
       
   135 		// Log the first few bytes only
       
   136 		TPtrC8 truncatedData = iLineBufferForSend->Left(60);
       
   137 		// only log up to the first \r\n
       
   138 		TInt pos = truncatedData.Find(KImapTxtCrlf);
       
   139 		if (pos >= 0)
       
   140 			{
       
   141 			truncatedData.Set(truncatedData.Left(pos));
       
   142 			}
       
   143 		else 
       
   144 			{
       
   145 			// \r\n may have been split by the intial truncation,
       
   146 			// so check for the \r
       
   147 			pos = truncatedData.Locate('\r');
       
   148 			if (pos >= 0)
       
   149 				{
       
   150 				truncatedData.Set(truncatedData.Left(pos));
       
   151 				}
       
   152 			}
       
   153 
       
   154 		__LOG_FORMAT((iLogId, "CImapAppend::MessageSizeCalculationStepL() - %3d ==> %3d [%S]", iLineBufferForSend->Length(), iTotalMessageSize, &truncatedData));
       
   155 	}
       
   156 #endif //__IMAP_LOGGING
       
   157 	
       
   158 	if (status == KImCvFinished)
       
   159 		{
       
   160 		iSource.Reset();
       
   161 		iPadCount = 0;
       
   162 		nextLine.Zero();
       
   163 		
       
   164 		SendAppendCommandWithSizeL();
       
   165 		}
       
   166 	else
       
   167 		{
       
   168 		callAgain = KCallAgain;
       
   169 		}
       
   170 		
       
   171 	return callAgain;
       
   172 	}
       
   173 	
       
   174 /**
       
   175 Sends the IMAP APPEND command.
       
   176 This method is called after the size of the message has been calculated.
       
   177 */
       
   178 void CImapAppend::SendAppendCommandWithSizeL()
       
   179 	{
       
   180 	TInt bufferLength = KTxtAppendFormat().Length() + TagLength(iTagId) + iDestinationMailboxName->Length() + TagLength(iTotalMessageSize);
       
   181 	
       
   182 	delete iOutputBuffer;
       
   183 	iOutputBuffer=NULL;
       
   184 	
       
   185 	iOutputBuffer = HBufC8::NewL(bufferLength);
       
   186 	iOutputBuffer->Des().Format(KTxtAppendFormat, iTagId, iDestinationMailboxName, iTotalMessageSize);
       
   187 	
       
   188 	// Send the data on the output stream
       
   189 	iAppendCommandSendState = EAppendWaitingForContinuationResponse;
       
   190 	iStream->SendDataReq(*iOutputBuffer);
       
   191 	}
       
   192 
       
   193 /**
       
   194 Sends the first line of the message upon reciept of a continuation response from server.
       
   195 The next line will be sent SendDataCnfL() is called, indicating that the first line has been succesfully sent.
       
   196 */
       
   197 void CImapAppend::ParseContinuationResponseL() 
       
   198 	{
       
   199 	if (iAppendCommandSendState != EAppendWaitingForContinuationResponse)
       
   200 		{
       
   201 		CorruptDataL();
       
   202 		}
       
   203 		
       
   204 	iAppendCommandSendState = EAppendSendingMessageData;		
       
   205 	SendNextMessageLineL();
       
   206 	}
       
   207 
       
   208 /**
       
   209 This is called when the previous line has been succesfully sent.
       
   210 If there are more lines of the message to send, then the next line is sent now.
       
   211 @return ECompleteUntagged
       
   212 */
       
   213 void CImapAppend::SendDataCnfL()
       
   214 	{
       
   215 	if (iAppendCommandSendState == EAppendSendingMessageData)
       
   216 		{
       
   217 		SendNextMessageLineL();
       
   218 		}
       
   219 	else if (iAppendCommandSendState == EAppendWaitingForContinuationResponse)
       
   220 		{
       
   221 		__LOG_TEXT(iLogId, "CImapAppend::SendDataCnfL() - Initial Command Sent");
       
   222 		}
       
   223 	else
       
   224 		{
       
   225 		__ASSERT_DEBUG(iAppendCommandSendState == EAppendSendingLastMessageData, TImapServerPanic::ImapPanic(TImapServerPanic::EAppendInvalidState));
       
   226 		__LOG_TEXT(iLogId, "CImapAppend::SendDataCnfL() - Message Data Sent");
       
   227 		
       
   228 		iAppendCommandSendState = EAppendFinishedSending;
       
   229 		}
       
   230 	}
       
   231 	
       
   232 /**
       
   233 Sends the first or next line of the message to the server.
       
   234 SendDataCnfL() will be called when the line has been succefully sent.
       
   235 */
       
   236 void CImapAppend::SendNextMessageLineL()
       
   237 	{	
       
   238 	__ASSERT_DEBUG(iAppendCommandSendState == EAppendSendingMessageData, TImapServerPanic::ImapPanic(TImapServerPanic::EAppendInvalidState));
       
   239 	
       
   240 	// Receive the next line to be sent, by passing in a modifyable descriptor.
       
   241 	// Note that iPadCount receives the padding count, which will be passed into the next call to NextLineL()
       
   242 	TPtr8 nextLine = iLineBufferForSend->Des();
       
   243 	TInt sendStatus = iSource.NextLineL(nextLine, iPadCount);
       
   244 	
       
   245 	__LOG_TEXT(iLogId, "CImapAppend::SendNextMessageLineL()");
       
   246 	
       
   247 	if (sendStatus == KImCvFinished)
       
   248 		{
       
   249 		// As well as sending the last part of the literal block,
       
   250 		// we need to send a CRLF to terminate the APPEND command.
       
   251 		// The CRLF is not part of the message data.
       
   252 		
       
   253 		// Is there enough room to append the CRLF?		
       
   254 		TInt lengthWithCrlf = nextLine.Length() + KImapTxtCrlf().Length();		
       
   255 		if (nextLine.MaxLength() < lengthWithCrlf)
       
   256 			{
       
   257 			// Make enough space for the CRLF
       
   258 			iLineBufferForSend = iLineBufferForSend->ReAllocL(lengthWithCrlf);
       
   259 			nextLine.Set(iLineBufferForSend->Des());
       
   260 			}
       
   261 		
       
   262 		__LOG_TEXT(iLogId, "CImapAppend::SendNextMessageLineL() - appending command terminator");
       
   263 		nextLine.Append(KImapTxtCrlf());
       
   264 		
       
   265 		// Indicate that this is the final line to be sent
       
   266 		iAppendCommandSendState = EAppendSendingLastMessageData;
       
   267 		}
       
   268 
       
   269 	// Send the data, using a non-modifyable descriptor.
       
   270 	iStream->SendDataReq(*iLineBufferForSend);
       
   271 	}
       
   272 
       
   273 /**
       
   274 Overrides the default implementation of Cancel.
       
   275 If the command is still calculating the message size, then the calculation is cancelled
       
   276 */
       
   277 void CImapAppend::Cancel()
       
   278 	{
       
   279 	__LOG_TEXT(iLogId, "CImapAppend::Cancel()"); // Overrides CImapCommand::Cancel()
       
   280 	
       
   281 	iBackgroundCalculationStepper->Cancel();
       
   282 	
       
   283 	EnterFlushingState();
       
   284 	}
       
   285 
       
   286 /**
       
   287 Overrides the default implementation of CanCompleteFlushNow.
       
   288 If the command has not yet sent any data, then it can be completed now
       
   289 as it is not yet expecting to receive any response data.
       
   290 @return EFalse if data has been sent.
       
   291 		ETrue if still at the message size calculation stage
       
   292 */
       
   293 TBool CImapAppend::CanCompleteFlushNow() const 
       
   294 	{
       
   295 	// Any command that has completed should have been destroyed before this
       
   296 	// method is called.
       
   297 	__ASSERT_DEBUG(ParseState() != ECommandComplete, TImapServerPanic::ImapPanic(TImapServerPanic::ECommandInvalidParseState1));
       
   298 	__ASSERT_DEBUG(Flushing(), TImapServerPanic::ImapPanic(TImapServerPanic::ECommandNotFlushing));
       
   299 
       
   300 	return (iAppendCommandSendState <= EAppendCalculatingSize) ? ETrue: EFalse;
       
   301 	}