diff -r 6a20128ce557 -r ebfee66fde93 email/imap4mtm/imapmailstore/src/cstoreutilities.cpp --- /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 +#include + +// 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 " 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; iInsertL(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; + } +