--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/email/pop3andsmtpmtm/servermtmutils/src/IMCVCODC.CPP Thu Dec 17 08:44:11 2009 +0200
@@ -0,0 +1,2009 @@
+// Copyright (c) 1999-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 "IMCVCODC.H"
+#include "IMUTDLL.H"
+#include "IMCVSEND.H"
+
+const TInt8 AsciiToBase64[80]=
+ {
+ 62, -1, -1, -1, 63, 52, 53, 54, 55, 56,
+ 57, 58, 59, 60, 61, -1, -1, -1, 64, -1,
+ -1, -1, 0, 1, 2, 3, 4, 5, 6, 7,
+ 8, 9, 10, 11, 12, 13, 14, 15, 16, 17,
+ 18, 19, 20, 21, 22, 23, 24, 25, -1, -1,
+ -1, -1, -1, -1, 26, 27, 28, 29, 30, 31,
+ 32, 33, 34, 35, 36, 37, 38, 39, 40, 41,
+ 42, 43, 44, 45, 46, 47, 48, 49, 50, 51
+ };
+
+const TInt8 Base64ToAscii[65]=
+ {
+ 65, 66, 67, 68, 69, 70, 71, 72, 73, 74,
+ 75, 76, 77, 78, 79, 80, 81, 82, 83, 84,
+ 85, 86, 87, 88, 89, 90, 97, 98, 99,100,
+ 101,102,103,104,105,106,107,108,109,110,
+ 111,112,113,114,115,116,117,118,119,120,
+ 121,122, 48, 49, 50, 51, 52, 53, 54, 55,
+ 56, 57, 43, 47, 61
+ };
+
+const TInt8 KImcvLookUpStartOffset = 43;
+const TUint8 KImcvConvEquals = '=';
+
+const TInt KImMaxLengthForEncodedWordAndExtraEncodingTokens = 9;
+
+// Define the maximum length that one encoded character should occupy.
+// For certain encoding schemes such as Japanese, a single unicode character
+// may need a multi character string to represent it when it is sent as part
+// of an email header. This constant defines a maximum length for that string.
+// The value is based on the maximum length for a Japanese character
+const TInt KImMaxLengthForEncodedChar = 8;
+
+
+//---------------------------------------------------------------------------------
+// Class TImNoCodec Functions
+//---------------------------------------------------------------------------------
+
+
+//
+TInt TImCodecNull::Encode( const TDesC8& aSrcString, TDes8& rDestString)
+ {
+ rDestString.Copy(aSrcString);
+ return 0;
+ }
+
+//
+TBool TImCodecNull::Decode( const TDesC8& aInputLine, TDes8& rOutputLine)
+ {
+ rOutputLine.Copy(aInputLine);
+ return ETrue;
+ }
+
+
+
+//---------------------------------------------------------------------------------
+// Class TImCodecQP Functions
+//
+// Utility class, providing encoding/decoding functions for :
+// Quotable-printable, Base64 & UU.
+// Input/output consisting of 8bit strings.
+//---------------------------------------------------------------------------------
+
+//
+EXPORT_C TImCodecQP::TImCodecQP() : iPlainCharList(TPtrC8()), iEncodeCharList(TPtrC8())
+ {
+ iQPCharacter=KImcvEquals;
+ }
+
+//
+TBool TImCodecQP::SmartBreak( TInt written, const TDesC8& pSource )
+ {
+ TLex8 source( pSource );
+
+ // only check for whether we should break if the current char is breakable
+ if ( !IsBreakable(source.Peek()) )
+ return EFalse;
+
+ // scan ahead looking for the next breakable char.
+
+ source.Inc();
+ TBool found = EFalse;
+ TInt encodingOffset=(IsPlain(source.Peek()) ? 0 : 2);
+ while ( !found && !source.Eos() )
+ {
+ found = IsBreakable(source.Peek());
+ if (!found)
+ {
+ encodingOffset+=(IsPlain(source.Peek()) ? 0 : 2);
+ source.Inc();
+ }
+ }
+
+ // there's another breakable char before the end of the text
+ // - we need to break now if it's too far away
+ // but only if the non-breakable text fits on a line itself.
+
+ return ((written+source.Offset()+encodingOffset) > KMaxIMailBodyLineLength-4);
+ }
+
+//
+EXPORT_C TInt TImCodecQP::Encode( const TDesC8& aInputLine, TDes8& rOutputLine)
+ {
+ // number of characters written to the current line.
+ TInt written=0;
+
+ // Used to check we do not 'fold' a line after encountering an ESC character.
+ TInt escapeChar=0;
+
+ // number of characters introduced into the line by the encoding mechanism.
+ TInt localPaddingCount=0;
+
+ TChar nextChar=0;
+
+ // buffer used for preparing the hex encoding of a non-printable char
+ TBuf8<5> formatted;
+
+ TLex8 lexSource(aInputLine);
+ TDes8& ptr = rOutputLine;
+ TInt ptrEnd = ptr.MaxLength();
+
+ if (!lexSource.Eos())
+ {
+ lexSource.Get();
+ nextChar = lexSource.Peek();
+ lexSource.Inc(-1);
+ }
+
+ while (written<KImMailMaxBufferSize-2 && !lexSource.Eos())
+ {
+ if (written>=KMaxIMailBodyLineLength-3 && !escapeChar)
+ {
+ // force a soft line break.
+ __ASSERT_ALWAYS( ptr.Length()+4< ptr.MaxLength(), gPanic(KPanicDescriptorToSmall) );
+ ptr.Append(iQPCharacter);
+ ptr.Append(KImcvCRLF);
+ written+=3; localPaddingCount+=3;
+ break;
+ }
+
+ TChar peek = lexSource.Peek();
+
+ if (peek==KImcvESC)
+ escapeChar=3;
+
+ if ( SmartBreak(written,lexSource.Remainder()) && !escapeChar)
+ {
+ AddSoftLineBreak( ptr, localPaddingCount, written);
+ break;
+ }
+ else if ( IsPlain(peek) && peek!=KImcvSP && peek!=KImcvEquals )
+ // simple case, printable character
+ {
+ __ASSERT_ALWAYS( ptr.Length()+1<ptrEnd, gPanic(KPanicDescriptorToSmall) );
+ ptr.Append(peek);
+ written++;
+ }
+ else if ( peek==KImcvTab || peek==KImcvSP )
+ // Tab or space, need to check for immediate EOL so we can keep the space character
+ {
+ TChar thisChar =lexSource.Get();
+ TChar nextChar =(lexSource.Eos() ? (TChar)0 : lexSource.Get());
+
+ if (nextChar==KImcvCR && lexSource.Peek()==KImcvLF)
+ // Encode space, as EOL follows.
+ {
+ __ASSERT_ALWAYS( ptr.Length()+5<ptrEnd, gPanic(KPanicDescriptorToSmall) );
+ formatted.Format( KImcvQPFormatString, (TUint) thisChar );
+ formatted.UpperCase();
+ ptr.Append( formatted );
+
+ // also skip EOL the characters we just allowed for
+ written+=5;
+ localPaddingCount+=2;
+ break;
+ }
+ else
+ // no EOL, just carry on after the whitespace
+ {
+ __ASSERT_ALWAYS( ptr.Length()+1<ptrEnd, gPanic(KPanicDescriptorToSmall) );
+ ptr.Append( thisChar );
+ written++;
+ lexSource.Inc(-1);
+ if (nextChar)
+ lexSource.Inc(-1);
+ }
+ }
+ else if (peek==KImcvCR && nextChar==KImcvLF)
+ // Do not encode.
+ {
+ __ASSERT_ALWAYS( ptr.Length()+2<ptrEnd, gPanic(KPanicDescriptorToSmall) );
+ ptr.Append(KImcvCRLF);
+ written+=2;
+ lexSource.Inc();
+ break;
+ }
+ else if ( (TUint8)peek==iQPCharacter )
+ // '=' in source text
+ {
+ __ASSERT_ALWAYS( ptr.Length()+3<ptrEnd, gPanic(KPanicDescriptorToSmall) );
+ ptr.Append( KImcvQPEqualsSign );
+ written += 3;
+ localPaddingCount+=2;
+ }
+ else if (peek==KImcvTab || peek==KImcvHyphen || peek==KImcvSP)
+ {
+ __ASSERT_ALWAYS( ptr.Length()+1<ptrEnd, gPanic(KPanicDescriptorToSmall) );
+ ptr.Append( peek );
+ written++;
+ }
+ else
+ // non-printable char, must encode with Hex value
+ {
+ __ASSERT_ALWAYS( ptr.Length()+3<ptrEnd, gPanic(KPanicDescriptorToSmall) );
+ formatted.Format( KImcvQPEncoded, (TUint) peek );
+ formatted.UpperCase();
+ ptr.Append(formatted);
+ written += 3;
+ localPaddingCount += 2;
+ }
+
+ // advance to next source character
+ lexSource.Inc();
+ if (escapeChar)
+ escapeChar--;
+
+ // check whether we should give up without creating all the output
+ // non-quotable char to come & we're nearly at max length.
+
+ TChar thisChar = lexSource.Get();
+
+ // just in case we're pointing at the last character
+ nextChar = (lexSource.Eos() ? (TChar)0 : lexSource.Peek());
+ if (thisChar != 0)
+ lexSource.Inc(-1);
+
+ } // while
+
+ return written-localPaddingCount;
+ }
+
+//
+EXPORT_C TInt TImCodecQP::Decode( const TDesC8& aSrcString, TDes8& rDestString )
+ {
+ TInt error = KErrNone;
+
+ __ASSERT_DEBUG(aSrcString.Length(), gPanic(KPanicInvalidSMTPLine));
+
+ rDestString = KNullDesC8;
+
+ TPtrC8 source( aSrcString.Ptr(), aSrcString.Length() );
+ const TUint8* pSource = source.Ptr();
+ const TUint8* pEnd = pSource+aSrcString.Length();
+
+ // find out if this is a blank line, if so then we'll add a paragraph delimiter instead
+ // assume it's blank and then look for non-blank characters
+ // avoid the CRLF at the end of the line (we know it's there thanks to the assertion above)
+
+ TBool blankLine = ETrue;
+ while (pSource < pEnd-2)
+ {
+ if (*pSource!=KImcvSP && *pSource!=KImcvTab)
+ {
+ blankLine = EFalse;
+ break;
+ }
+ pSource++;
+ }
+
+ if ( blankLine )
+ {
+ rDestString.Copy( aSrcString );
+ return KErrNone;
+ }
+
+ TInt outputLength=0;
+ TUint8 loBits;
+ TUint8 hiBits;
+ TUint8 asciiValue;
+ pSource = source.Ptr(); // reset to start of source data
+ const TUint8 zero = '0';
+ const TUint8 alphaAdjust = 55; // 'A' is ascii 65 so we need to subtract 55 from
+ // alphabetical hex digits to get their numeric value
+ while( pSource < pEnd )
+ {
+ if (*pSource != iQPCharacter )
+ {
+ // Quoted character or Attachment bound, just bung it on & move to the next one
+ // *ptr++ = *pSource;
+ outputLength++;
+ rDestString.Append( *pSource );
+ }
+ else // check for encoded character
+ {
+ // start looking at the next two characters, if they are there.
+
+ if ( pSource+2 < pEnd )
+ {
+ pSource++;
+
+ // check for '=' at EOL => this is a soft break, so remove it
+ if (*pSource != KImcvCR)
+ {
+ if(*pSource != KImcvLF)
+ {
+ // now decode hex value into ASCII code : hi-order bits come first
+ hiBits = (TUint8)(0x0F & (IsDigit( *pSource ) ? (TUint8)(*pSource-zero) : (TUint8)(*pSource-alphaAdjust)));
+ pSource++;
+ loBits = (TUint8)(0x0F & (IsDigit( *pSource ) ? (TUint8)(*pSource-zero) : (TUint8)(*pSource-alphaAdjust)));
+ asciiValue = (TUint8)( (hiBits<<4) + loBits);
+ // bung the character thus formed onto the decoded string
+ rDestString.Append( asciiValue );
+ // *ptr++ = asciiValue;
+ outputLength++;
+ }
+ }
+ else
+ {
+ pSource++;
+ if(*pSource != KImcvLF)
+ {
+ error=KErrCorrupt;
+ pSource-=2;
+ rDestString.Append( *pSource );
+ pSource++;
+ rDestString.Append( *pSource );
+ pSource++;
+ outputLength+=2;
+ }
+ }
+ }
+ else
+ {
+ // copy the rest of the data & use up the input string in the process.
+
+ while (pSource < pEnd)
+ {
+ error=KErrCorrupt; // not QP compliant
+ //*ptr++ = *pSource++;
+ outputLength++;
+ rDestString.Append( *pSource );
+ pSource++;
+ }
+ }
+ } // check for '=' char
+
+ pSource++; // next source charactery
+ } // while
+
+ rDestString.SetLength(outputLength);
+
+ return error;
+ }
+
+
+// Not used. Remove in 6.3
+//
+EXPORT_C TInt TImCodecQP::EncodeRichText( const TDesC8& aInputLine, TDes8& rOutputLine)
+ {
+ TInt written=0; // number of characters written to the current line
+ TInt localPaddingCount=0; // number of characters introduced into the line by the encoding mechanism
+
+ // buffer used for preparing the hex encoding of a non-printable char
+ TBuf8<5> formatted;
+
+ TLex8 lexSource(aInputLine);
+ TDes8& ptr = rOutputLine;
+ TInt ptrEnd = ptr.MaxLength();
+
+ while (written < KMaxIMailBodyLineLength-3 &&!lexSource.Eos())
+ {
+ if ( SmartBreak(written,lexSource.Remainder()) )
+ {
+ AddSoftLineBreak(ptr, localPaddingCount, written);
+ break;
+ }
+
+ TChar peek = lexSource.Peek();
+ if ( IsPlain(peek) && peek!=KImcvSP )
+ // simple case, printable character
+ {
+ __ASSERT_ALWAYS( ptr.Length()+1<ptrEnd, gPanic(KPanicDescriptorToSmall) );
+ ptr.Append(peek);
+ written++;
+ }
+ else if ( peek==KImcvTab || peek==KImcvSP )
+ // Tab or space, need to check for immediate EOL so we can keep the space character
+ {
+ TChar thisChar = (lexSource.Eos() ? (TChar)0 : lexSource.Get());
+
+ if ( lexSource.Peek()==ETextParagraphDelimiter )
+ {
+ __ASSERT_ALWAYS( ptr.Length()+5<ptrEnd, gPanic(KPanicDescriptorToSmall) );
+ formatted.Format( KImcvQPFormatString, (TUint) thisChar );
+ formatted.UpperCase();
+ ptr.Append( formatted );
+ ptr.Append(KImcvCRLF);
+
+ // also skip EOL the characters we just allowed for
+ written+=7;
+ localPaddingCount+=4;
+
+ // advance to next source character
+ lexSource.Inc();
+ break;
+ }
+ else
+ // no EOL, just carry on after the whitespace
+ {
+ __ASSERT_ALWAYS( ptr.Length()+1<ptrEnd, gPanic(KPanicDescriptorToSmall) );
+ ptr.Append( thisChar );
+ written++;
+ lexSource.Inc(-1);
+ }
+ }
+ else if ( (TUint8)peek==iQPCharacter )
+ // '=' in source text
+ {
+ //is there enough space to encoded a char and put a soft break on the end.
+ if(written > KMaxIMailBodyLineLength-6)
+ break;
+
+ __ASSERT_ALWAYS( ptr.Length()+3<ptrEnd, gPanic(KPanicDescriptorToSmall) );
+ ptr.Append( KImcvQPEqualsSign );
+ written += 3;
+ localPaddingCount+=2;
+ }
+ else if (peek<KImcvSP && peek!=KImcvLF && peek !=KImcvCR )
+ // check for CEditableText control character
+ {
+ TChar replacement = ReplacementChar(peek);
+ if (replacement)
+ {
+ __ASSERT_ALWAYS( ptr.Length()+1<ptrEnd, gPanic(KPanicDescriptorToSmall) );
+ ptr.Append( replacement );
+ written++;
+ }
+ else if ( lexSource.Peek()==ETextParagraphDelimiter )
+ {
+ ptr.Append(KImcvCRLF);
+ written+=2;
+ localPaddingCount+=1;
+ break;
+ }
+ else
+ localPaddingCount-=1;
+ }
+ else
+ // non-printable char, must encode with Hex value
+ {
+ //is there enough space to encoded a char and put a soft break on the end
+ if(written > KMaxIMailBodyLineLength-6)
+ {
+ if (written+3 < KMaxIMailBodyLineLength)
+ {
+ AddSoftLineBreak(ptr, localPaddingCount, written);
+ }
+ break;
+ }
+ __ASSERT_ALWAYS( ptr.Length()+3<ptrEnd, gPanic(KPanicDescriptorToSmall) );
+ formatted.Format( KImcvQPEncoded, (TUint) peek );
+ formatted.UpperCase();
+ ptr.Append(formatted);
+ written += 3;
+ localPaddingCount += 2;
+ }
+
+ // advance to next source character
+ lexSource.Inc();
+
+ // check whether we should give up without creating all the output
+ // non-quotable char to come & we're nearly at max length.
+
+ TChar thisChar = lexSource.Get();
+ // just in case we're pointing at the last character
+ TChar nextChar = (lexSource.Eos() ? (TChar)0 : lexSource.Peek());
+ if (thisChar != 0)
+ lexSource.Inc(-1);
+
+ if ( !IsPlain( thisChar ) && (written >= KMaxIMailBodyLineLength-2)
+ || ( thisChar==KImcvSP || thisChar==KImcvTab)
+ && nextChar==CEditableText::EParagraphDelimiter
+ && (written >= KMaxIMailBodyLineLength-3) ) // whitespace just before linebreak
+ break;
+ } // while
+
+ rOutputLine.SetLength( written );
+
+ return (written-localPaddingCount);
+ }
+
+
+EXPORT_C TInt TImCodecQP::DecodeRichText( const TDesC8& aSrcString, TDes& rDestString )
+ {
+ TInt error = KErrNone;
+
+ __ASSERT_DEBUG(aSrcString.Length()>=2&&aSrcString[aSrcString.Length()-2]==KImcvCR&&aSrcString[aSrcString.Length()-1]==KImcvLF, gPanic(KPanicInvalidSMTPLine));
+
+ rDestString = KNullDesC;
+
+ TPtrC8 source( aSrcString.Ptr(), aSrcString.Length() );
+ const TUint8* pSource = source.Ptr();
+ const TUint8* pEnd = pSource+aSrcString.Length();
+
+ // find out if this is a blank line, if so then we'll add a paragraph delimiter instead
+ TBool blankLine = ETrue; // assume it's blank and then look for non-blank characters
+ while (pSource < pEnd-2) // avoid the CRLF at the end of the line (we know it's there thanks to the assertion above)
+ {
+ if (*pSource!=KImcvSP && *pSource!=KImcvTab)
+ {
+ blankLine = EFalse;
+ break;
+ }
+ else
+ pSource++;
+ }
+
+ if ( blankLine )
+ rDestString.Copy( aSrcString )
+ ;
+ else
+ {
+ TInt outputLength=0;
+ TUint8 loBits;
+ TUint8 hiBits;
+ TUint8 asciiValue;
+ pSource = source.Ptr(); // reset to start of source data
+ const TUint8 zero = '0';
+ const TUint8 alphaAdjust = 55; // 'A' is ascii 65 so we need to subtract 55 from
+ // alphabetical hex digits to get their numeric value
+ while( pSource < pEnd )
+ {
+ // check for encoded character
+ if (*pSource == iQPCharacter )
+ {
+ // start looking at the next two characters, if they are there
+ if ( pSource+2 < pEnd )
+ {
+ pSource++;
+ // check for '=' at EOL => this is a soft break, so remove it
+ if (*pSource != KImcvCR)
+ {
+ // now decode hex value into ASCII code : hi-order bits come first
+ hiBits = (TUint8)(0x0F & (IsDigit( *pSource ) ? (TUint8)(*pSource-zero) : (TUint8)(*pSource-alphaAdjust)));
+ pSource++;
+ loBits = (TUint8)(0x0F & (IsDigit( *pSource ) ? (TUint8)(*pSource-zero) : (TUint8)(*pSource-alphaAdjust)));
+ asciiValue = (TUint8)( (hiBits<<4) + loBits);
+ // bung the character thus formed onto the decoded string
+ rDestString.Append( asciiValue );
+ // *ptr++ = asciiValue;
+ outputLength++;
+ }
+ else
+ {
+ pSource++;
+ if(*pSource != KImcvLF)
+ {
+ error=KErrCorrupt;
+ pSource-=2;
+ rDestString.Append( *pSource );
+ pSource++;
+ rDestString.Append( *pSource );
+ pSource++;
+ outputLength+=2;
+ }
+ }
+ }
+ else
+ {
+ // copy the rest of the data & use up the input string in the process
+ while (pSource < pEnd)
+ {
+ error=KErrCorrupt; // not QP compliant
+ //*ptr++ = *pSource++;
+ outputLength++;
+ rDestString.Append( *pSource );
+ pSource++;
+ }
+ }
+ } // check for '=' char
+ else
+ {
+ if ( *pSource == KImcvCR && (pSource+1 < pEnd && *(pSource+1) == KImcvLF))
+ {
+ // this is a hard CRLF, so replace it with a Paragraph Delimiter
+
+ // *ptr++ = ETextParagraphDelimiter;
+ rDestString.Append( (TChar) CEditableText::EParagraphDelimiter );
+ outputLength++;
+
+ // ... and skip an extra char (the LF)
+ pSource++;
+ }
+ else
+ {
+ // Quoted character or Attachment bound, just bung it on & move to the next one
+ // *ptr++ = *pSource;
+ outputLength++;
+ rDestString.Append( *pSource );
+ }
+ }
+ // next source character
+ pSource++;
+ } // while
+ rDestString.SetLength(outputLength);
+ } // else
+ return error;
+ }
+
+
+//---------------------------------------------------------------------------------
+// Class TImFileCodec Functions
+//---------------------------------------------------------------------------------
+
+
+TInt TImFileCodec::PostfixNextLine(TDes8& rOutputLine, TInt& rPaddingCount)
+ {
+ return BlankLine(rOutputLine, rPaddingCount);
+ }
+
+
+TInt TImFileCodec::PrefixNextLineL(TDes8& /* rOutputLine*/, const TFileName& /*aName*/, TInt& /*rPaddingCount*/)
+ {
+ return KImAttFinished;
+ }
+
+
+void TImFileCodec::Initialise()
+ {
+ iPostfixState=0;
+ iPrefixState=0;
+ }
+
+//---------------------------------------------------------------------------------
+// Class TImCodecB64 Functions
+//---------------------------------------------------------------------------------
+
+
+EXPORT_C TImCodecB64::TImCodecB64(): iShiftStored(0), iMaskShiftStored(ESix)
+ {}
+
+
+// Returns ETrue if aSrcString is not long enough to decode fully, resulting in the storage of
+// the last character and requiring another aSrcString (poss 0 length) to be passed to it to
+// clear this character.
+// Returns EFalse if the line was decoded OK or the end of the encoded file is reached ie "="
+//
+EXPORT_C TBool TImCodecB64::Decode(const TDesC8& aSrcString, TDes8& rDestString)
+ {
+ TInt decodedInt=0;
+ TInt8 offsetChar=0;
+ TUint8 decodedChar=0;
+
+ // Clears the destination string
+ rDestString.Zero();
+
+ // Initialise variables
+ const TUint8* srcStringPtr=aSrcString.Ptr();
+ const TUint8* srcStringEnd=aSrcString.Length()+srcStringPtr;
+ TUint8* destStringPtr=(TUint8*)rDestString.Ptr();
+ TUint8* destStringPtrBase=destStringPtr;
+
+ TInt maskShift=iMaskShiftStored;
+ TInt shiftStorage=iShiftStored;
+
+ // Main character process loop
+ while(srcStringPtr<srcStringEnd)
+ {
+ offsetChar=(TInt8)(*srcStringPtr-KImcvLookUpStartOffset);
+ srcStringPtr++;
+
+ // Check for valid B64 character
+ if((offsetChar>=0)&&(offsetChar<80))
+ {
+ // Read in next character and B64 decode
+ decodedInt=AsciiToBase64[offsetChar];
+
+ // Exits when a PAD char is reached
+ if(decodedInt==EPadChar)
+ {
+ rDestString.SetLength((TInt)(destStringPtr-destStringPtrBase));
+ return EFalse;
+ }
+
+ // Ensures the first 2 chars of 4 are received before processing
+ if(maskShift==ESix)
+ maskShift=EFour;
+ else
+ {
+ shiftStorage=shiftStorage<<ESix;
+ shiftStorage=shiftStorage|decodedInt;
+ decodedChar=(TUint8)((shiftStorage>>maskShift)&EEightBitMask);
+
+ if((maskShift-=ETwo)<EZero)
+ maskShift=ESix;
+
+ *destStringPtr++=decodedChar;
+ }
+ shiftStorage=decodedInt;
+ }
+ }
+ iShiftStored=shiftStorage;
+ iMaskShiftStored=maskShift;
+
+ rDestString.SetLength((TInt)(destStringPtr-destStringPtrBase));
+
+ return maskShift<ESix;
+ }
+
+EXPORT_C TInt TImCodecB64::Encode(const TDesC8& aSrcString, TDes8& rDestString)
+ {
+ return DoEncode(aSrcString, rDestString, EFalse);
+ }
+
+EXPORT_C void TImCodecB64::Initialise()
+ {
+ iMaskShiftStored=ESix;
+ }
+
+TInt TImCodecB64::DoEncode(const TDesC8& aSrcString, TDes8& rDestString, TBool aInsertLineBreaks)
+ {
+ // Clears the destination string
+ rDestString.Zero();
+
+ // Initialise variables
+ const TUint8* srcStringPtr=aSrcString.Ptr();
+ const TUint8* srcStringEnd=aSrcString.Length()+srcStringPtr;
+ TUint8* destStringPtr=(TUint8*)rDestString.Ptr();
+ TUint8* destStringPtrBase=destStringPtr;
+
+ TInt character=0;
+ TUint8 encodedChar=0;
+ TInt charStorage=0;
+ TInt maskShift=EZero;
+ TInt destStringCharNum = 0;
+
+ while(srcStringPtr<=srcStringEnd)
+ {
+ // maskShift is used as a char read counter
+ if(maskShift==ESix)
+ {
+ // If the 3rd char read is also the last char then the while loop
+ // is broken on the next check.
+ if(srcStringPtr==srcStringEnd)
+ srcStringPtr++;
+ maskShift=EZero;
+ character=0;
+ }
+ else
+ {
+ if(srcStringPtr==srcStringEnd)
+ character=0;
+ else
+ character=*srcStringPtr;
+
+ srcStringPtr++;
+ // Shifts charStorage ready for the next char
+ charStorage=charStorage<<8;
+ maskShift+=ETwo;
+ }
+ charStorage=charStorage|character;
+ // Shifts the mask to the correct bit location
+ // Masks (AND's) the valid bits from charStorage
+ // Shifts the valid bits into the low order 8bits
+ // Converts to BASE64 char, Casts the result to an unsigned char (which it should be ?....I hope)
+ encodedChar=(TUint8)Base64ToAscii[((charStorage>>maskShift)&ESixBitMask)];
+
+ *destStringPtr++=encodedChar;
+ destStringCharNum++;
+
+ // Add a CRLF every KMaxB64EncodedCharsPerLine characters so as not to exceed the line length
+ // limitation specified in RFC 2822.
+ if (aInsertLineBreaks && destStringCharNum == KMaxB64EncodedCharsPerLine)
+ {
+ destStringCharNum = 0;
+ *destStringPtr++ = '\r';
+ *destStringPtr++ = '\n';
+ }
+ }
+
+ // Check for not enough chars and pad if required
+ if (maskShift==EFour)
+ {
+ *destStringPtr++=KImcvConvEquals;
+ *destStringPtr++=KImcvConvEquals;
+ }
+ else
+ if(maskShift==ESix)
+ *destStringPtr++=KImcvConvEquals;
+
+ rDestString.SetLength((TInt)(destStringPtr-destStringPtrBase));
+ return ((TInt)(srcStringPtr-srcStringEnd));
+ }
+
+TInt TImCodecB64WithLineBreaks::Encode(const TDesC8& aSrcString, TDes8& rDestString)
+ {
+ return DoEncode(aSrcString, rDestString, ETrue);
+ }
+
+//---------------------------------------------------------------------------------
+// Class TImCodecUU Functions
+//---------------------------------------------------------------------------------
+
+
+EXPORT_C TImCodecUU::TImCodecUU()
+ {}
+
+
+// returns ETrue if aSrcString is not long enough, relative to its line length character.
+// or if an invalid UU encoded character is found.
+// returns EFalse if the line was decoded OK
+//
+EXPORT_C TBool TImCodecUU::Decode(const TDesC8& aSrcString, TDes8& rDestString)
+ {
+ // Clears the destination string
+ rDestString.Zero();
+
+ // Initialise variables
+ const TUint8* srcStringPtr=aSrcString.Ptr();
+ TInt numEncChrs=*srcStringPtr++-ESpace;
+ TInt maskShift=ESix;
+ TInt numDecChrs=0;
+ TInt shiftStorage=0;
+ TInt character=0;
+ TUint8 decodedChar=0;
+
+ // Checks if the srcString is atleast long enough to decode.
+ if((numEncChrs*4)>((aSrcString.Length()-1)*3)) return ETrue;
+
+ // Main character process loop
+ while(numDecChrs<numEncChrs)
+ {
+ // Read in next character
+ character=*srcStringPtr++;
+
+ // Check for UU character validity
+ if((character<ESpace)||(character>EBackQuote)) return ETrue;
+
+ // Protocol thing
+ if(character==EBackQuote)
+ character=ESpace;
+
+ character-=ESpace;
+
+ // Ensures the first 2 chars of 4 are received before processing
+ if(maskShift==ESix)
+ maskShift=EFour;
+ else
+ {
+ shiftStorage=shiftStorage<<ESix;
+ shiftStorage=shiftStorage|character;
+
+ decodedChar=(TUint8)((shiftStorage>>maskShift)&EEightBitMask);
+ maskShift=((maskShift==EZero)? ESix:(maskShift-ETwo));
+
+ rDestString.Append(decodedChar);
+ numDecChrs++;
+ }
+ shiftStorage=character;
+ }
+ return EFalse;
+ }
+
+
+EXPORT_C TInt TImCodecUU::Encode(const TDesC8& aSrcString, TDes8& rDestString)
+ {
+ // Clears the destination string
+ rDestString.Zero();
+
+ // Initialise variables
+ const TUint8* srcStringPtr=aSrcString.Ptr();
+ const TInt srcLength=aSrcString.Length();
+ const TUint8* srcStringEnd=srcStringPtr+srcLength;
+ TInt charStorage=0;
+ TInt maskShift=EZero;
+ TInt character=0;
+ TUint8 encodedChar=0;
+ TInt destStringCharNum = 0;
+ TInt srcStringBytesRemaining = 0;
+
+ while(srcStringPtr<=srcStringEnd)
+ {
+ // Add unencoded length to start of line as per UU specification.
+ if (destStringCharNum == 0)
+ {
+ srcStringBytesRemaining = srcStringEnd - srcStringPtr;
+ if ( srcStringBytesRemaining < KMaxUUUnEncodedCharsPerLine )
+ rDestString.Append(static_cast<TUint8>(srcStringBytesRemaining) + ESpace);
+ else
+ rDestString.Append(KMaxUUUnEncodedCharsPerLine + ESpace);
+ }
+
+ if(maskShift==ESix)
+ {
+ // If the 3rd char read is also the last char then the while loop
+ // is broken on the next check.
+ if(srcStringPtr==srcStringEnd)
+ srcStringPtr++;
+ character=0;
+ maskShift=EZero;
+ }
+ else
+ {
+ if(srcStringPtr==srcStringEnd)
+ character=0;
+ else
+ character=*srcStringPtr;
+
+ srcStringPtr++;
+ charStorage=charStorage<<8;
+ maskShift+=ETwo;
+ }
+ charStorage=charStorage|character;
+ // Shifts the mask to the correct bit location
+ // Masks (AND's) the valid bits
+ // Shifts the valid bits into the low order 8bits
+ // Adds 32 (SPACE), Casts the result to an unsigned char (which it should be ?....I hope)
+ encodedChar=(TUint8)(((charStorage>>maskShift)&ESixBitMask)+ESpace);
+
+ // Protocol thing
+ if(encodedChar==ESpace)
+ encodedChar=EBackQuote;
+
+ rDestString.Append(encodedChar);
+ ++destStringCharNum;
+
+ // Add a CRLF every KMaxUUEncodedCharsPerLine characters so as not to exceed the line length
+ // limitation recommended for UUE.
+ if (destStringCharNum == KMaxUUEncodedCharsPerLine)
+ {
+ destStringCharNum = 0;
+ rDestString.Append(KImcvCRLF);
+ }
+ }
+
+ return ((TInt)(srcStringPtr-srcStringEnd));
+ }
+
+
+TInt TImCodecUU::PrefixNextLineL( TDes8& rOutputLine, const TFileName& aName, TInt& rPaddingCount )
+ {
+ rOutputLine.Append( KImcvUueStart );
+ rOutputLine.Append( KImcvUue644 );
+ AppendFilenameL( rOutputLine, aName );
+ rPaddingCount=rOutputLine.Length();
+ return 1;
+ }
+
+TInt TImCodecUU::PostfixNextLine( TDes8& rOutputLine, TInt& rPaddingCount )
+ {
+ switch( iPostfixState )
+ {
+ case EInvertedComma:
+ rOutputLine.Append( KImcvInvertedComma );
+ break;
+ case EEndString:
+ rOutputLine = KImcvUueEnd;
+ break;
+ }
+
+ iPostfixState++;
+ rPaddingCount=rOutputLine.Length();
+
+ return (iPostfixState==EEndOfPostfix ? KImAttFinished : KErrNone);
+ }
+
+
+
+void TImCodecUU::AppendFilenameL( TDes8& rOutputLine, const TFileName& aName)
+ {
+ HBufC8* buf = HBufC8::NewLC( aName.Length() );
+ buf->Des().Copy( aName );
+ rOutputLine.Append(KImcvSpace);
+ rOutputLine.Append( *buf );
+ CleanupStack::PopAndDestroy(); // buf
+ }
+
+
+
+
+//---------------------------------------------------------------------------------
+// Class CImConvertHeader Functions
+//
+// Utility class, providing functionality for encoding/decoding header fields.
+// Requires use of Charconv "Wrapper" class.
+//------------------------------------------------------------------------------
+
+/**
+@publishedPartner
+@released
+*/
+EXPORT_C CImConvertHeader* CImConvertHeader::NewL(CImConvertCharconv& aConverter)
+ {
+ CImConvertHeader* self = new (ELeave) CImConvertHeader (aConverter);
+ CleanupStack::PushL(self);
+ self->ConstructL();
+ CleanupStack::Pop(self);
+ return self;
+ }
+
+CImConvertHeader::CImConvertHeader(CImConvertCharconv& aConverter) :
+ iCharConv (aConverter)
+ {
+ }
+
+CImConvertHeader::~CImConvertHeader()
+ {
+ iHeader = NULL;
+ }
+
+void CImConvertHeader::ConstructL()
+ {
+ iQPCodec.AddEncodeChar(KImcvEncodeCharacterList);
+
+ // Default setting.
+ iCharConv.PrepareToConvertToFromOurCharsetL(iCharConv.DefaultCharset());
+ }
+
+EXPORT_C void CImConvertHeader::SetMessageType(TBool aIsMIME)
+ {
+ isMIMEMessageHeader=aIsMIME;
+ }
+
+EXPORT_C void CImConvertHeader::SetOverrideCharset(TUint aCharset)
+/**
+Sets the override character set to use when decoding the 8 bit data. Zero
+indicates the charset not to be used.
+
+@param aCharset
+The new character set to use as an overriding character set.
+*/
+ {
+ iOverrideCharset = aCharset;
+ }
+
+EXPORT_C TUint CImConvertHeader::OverrideCharset() const
+/**
+Retrieves the override character set that will be used when decoding the 8 bit
+data. A character set value of zero indicates no overriding character set will
+be used.
+*/
+ {
+ return iOverrideCharset;
+ }
+
+//------------------------------------------------------------------------------
+
+EXPORT_C void CImConvertHeader::DecodeAllHeaderFieldsL(CImHeader& rHeader)
+ {
+ iHeader = &rHeader;
+
+ iHeader->SaveEncodedHeadersL();
+
+ // If Header field does not have a Mime info, but header has encoded words, then
+ // we need to parse it accordingly.
+ TBool nonMime = EFalse;
+ if (!isMIMEMessageHeader)
+ {
+ isMIMEMessageHeader = ETrue;
+ nonMime = ETrue;
+ }
+
+ // FROM:
+ iEncodingInfo.SetField(TImHeaderEncodingInfo::EFrom);
+ DecodeFieldL( rHeader.From());
+
+ // SUBJECT:
+ iEncodingInfo.SetField(TImHeaderEncodingInfo::ESubject);
+ DecodeFieldL( rHeader.Subject());
+
+ // REPLYTO:
+ iEncodingInfo.SetField(TImHeaderEncodingInfo::EReplyTo);
+ DecodeFieldL( rHeader.ReplyTo());
+
+ // TO:
+ iEncodingInfo.SetField(TImHeaderEncodingInfo::ETo);
+ DecodeRecipientListL(rHeader.ToRecipients());
+
+ // CC:
+ iEncodingInfo.SetField(TImHeaderEncodingInfo::ECc);
+ DecodeRecipientListL(rHeader.CcRecipients());
+
+ // BCC:
+ iEncodingInfo.SetField(TImHeaderEncodingInfo::EBcc);
+ DecodeRecipientListL(rHeader.BccRecipients());
+
+ if(nonMime)
+ {
+ isMIMEMessageHeader = EFalse;
+ }
+
+ iHeader = NULL; // iHeader is not used outside non-exported function DecodeFieldL
+ }
+
+
+void CImConvertHeader::DecodeFieldL(const TDesC& aField)
+ {
+ HBufC* buf = HBufC::NewLC(aField.Size());
+ TPtr ptr(buf->Des());
+ DecodeHeaderFieldL(aField, ptr);
+
+ switch (iEncodingInfo.Field())
+ {
+ case TImHeaderEncodingInfo::EFrom:
+ iHeader->SetFromL(*buf);
+ break;
+ case TImHeaderEncodingInfo::ESubject:
+ iHeader->SetSubjectL(*buf);
+ break;
+ case TImHeaderEncodingInfo::EReplyTo:
+ iHeader->SetReplyToL(*buf);
+ break;
+ default:
+ __ASSERT_DEBUG(1, User::Invariant());
+ }
+ CleanupStack::PopAndDestroy( ); // buf
+ }
+
+
+void CImConvertHeader::DecodeRecipientListL(CDesCArray& aArray)
+ {
+ HBufC* buf = NULL;
+ TInt i = aArray.Count();
+ while (i--)
+ {
+ iEncodingInfo.SetArrayValue(i);
+
+ if (!(aArray[i]).Length())
+ continue; // Should really delete them some how
+
+ buf = HBufC::NewLC(aArray[i].Length());
+ TPtr ptr(buf->Des());
+
+ DecodeHeaderFieldL(aArray[i], ptr);
+ aArray.Delete(i);
+ aArray.InsertL(i, *buf);
+
+ CleanupStack::PopAndDestroy( ); // buf
+ }
+ }
+
+/**
+Search for one or more encoded words in aLine
+
+@publishedPartner
+@released
+*/
+
+ EXPORT_C void CImConvertHeader::DecodeHeaderFieldL(const TDesC16& aBufIn, TDes& aBufOut)
+
+ {
+ // input should be 8bit, possible loss of data otherwise.
+ HBufC8* buffer8 = HBufC8::NewLC( aBufIn.Length() );
+ buffer8->Des().Copy( aBufIn );
+
+ if (isMIMEMessageHeader)
+
+ DecodeHeaderFieldL( *buffer8, aBufOut);
+
+ else
+ DecodeNonMIMEHeaderFieldL( *buffer8, aBufOut);
+
+
+
+ CleanupStack::PopAndDestroy( ); // buffer8
+ }
+
+/**
+Search for one or more encoded words in aLine
+
+@publishedPartner
+@released
+*/
+ EXPORT_C void CImConvertHeader::DecodeHeaderFieldL(const TDesC8& aBufIn, TDes& aBufOut)
+ {
+ __ASSERT_DEBUG(aBufIn.Size() <= aBufOut.MaxSize(), User::Invariant());
+ aBufOut.SetLength(0);
+
+ TBool wordExists = ETrue;
+ TBool decoded = EFalse;
+ TInt rem = 0;
+ TPtrC8 encodedWord8(aBufIn);
+ TChar QMark = KImcvQuestionMark;
+ TInt spaces = 0;
+ TLex8 lex(aBufIn);
+
+ while (wordExists)
+ {
+ wordExists = EFalse;
+
+ lex.SkipSpaceAndMark();
+ spaces = lex.TokenLength();
+
+ // Get next Encoded word
+ while (lex.Peek() != KImcvEquals && !lex.Eos())
+ {
+ lex.Inc();
+ }
+
+ if (lex.Eos())
+ {
+ break;
+ }
+
+ lex.Inc();
+ if (lex.Peek() == QMark)
+ {
+ // We have the start of an encoded word..
+ // Copy over all data marked prior to word
+ lex.Inc(-1);
+
+ if (spaces==lex.TokenLength())
+ {
+ // contiguous encoded-words, spaces removed in decoded word.
+ iEncodingInfo.SetAddSpace(ETrue);
+ }
+ else
+ {
+ do
+ {
+ lex.Inc(-1);
+ }
+ while (lex.Peek()==KImcvSpaceChar || lex.Peek()==KImcvTab);
+ lex.Inc();
+ if (!lex.Eos() &&
+ (lex.Peek()==KImcvSpaceChar || lex.Peek()==KImcvTab) ) // Get back to space
+ {
+ lex.Inc();
+ }
+ TPtrC8 marked = lex.MarkedToken();
+ Append(aBufOut, marked);
+
+ }
+
+ lex.SkipSpaceAndMark(); // Start of encoded word
+
+ //--Need to check two question marks within encoded word --
+ lex.Inc(2);
+ while ( lex.Peek() != QMark && !lex.Eos() )
+ {
+ lex.Inc();
+ }
+
+ if (lex.Peek() != QMark)
+ {
+ break; // incorrectly formed encoded-word
+ }
+
+ if (!lex.Eos())
+ {
+ lex.Inc();
+ }
+ else
+ {
+ break;
+ }
+
+ if (!lex.Eos())
+ {
+ lex.Inc();
+ }
+ else
+ {
+ break;
+ }
+
+ if (!lex.Eos() && lex.Peek() != QMark)
+ {
+ break; // incorrectly formed encoded-word
+ }
+
+ lex.Inc();
+
+ while ( lex.Peek() != QMark && !lex.Eos() )
+ {
+ lex.Inc();
+ }
+
+ if (lex.Peek() != QMark)
+ {
+ break; // incorrectly formed encoded-word
+ }
+
+ if (!lex.Eos())
+ {
+ lex.Inc();
+ }
+ else
+ {
+ break;
+ }
+
+ if (lex.Peek() != KImcvEquals)
+ {
+ break; // incorrectly formed encoded-word
+ }
+
+ if (!lex.Eos())
+ {
+ lex.Inc();
+ }
+ else
+ {
+ break;
+ }
+ //---------------------------------------------------------
+
+ encodedWord8.Set(lex.MarkedToken());
+
+ wordExists = ETrue;
+ }
+
+ if (wordExists)
+ {
+ // If found ...
+ decoded=ETrue;
+ HBufC* decodedWord = HBufC::NewLC(encodedWord8.Length());
+
+ TPtr decodedPtr(decodedWord->Des());
+ if ( DecodeWordL(encodedWord8, decodedPtr, rem) )
+ {
+ // replace decoded string with new string
+ TUint offset = aBufOut.Length();
+
+
+ // Store encoding information in Header object.
+ iEncodingInfo.SetEncodedLength(lex.TokenLength());
+ iEncodingInfo.SetOffset(offset);
+ iEncodingInfo.SetLength(decodedPtr.Length());
+
+ if (iHeader)
+ {
+ iHeader->AddEncodingInfoL(iEncodingInfo);
+ }
+
+ }
+
+ aBufOut.Append( decodedPtr );
+
+ CleanupStack::PopAndDestroy(); // decodedWord;
+ }
+ } // while
+
+ lex.UnGetToMark();
+ if (decoded && lex.MarkedOffset())
+ {
+ lex.UnGet();
+ if (lex.Peek()==KImcvSpaceChar || lex.Peek()==KImcvTab)
+ {
+ lex.Mark();
+ }
+ }
+
+ if(decoded==EFalse)
+ {
+ DecodeNonMIMEHeaderFieldL(aBufIn,aBufOut);
+
+ }
+ else
+ {
+ TPtrC8 marked = lex.RemainderFromMark();
+ Append(aBufOut, marked);
+
+ }
+}
+
+
+// For non-MIME case, System default being ASCII normally
+//
+ EXPORT_C void CImConvertHeader::DecodeNonMIMEHeaderFieldL(const TDesC8& aBufIn, TDes& aBufOut)
+
+ {
+ __ASSERT_DEBUG(aBufIn.Size() <= aBufOut.MaxSize(), User::Invariant());
+
+ TUint charset;
+
+ (iOverrideCharset != 0) ?
+ (charset = iOverrideCharset) : (charset = iCharConv.DefaultCharset());
+
+ if (iCharConv.PrepareToConvertToFromOurCharsetL(charset)== EFalse)
+ {
+ // Charset not available, don't decode.
+ aBufOut.Copy(aBufIn);
+ }
+
+ // Character set conversion
+ TInt unconvertedChars;
+ TInt pos;
+ iCharConv.ConvertToOurCharsetL(aBufIn, aBufOut, unconvertedChars, pos);
+
+}
+
+
+
+// aBufIn is of the form "=?" "charset" "?" "Encoding" "?" "Encoding Text" "?="
+// Decode the 'Encoding Text' based on the information in 'Encoding' and 'charset'
+// and pass back in aBufOut
+
+//
+ TBool CImConvertHeader::DecodeWordL(const TDesC8& aBufIn, TDes& aBufOut, TInt rRemainder)
+ {
+ rRemainder=0;
+ HBufC8* dataBuf8 = HBufC8::NewLC(aBufOut.MaxLength());
+
+
+ const TUint8* ptr = aBufIn.Ptr();
+
+ __ASSERT_DEBUG( (*ptr == KImcvEquals) && (*(ptr+1) == KImcvQuestionMark),User::Invariant());
+
+ // Extract the charset string and store
+ TInt i;
+ for(i = 2; *(ptr+i) != KImcvQuestionMark ; i++)
+ ;
+
+ TUint uid;
+ if (iOverrideCharset != 0)
+ {
+ uid = iOverrideCharset;
+ }
+ else
+ {
+ TPtrC8 buf8(ptr+2, i-2);
+ uid = iCharConv.GetMimeCharsetUidL(buf8);
+ }
+
+ if (!uid || !iCharConv.PrepareToConvertToFromOurCharsetL(uid))
+ {
+ // Charset not available, dont decode.
+ aBufOut.Copy(aBufIn);
+ CleanupStack::PopAndDestroy(dataBuf8);
+ return EFalse;
+ }
+
+ iEncodingInfo.SetCharsetUid(uid);
+
+ // Extract the Encoding string and store
+ for(i++; *(ptr+i) != KImcvQuestionMark ; i++)
+ ;
+ TPtrC8 buf28(ptr+i-1, 1);
+ iEncodingInfo.SetEncodingType(buf28); // Currently encoding is either Q or B
+
+
+ // Now at the encoding text
+ TInt j;
+ for(j = i+1; *(ptr+j) != KImcvQuestionMark ; j++)
+ ;
+
+ // Intermediate buffer for decoding, prior to converting
+
+ HBufC8* decodeBuf8 = HBufC8::NewLC(aBufOut.MaxLength());
+
+ decodeBuf8->Des().Copy( aBufIn.Mid(i+1, j -i-1));
+
+ // Depending on type of encoding Q or B, decode.
+
+ TPtr8 dataPtr8(dataBuf8->Des());
+
+ switch (iEncodingInfo.EncodingType())
+ {
+ case TImHeaderEncodingInfo::EBase64 :
+ iB64Codec.Decode( *decodeBuf8, dataPtr8 );
+ break;
+ case TImHeaderEncodingInfo::EQP :
+ // Replace all underscores in text with SPACE.
+ iQPCodec.Decode( *decodeBuf8, dataPtr8 );
+
+ i=dataPtr8.Length();
+ while (i--)
+ {
+ if (dataPtr8[i] == KImcvUnderScore)
+ dataPtr8[i] = KImcvSpaceChar;
+ }
+ break;
+ default:
+ dataBuf8->Des().Copy(*decodeBuf8);
+ break;
+ }
+
+ // Character set conversion
+ TInt unconvertedChars, pos;
+ rRemainder = iCharConv.ConvertToOurCharsetL(*dataBuf8, aBufOut, unconvertedChars, pos);
+
+ CleanupStack::PopAndDestroy(decodeBuf8);
+ CleanupStack::PopAndDestroy(dataBuf8);
+ return (rRemainder < 0) ? EFalse:ETrue;
+ }
+/**
+Convert function used for non-MIME messages.
+
+@publishedPartner
+@released
+*/
+EXPORT_C void CImConvertHeader::ConvertHeaderFieldL(const TDesC16& aBufIn, RBuf8& aBufOut, TBool aIsAddressField)
+ {
+ // Don't make use of the unconverted char info.
+ //Assume text has been checked for non ascii characters.
+
+ // Need to identify the email address
+ TInt start=0;
+ TInt end=0;
+
+ if (ExtractTextToEncode(aBufIn, start, end, aIsAddressField)==EFalse)
+ aBufOut.Copy(aBufIn);
+ else
+ {
+ // clear out buffer
+ aBufOut.Zero();
+ TInt unconvertedChars;
+ TInt pos;
+ iCharConv.ConvertFromOurCharsetL( aBufIn.Mid(start, end-start+1), aBufOut, unconvertedChars, pos);
+
+ if (start>0)
+ {
+ // Copy over text prior to bit needing encoding
+ aBufOut.ReAllocL(aBufOut.Length() + aBufIn.Length());
+ Insert( aBufOut, aBufIn.Left(start));
+
+ }
+
+ if (end<aBufIn.Length())
+ {
+ // Copy over text after bit needing encoding
+
+ aBufOut.ReAllocL(aBufOut.Length() + (aBufIn.Length()-end-1));
+ aBufOut.Append(aBufIn.Right(aBufIn.Length()-end-1));
+
+ }
+ }
+ }
+
+
+/**
+@publishedPartner
+@released
+*/
+EXPORT_C void CImConvertHeader::EncodeHeaderFieldL(const TDesC& aBufIn, RBuf8& aBufOut,
+ CArrayFix<TImHeaderEncodingInfo>* aInfoArray, TInt aState, TInt aArrayVal)
+ {
+ // In case not requiring encoding, already ascii
+ // allocate enough space to copy data
+ aBufOut.ReAllocL(aBufIn.Length());
+ aBufOut.Copy(aBufIn);
+
+ for (TInt i=0; i < aInfoArray->Count(); i++)
+ {
+ if ( (aInfoArray->At(i).Field() == (TImHeaderEncodingInfo::TFieldList) aState)
+ && ((*aInfoArray)[i].ArrayValue() == (TInt)aArrayVal) )
+ {
+ GetCharsetAndEncodeDataL( aBufIn, aBufOut, (*aInfoArray)[i]);
+ }
+ }
+ }
+
+/**
+ This function has to encode without any prestored information.
+ Encodes from UNICODE, to UTF-7
+
+@publishedPartner
+@released
+*/
+EXPORT_C void CImConvertHeader::EncodeHeaderFieldL(const TDesC& aBufIn, RBuf8& aBufOut,
+ const TUint aCharset, const TImHeaderEncodingInfo::TEncodingType aType, TBool aIsAddressField)
+ {
+ TImHeaderEncodingInfo infoArray;
+
+ aBufOut.ReAllocL(aBufIn.Length());
+ aBufOut.Copy(aBufIn);
+
+ infoArray.SetCharsetUid(aCharset);
+ infoArray.SetEncodingType(aType);
+
+ TInt startOfEncoding = 0;
+ TInt endOfEncoding = 0;
+ if(ExtractTextToEncode(aBufIn, startOfEncoding, endOfEncoding, aIsAddressField))
+ {
+ infoArray.SetOffset(startOfEncoding);
+ infoArray.SetLength(endOfEncoding - startOfEncoding + 1);
+ GetCharsetAndEncodeDataL(aBufIn, aBufOut, infoArray);
+ }
+ }
+
+// Return the offset in the text buffer for the text portion of the header field
+//
+TBool CImConvertHeader::ExtractTextToEncode(const TDesC& aBufIn, TInt& rStart, TInt& rEnd, TBool aIsAddressField)
+ {
+ TInt startOfEncoding = 0;
+ TInt endOfEncoding = 0;
+ TBool mustEncode = EFalse;
+ TBool mustEncodeThisWord=EFalse;
+
+ // Check aField for non ascii characters - encode. Return in rEncodedField.
+
+ TInt len=aBufIn.Length();
+ TInt i=0;
+ for (;i < len;i++)
+ {
+ TChar inChar = aBufIn[i];
+ if (inChar==KImcvSpaceChar || inChar==KImcvQuote || inChar==KImcvTab)
+ {
+ if (mustEncodeThisWord)
+ endOfEncoding=i-1;
+ else if (!mustEncode)
+ startOfEncoding=i+1;
+ mustEncodeThisWord=EFalse;
+ }
+ else if (inChar==KImcvLeftChevron && aIsAddressField)
+ {
+ if (mustEncodeThisWord)
+ {
+ endOfEncoding=i-1;
+ mustEncodeThisWord=EFalse;
+ }
+ if (mustEncode)
+ break; // already have word to encode, now at an address
+ }
+ else if (inChar==KImcvRightChevron && aIsAddressField)
+ {
+ startOfEncoding=i+1;
+ }
+ else if ( !IsAscii(inChar) )
+ {
+ mustEncode = ETrue;
+ mustEncodeThisWord=ETrue;
+ }
+ }
+
+ if (mustEncodeThisWord)
+ endOfEncoding=i-1;
+
+ rStart=startOfEncoding;
+ rEnd=endOfEncoding;
+ return mustEncode;
+ }
+
+void CImConvertHeader::GetCharsetAndEncodeDataL(const TDesC& aBufIn,
+ RBuf8& aBufOut, TImHeaderEncodingInfo& aInfo)
+ {
+ // Work out which character set to use, and get a string representation
+ // of it.
+ HBufC8* charsetName=iCharConv.GetMimeCharsetTextStringL(aInfo.CharsetUid());
+
+ TUint charset=aInfo.CharsetUid();
+ if (charset==KCharacterSetIdentifierIso88591)
+ charset=KCharacterSetIdentifierCodePage1252;
+
+ if (!charsetName || !iCharConv.PrepareToConvertToFromOurCharsetL(charset))
+ {
+ delete charsetName;
+ charsetName=NULL;
+
+ // Problem with charset Uid, use default character set.
+ charset=iCharConv.DefaultCharset();
+ aInfo.SetCharsetUid(charset);
+ charsetName=iCharConv.GetMimeCharsetTextStringL(charset);
+ if (charset==KCharacterSetIdentifierIso88591)
+ charset=KCharacterSetIdentifierCodePage1252;
+ __ASSERT_ALWAYS(iCharConv.PrepareToConvertToFromOurCharsetL(charset), User::Invariant());
+ }
+
+ CleanupStack::PushL(charsetName);
+ __ASSERT_ALWAYS(charsetName, gPanic(KPanicInvalidDefaultCharacterSet) );
+
+ // Create a buffer to use to store the encoded word
+ HBufC8* encodedWordBuffer = HBufC8::NewL(aBufOut.MaxSize());
+ RBuf8 encodedWord(encodedWordBuffer);
+ encodedWord.CleanupClosePushL();
+
+ EncodeWordL(aBufIn, aBufOut, aInfo, *charsetName, encodedWord);
+
+ CleanupStack::PopAndDestroy(2, charsetName); // charset name, encoded word
+ }
+
+
+void CImConvertHeader::EncodeWordL(const TDesC& aBufIn,
+ RBuf8& aBufOut, TImHeaderEncodingInfo& aInfo,
+ const TDesC8& aCharsetName, RBuf8& aEncodedWord)
+ {
+ TInt max = KEncodedWordMaxLength - KMaxEncodedInformationLength -
+ aCharsetName.Length() - KMaxHeaderFieldNameLength;
+
+ TBool splitAndRetry = ETrue;
+
+ // We will convert the word to the required character set, and perform any
+ // encoding (base64, quoted-printable) required. At each stage we check whether
+ // the buffer has exceeded the maximum length allowed for a line. If so, we
+ // cut the buffer into two halves and encode each half separately.
+
+ if (aInfo.Length() <= max)
+ {
+ // Identify the part of the input buffer that will be encoded
+ TPtrC data = aBufIn.Mid(aInfo.Offset(), aInfo.Length());
+
+ // Perform the conversion to the required character set
+ DoCharsetConversionL(data, aEncodedWord);
+
+ if (aEncodedWord.Length() <= max)
+ {
+ // Perform any base64 / quoted printable encoding
+ DoEncodingL(aEncodedWord, aInfo);
+
+ if (aEncodedWord.Length() <= max)
+ {
+ // We have managed to do all the steps without the buffer exceeding
+ // the maximum line length
+ splitAndRetry = EFalse;
+ }
+ }
+ }
+
+ if (splitAndRetry)
+ {
+ TInt len = aInfo.Length()/2;
+ TUint16 offset = (TUint16) aInfo.Offset();
+ TUint16 length = (TUint16) aInfo.Length();
+
+ aInfo.SetOffset(offset+len);
+ aInfo.SetLength(length-len);
+ EncodeWordL(aBufIn, aBufOut, aInfo, aCharsetName, aEncodedWord);
+ aBufOut.ReAllocL(aBufOut.MaxLength()+1);
+ aBufOut.Insert(offset+len,KImcvSpace);
+
+ aInfo.SetOffset(offset);
+ aInfo.SetLength(len);
+ EncodeWordL(aBufIn, aBufOut, aInfo, aCharsetName, aEncodedWord);
+
+ aInfo.SetLength(length);
+ }
+ else
+ {
+ // Delete unencoded data, prior to putting in encoded data
+ aBufOut.Delete(aInfo.Offset(), aInfo.Length());
+ aBufOut.ReAllocL(aBufOut.MaxLength()-aInfo.Length());
+ AddEncodedWordInfoL(aEncodedWord, aBufOut, aInfo, aCharsetName);
+ aEncodedWord.Zero();
+ }
+ }
+
+
+TBool CImConvertHeader::DoCharsetConversionL(const TDesC& aDataToConvert, RBuf8& aEncodedWord)
+ {
+ TBool convertOk = ETrue;
+
+ TInt unconvertedChars, pos;
+ TInt excessChars;
+ TInt lastExcessChars = 0;
+ TBool failNextTimeExcessCharsStaySame = EFalse;
+ TBool finishedConvert = EFalse;
+
+ while (!finishedConvert)
+ {
+ excessChars = iCharConv.ConvertFromOurCharsetL(aDataToConvert, aEncodedWord, unconvertedChars, pos);
+
+ if (excessChars == 0)
+ {
+ finishedConvert = ETrue;
+ }
+ else if (excessChars == CCnvCharacterSetConverter::EErrorIllFormedInput)
+ {
+ User::Leave(KErrCorrupt);
+ }
+ else
+ {
+ // We did not convert all the characters in the buffer. This is
+ // probably because the output buffer is not large enough.
+ // If the number of characters left unconverted this time is the same
+ // as last time, then perhaps the conversion is failing for other
+ // reasons. To avoid getting stuck like this forever, we will only
+ // allow this to happen once.
+
+ if (excessChars == lastExcessChars)
+ {
+ if (failNextTimeExcessCharsStaySame)
+ {
+ finishedConvert = ETrue;
+ convertOk = EFalse;
+ }
+ else
+ {
+ failNextTimeExcessCharsStaySame = ETrue;
+ }
+ }
+ else
+ {
+ failNextTimeExcessCharsStaySame = EFalse;
+ }
+
+ // If we are going around again, increase the size of the output buffer
+ if (!finishedConvert)
+ {
+ aEncodedWord.ReAllocL(aEncodedWord.MaxSize() + KImMaxLengthForEncodedChar);
+ lastExcessChars = excessChars;
+ }
+ }
+ }
+
+ return convertOk;
+ }
+
+void CImConvertHeader::DoEncodingL(RBuf8& aEncodedWord, TImHeaderEncodingInfo& aInfo)
+ {
+ // Take a copy of the encoded word so far. This will be used as the
+ // input to the encoding routines
+ HBufC8* dataToEncode = HBufC8::NewLC(aEncodedWord.Length());
+ dataToEncode->Des().Copy(aEncodedWord);
+ aEncodedWord.Zero();
+
+ if (aInfo.EncodingType() == TImHeaderEncodingInfo::EBase64)
+ {
+ // Increase the size of the buffer to allow for the base64 encoding.
+ // Base64 takes three 8 bit octets and encodes them into four 6 bit
+ // characters.
+ aEncodedWord.ReAllocL((((*dataToEncode).Length() + 2) / 3) * 4);
+
+ iB64Codec.Encode(*dataToEncode, aEncodedWord);
+ }
+ else if (aInfo.EncodingType() == TImHeaderEncodingInfo::EQP)
+ {
+ // Worst case scenario is that each character in the buffer has to be
+ // encoded to its hex equivalent with preceding '=' sign. Also added an
+ // extra byte becuase the QP encoder expects the buffer to be one longer
+ // than required.
+ aEncodedWord.ReAllocL(((*dataToEncode).Length() * 3) + 1);
+
+ // Replace all underscores in text with SPACE.
+ for(TInt i=0; i < (*dataToEncode).Length(); i++)
+ {
+ if ((*dataToEncode)[i] == KImcvSpaceChar)
+ dataToEncode->Des()[i] = KImcvUnderScore;
+ }
+ iQPCodec.Encode(*dataToEncode, aEncodedWord);
+ }
+ else
+ aEncodedWord.Copy(*dataToEncode);
+
+ CleanupStack::PopAndDestroy(); // dataToEncode
+ }
+
+
+TInt CImConvertHeader::AddEncodedWordInfoL(const TDesC8& aEncodedWord, RBuf8& aBufOut,
+ TImHeaderEncodingInfo& aInfo, const TDesC8& aCharsetName)
+ {
+ // Encoded data 'in place' in OutBuf.
+
+ // Add BEFORE encode data
+ TInt offset = aInfo.Offset();
+ TInt charsetSize = aCharsetName.Size();
+
+ // Convert based on iCharSet and iEncoding
+
+ // allocate enough space for encoded word plus extra encoding tokens
+ // KImMaxLengthForEncodedWordAndExtraEncodingTokens = size of '?=' + '?' + ('B' or 'Q') + '?' + '?=' + ' '
+ aBufOut.ReAllocL(aBufOut.MaxSize() + KImMaxLengthForEncodedWordAndExtraEncodingTokens + charsetSize + aEncodedWord.Size());
+ aBufOut.Insert( offset, KImcvEncodedWordStart);
+
+ // KImcvEncodedWordStart = 2
+ // Other numerical values are from the encoded word characters
+ // =? .. ?.. ? .. ?=
+
+ aBufOut.Insert( offset + 2, aCharsetName);
+ aBufOut.Insert( offset + 2 + charsetSize, KImcvQuestionMarkString);
+
+
+ if (aInfo.EncodingType() == TImHeaderEncodingInfo::EBase64)
+ {
+ aBufOut.Insert( offset + 2 + charsetSize+1, KImcvB);
+ }
+ else
+ {
+ aBufOut.Insert( offset + 2 + charsetSize+1, KImcvQ);
+ }
+
+ aBufOut.Insert( offset + 2 + charsetSize+2, KImcvQuestionMarkString);
+
+ offset += 2 + charsetSize + 3;
+
+ aBufOut.Insert( offset, aEncodedWord );
+
+ aBufOut.Insert( offset + aEncodedWord.Length(), KImcvEncodedWordEnd);
+
+ TInt returnOffset = offset + aEncodedWord.Length() + 2;
+
+ if (aInfo.AddSpace())
+ {
+ aBufOut.Insert( aInfo.Offset(), KImcvSpace);
+
+ returnOffset++;
+ }
+
+ // Return end of encoding offset.
+ return returnOffset;
+ }
+
+
+
+// Check aData to see if it has any partial 'encoded-word's.
+// ie a string of the gotm '=? ... ? ... ?=' which is incomplete.
+// Return length of new string, up to the start of the partial encoded word.
+//
+EXPORT_C TBool CImConvertHeader::FindEncodedWord(TPtrC8& aData, TInt& aInit, TInt& rStart, TInt& rEnd)
+ {
+ TBool found = EFalse;
+
+ TPtrC8 data = aData.Mid(aInit);
+ rStart = data.Find(KImcvEncodedWordStart);
+ rEnd = data.Length();
+ if (rStart != KErrNotFound)
+ {
+ found = ETrue;
+
+ TInt i;
+ TInt j = 0;
+
+ // Check for the three question marks
+ for (i = rStart+2; i < data.Length(); i++)
+ {
+ if (data[i] == KImcvQuestionMark)
+ j++;
+ if (j == 3)
+ break;
+ }
+
+ if (j != 3)
+ found = EFalse; // Have encountered an incomplete encoded-word
+
+ // Check last ? is followed by =
+ rEnd = i+1;
+ if ( rEnd > data.Length() || data[rEnd] != KImcvEquals )
+ found = EFalse; // Have encountered an incomplete encoded-word
+ } // if
+
+ return found;
+ }
+
+
+TBool CImConvertHeader::IsAscii( TUint aChar ) const
+ {
+ return ( ((aChar >= 32) && (aChar <= 126)));
+ };
+
+// function for adding 8 bit descriptor onto a 16bit descritpr.
+//
+void CImConvertHeader::Append(TDes& aBuffer, const TDesC8& aAddition)
+//----------------------------------------------------------------------------------------
+ {
+ TInt addLen = aAddition.Length();
+ TInt bufLen = aBuffer.Length();
+
+ aBuffer.SetLength(bufLen+addLen);
+ for(TInt i = 0; i < addLen; i++)
+ aBuffer[bufLen+i] = aAddition[i];
+ }
+
+
+void CImConvertHeader::Insert(TDes8& aBuffer, const TDesC16& aInsert)
+ {
+ TInt addLen = aInsert.Length();
+ TInt bufLen = aBuffer.Length();
+ TInt origAddLen=addLen;
+
+ aBuffer.SetLength(bufLen+addLen);
+
+
+ while (bufLen > addLen)
+ {
+ aBuffer[bufLen+addLen-1] = aBuffer[bufLen-1];
+ bufLen--;
+ }
+
+ while (addLen > bufLen)
+ {
+ aBuffer[addLen-1] = (TUint8) aInsert[addLen-1];
+ addLen--;
+ }
+
+ // Assert bufLen==addLen
+ while(bufLen)
+ {
+ aBuffer[bufLen+origAddLen-1] = aBuffer[bufLen-1];
+ aBuffer[bufLen-1] = (TUint8) aInsert[bufLen-1];
+ bufLen--;
+ }
+
+
+ }
+
+
+