--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/email/imap4mtm/imapmailstore/src/cstoreutilities.cpp Fri Jun 04 10:25:39 2010 +0100
@@ -0,0 +1,382 @@
+// Copyright (c) 2006-2009 Nokia Corporation and/or its subsidiary(-ies).
+// All rights reserved.
+// This component and the accompanying materials are made available
+// under the terms of "Eclipse Public License v1.0"
+// which accompanies this distribution, and is available
+// at the URL "http://www.eclipse.org/legal/epl-v10.html".
+//
+// Initial Contributors:
+// Nokia Corporation - initial contribution.
+//
+// Contributors:
+//
+// Description:
+//
+
+#include "cstoreutilities.h"
+#include <miuthdr.h>
+#include <barsread.h>
+
+// The maximum number of octets to be uuencoded on each line is 45
+const TInt KUuDecodedLineLength = 45;
+// Initial size of buffer in which the "Real name <user@host>" strings
+// are built before they're put into the CImHeader and the size by
+// which to increment the buffer when necessary
+const TInt KImapAddressSizeInc=256;
+const TInt KKiloByteSize = 1024;
+const TInt KBufferExtension = 4;
+/**
+Constructor.
+*/
+CStoreUtilities::CStoreUtilities(TImEncodingType aEncodingType,TUint aCharsetId,RFs& aFs)
+ :iEncodingType(aEncodingType),iCharsetId(aCharsetId),iFs(aFs)
+ {
+ }
+
+/**
+Factory constructors.
+Ownership aHeader is taken.
+*/
+CStoreUtilities* CStoreUtilities::NewL(TImEncodingType aEncodingType,TUint aCharsetId,RFs& aFs)
+ {
+ CStoreUtilities* self=new(ELeave) CStoreUtilities(aEncodingType,aCharsetId,aFs);
+ CleanupStack::PushL(self);
+ self->ConstructL();
+ CleanupStack::Pop();
+ return self;
+ }
+
+void CStoreUtilities::ConstructL()
+ {
+ User::LeaveIfError(iFs.Connect());
+ // Create converter objects
+ iCharacterConverter=CCnvCharacterSetConverter::NewL();
+ iCharConv=CImConvertCharconv::NewL(*iCharacterConverter, iFs);
+ }
+
+/**
+Destructor.
+*/
+CStoreUtilities::~CStoreUtilities()
+ {
+ delete iCharConv;
+ delete iCharacterConverter;
+ delete iFooterString;
+ delete iPartialLine;
+ }
+
+/**
+Checks if the descriptor contains the UUE begin header
+Extracts the file name if it is
+*/
+TBool CStoreUtilities::CheckUUEStartL(const TDesC8& aSourceLine)
+ {
+
+ TInt sourceLength = aSourceLine.Length();
+ if(sourceLength < KImcvUueStart().Length()+3) // can't be "begin ###", it's not long enough; 3=length of ###
+ return EFalse;
+
+ if(!aSourceLine.Left(KImcvUueStart().Length()).CompareF(KImcvUueStart)) // start of line might be UUE boundary
+ {
+ // we also need to check that the next three chars are numbers - Unix file access code
+ const TUint8* sourceLinePtr = aSourceLine.Ptr();
+ TInt length=KImcvUueStart().Length();// this defines length as 6 ie. "b e g i n "
+ if( TChar(sourceLinePtr[length]).IsDigit() &&
+ TChar(sourceLinePtr[length+1]).IsDigit() &&
+ TChar(sourceLinePtr[length+2]).IsDigit() )
+ {
+ // Found 'begin ###' at the start of a line - assume this is a UUencode header
+ // The attachment name in this header is ignored. We use the value from the MIME header
+ return ETrue;
+ }
+ }
+
+ return EFalse;
+ }
+
+/**
+Appends data to partial line object extening the destination buffer as appropirate
+@param aBufferPtr the destination bufer
+@param aText the data to be appended
+*/
+
+void CStoreUtilities::AppendExtendL(HBufC8** aBufferPtr, const TDesC8& aText)
+ {
+ HBufC8 *buffer = *aBufferPtr;
+ TInt32 space = buffer->Des().MaxLength() - (buffer->Des().Length() + aText.Length());
+ if (space < 0)
+ {
+ TInt32 inc = (-space) + KImapAddressSizeInc - ((-space) % KImapAddressSizeInc);
+ TInt32 newSize = buffer->Des().MaxLength() + inc;
+ HBufC8 *newBuf = buffer->ReAllocL(newSize);
+ *aBufferPtr = buffer = newBuf;
+ }
+ buffer->Des().Append(aText);
+ }
+
+
+void CStoreUtilities::AttachFooterInfoL(TInt32 aBodyPartRemainingSize,CImapSettings& aImapSettings,HBufC8*& aDecodedData)
+ {
+ const HBufC8* buf= aImapSettings.DefaultPartialMessageFooter();
+
+ _LIT(KIntegerDirective,"%d");
+ const TInt KNoOfDigitsInMailSize = 10; // maximum length for no of digits for remaining body parts size
+ TResourceReader reader;
+ reader.SetBuffer(buf);
+ // Check if %d is not found in the resource string (To avoid problems due to localisation)
+ if(buf->Find((TDesC8&)KIntegerDirective) == KErrNotFound)
+ {
+ iFooterString = (reader.ReadTPtrC()).AllocL();
+ }
+ else
+ {
+ HBufC* resourceBuf = (reader.ReadTPtrC()).AllocL();
+ CleanupStack::PushL(resourceBuf);
+ iFooterString = HBufC::NewL(resourceBuf->Length()+KNoOfDigitsInMailSize);
+ iFooterString->Des().Format(*resourceBuf,(aBodyPartRemainingSize / KKiloByteSize));
+ CleanupStack::PopAndDestroy(resourceBuf);
+ }
+ //caller will have left aDecodedData on the cleanupstack
+ CleanupStack::Pop(aDecodedData);
+ TInt newSize = aDecodedData->Size() + iFooterString->Size();
+ aDecodedData = aDecodedData->ReAlloc(newSize);
+ CleanupStack::PushL(aDecodedData);
+ aDecodedData->Des().Append(*iFooterString);
+ delete iFooterString;
+ iFooterString = NULL;
+
+ }
+
+
+// convert text from its charset and write to richtext store. aText
+// can span multiple and partial lines
+void CStoreUtilities::WriteToBodyL(const TDesC8& aText,CRichText* aMessageBody)
+ {
+ TInt pos = aMessageBody->DocumentLength();
+
+ // Add bits of body text, converting along the way, till no characters left
+ // .. to convert.
+
+ // Convert text before writing to body.
+ TInt rem = 0;
+
+ // there will be a max of one output char per input byte
+ HBufC16* text16=HBufC16::NewLC(aText.Length());
+ TPtr16 ptr16=text16->Des();
+
+ TBool preparedToConvert = iCharConv->PrepareToConvertToFromOurCharsetL(iCharsetId);
+
+ if (!preparedToConvert)
+ {
+ ptr16.Copy(aText);
+ aMessageBody->InsertL(pos, ptr16);
+ }
+ else
+ {
+ TInt unconvertedChars, firstPos; // not used
+ rem = iCharConv->ConvertToOurCharsetL(aText, ptr16,
+ unconvertedChars, firstPos);
+ if (rem < 0) // error
+ {
+ // Copy unconverted characters.
+ ptr16.Copy(aText);
+ aMessageBody->InsertL(pos, ptr16);
+ }
+ else if (rem && rem < iLeftOver.MaxLength())
+ {
+ iLeftOver.Copy(aText.Right(rem));
+ }
+
+ // convert CRLF to ELineBreak
+ TInt start = 0;
+ TInt length = ptr16.Length();
+
+ if (length>0)
+ {
+ TInt i;
+ for (i=1; i<length; i++)
+ {
+ if (ptr16[i-1] == KImcvCR && ptr16[i] == KImcvLF)
+ {
+ ptr16[i-1] = CEditableText::ELineBreak;
+
+ // write this line to body
+ TPtrC ptr = ptr16.Mid(start, i-start);
+ aMessageBody->InsertL(pos, ptr);
+ pos += ptr.Length();
+ start = i+1;
+ }
+ }
+
+ if (start != i)
+ {
+ TPtrC ptr = ptr16.Mid(start, i-start);
+ aMessageBody->InsertL(pos, ptr);
+ }
+ }
+ }
+
+ CleanupStack::PopAndDestroy(text16);
+ }
+
+// Decode and store received data
+HBufC8* CStoreUtilities::DecodeL(const TPtrC8& aBodyData, const TBool aEndOfStream)
+ {
+ // Somewhere to store decoded data, at least as long as source (plus anything we have left
+ // in the partial line buffer which may now get consumed)
+ TInt outputbuffersize=aBodyData.Length()+KBufferExtension;
+ if (iPartialLine)
+ outputbuffersize+=iPartialLine->Des().Length();
+
+ HBufC8* decoded=HBufC8::NewL(outputbuffersize);
+ TPtr8 decoded_ptr=decoded->Des();
+
+ // Which decoder are we using?
+ switch(iEncodingType)
+ {
+ case EEncodingTypeNone:
+ case EEncodingType7Bit:
+ case EEncodingType8Bit:
+ case EEncodingTypeBinary:
+ case EEncodingTypeUnknown:
+ // Nothing to do, just copy data
+ decoded->Des().Append(aBodyData);
+ break;
+
+ case EEncodingTypeBASE64:
+ // Decode Base64 data: just filter it through decoder, it
+ // ignores line breaks anyway.
+ iB64Decoder.Decode(aBodyData,decoded_ptr);
+ break;
+
+ case EEncodingTypeUU:
+ {
+ TPtrC8 bodydata=aBodyData;
+
+ // Got a partial buffer?
+ if (!iPartialLine)
+ {
+ // Allocate buffer
+ iPartialLine=HBufC8::NewL(KUuDecodedLineLength);
+ iUUDecoding = EFalse;
+ }
+
+ // Decode UUEncoded data: line by line
+ TBool decodeEnded = EFalse;
+ TInt position=0;
+ while ( bodydata.Length() && !decodeEnded )
+ {
+ // Find() returns the start of "\r\n". The decoding algorithm
+ // requires that the encoded line contains the "\r\n".
+ TInt lineEnd = bodydata.Find( _L8("\r\n") );
+ if (lineEnd != KErrNotFound)
+ {
+ lineEnd = lineEnd + 2;
+ AppendExtendL( &iPartialLine, bodydata.Left( lineEnd ));
+
+ bodydata.Set( bodydata.Mid( lineEnd ) );
+
+ // Check for a well-formated begin-tag
+ if ( CheckUUEStartL( iPartialLine->Des() ) )
+ {
+ iUUDecoding = ETrue;
+ }
+ else if ( iPartialLine->Compare( KImcvUueEnd ) != 0 && iUUDecoding )
+ {
+ // Every malformatted string is decoded as an empty string
+ // with length 0. Appending such a string is harmless.
+ TPtr8 destination((unsigned char*)decoded_ptr.Ptr()+position,0,outputbuffersize-position);
+ iUUDecoder.Decode(*iPartialLine,destination);
+ position+=destination.Length();
+ }
+ else if ( iUUDecoding )
+ {
+ decodeEnded = ETrue;
+ iUUDecoding = EFalse;
+ }
+
+ iPartialLine->Des().Zero();
+ }
+ else
+ {
+ AppendExtendL( &iPartialLine, bodydata);
+
+ // advance to end of bodydata
+ bodydata.Set(bodydata.Ptr()+bodydata.Length(), 0);
+ }
+ }
+ decoded->Des().SetLength(position);
+ break;
+ }
+
+ case EEncodingTypeQP:
+ {
+ TPtrC8 bodydata=aBodyData;
+
+ // Got a partial buffer?
+ if (!iPartialLine)
+ {
+ // Allocate buffer
+ iPartialLine=HBufC8::NewL(256);
+ }
+
+ // Build buffer to decode: basically, QP decoder wants CRLF terminated
+ // lines, so we build them in the iPartialLine buffer. There may be
+ // stuff already there from previous data packet - so we just append.
+ TInt position=0;
+ while(bodydata.Length())
+ {
+ // Find a line break
+ TInt lineend=bodydata.Find(_L8("\r\n"));
+
+ // No break?
+ if (lineend==KErrNotFound && !aEndOfStream)
+ {
+ // Stick it all in the partialline buffer, we should get a CRLF
+ // soon...
+ AppendExtendL( &iPartialLine,bodydata);
+ break;
+ }
+ else
+ {
+ if (lineend==KErrNotFound)
+ {
+ // Append whole thing left to buffer
+ AppendExtendL( &iPartialLine,bodydata);
+
+ // advance to end of bodydata
+ bodydata.Set(bodydata.Ptr()+bodydata.Length(), 0);
+ }
+ else
+ {
+ // Append to buffer up to that point (including the \r\n)
+ AppendExtendL( &iPartialLine,bodydata.Left(lineend+2));
+
+ // Remove from the buffer we're working on (including the \r\n)
+ bodydata.Set(bodydata.Ptr()+lineend+2,bodydata.Length()-lineend-2);
+ }
+
+ // Decode & skip on in buffer
+ TPtr8 destination((unsigned char*)decoded_ptr.Ptr()+position,0,outputbuffersize-position);
+ iQPDecoder.Decode(*iPartialLine,destination);
+ position+=destination.Length();
+ iPartialLine->Des().Zero();
+ }
+ }
+
+ // Update decoded
+ decoded->Des().SetLength(position);
+ break;
+ }
+ }
+
+ // put back any partially converted data
+ if (iLeftOver.Length())
+ {
+ decoded->Des().Insert(0, iLeftOver);
+ iLeftOver.SetLength(0);
+ }
+
+ return decoded;
+ }
+