email/pop3andsmtpmtm/servermtmutils/src/IMCVCODC.CPP
changeset 0 72b543305e3a
child 19 7e4e4bcc75b6
equal deleted inserted replaced
-1:000000000000 0:72b543305e3a
       
     1 // Copyright (c) 1999-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 "IMCVCODC.H"
       
    18 #include "IMUTDLL.H"
       
    19 #include "IMCVSEND.H"
       
    20 
       
    21 const TInt8 AsciiToBase64[80]=
       
    22 	{
       
    23 	 62, -1, -1, -1, 63, 52, 53, 54, 55, 56,
       
    24 	 57, 58, 59, 60, 61, -1, -1, -1, 64, -1,
       
    25 	 -1, -1,  0,  1,  2,  3,  4,  5,  6,  7,
       
    26 	  8,  9, 10, 11, 12, 13, 14, 15, 16, 17,
       
    27 	 18, 19, 20, 21, 22, 23, 24, 25, -1, -1,
       
    28 	 -1, -1, -1, -1, 26, 27, 28, 29, 30, 31,
       
    29 	 32, 33, 34, 35, 36, 37, 38, 39, 40, 41,
       
    30 	 42, 43, 44, 45, 46, 47, 48, 49, 50, 51
       
    31 	};
       
    32 
       
    33 const TInt8 Base64ToAscii[65]=
       
    34 	{
       
    35 	 65, 66, 67, 68, 69, 70, 71, 72, 73, 74,
       
    36 	 75, 76, 77, 78, 79, 80, 81, 82, 83, 84,
       
    37 	 85, 86, 87, 88, 89, 90, 97, 98, 99,100,
       
    38 	101,102,103,104,105,106,107,108,109,110,
       
    39 	111,112,113,114,115,116,117,118,119,120,
       
    40 	121,122, 48, 49, 50, 51, 52, 53, 54, 55,
       
    41 	 56, 57, 43, 47, 61 
       
    42 	};
       
    43 
       
    44 const TInt8 KImcvLookUpStartOffset = 43;
       
    45 const TUint8 KImcvConvEquals = '=';
       
    46 
       
    47 const TInt KImMaxLengthForEncodedWordAndExtraEncodingTokens = 9;
       
    48 
       
    49 // Define the maximum length that one encoded character should occupy.
       
    50 // For certain encoding schemes such as Japanese, a single unicode character
       
    51 // may need a multi character string to represent it when it is sent as part
       
    52 // of an email header. This constant defines a maximum length for that string.
       
    53 // The value is based on the maximum length for a Japanese character
       
    54 const TInt KImMaxLengthForEncodedChar = 8;
       
    55 
       
    56 
       
    57 //---------------------------------------------------------------------------------
       
    58 //              Class TImNoCodec Functions
       
    59 //---------------------------------------------------------------------------------
       
    60 
       
    61 
       
    62 //
       
    63 TInt TImCodecNull::Encode( const TDesC8& aSrcString, TDes8& rDestString)
       
    64 	{
       
    65 	rDestString.Copy(aSrcString);
       
    66 	return 0;
       
    67 	}
       
    68 
       
    69 //	
       
    70 TBool TImCodecNull::Decode( const TDesC8& aInputLine, TDes8& rOutputLine)
       
    71 	{
       
    72 	rOutputLine.Copy(aInputLine);
       
    73 	return ETrue;
       
    74 	}
       
    75 
       
    76 
       
    77 
       
    78 //---------------------------------------------------------------------------------
       
    79 //              Class TImCodecQP Functions
       
    80 //
       
    81 //			Utility class, providing encoding/decoding functions for :
       
    82 //			Quotable-printable, Base64 & UU.
       
    83 //			Input/output consisting of 8bit strings.
       
    84 //---------------------------------------------------------------------------------
       
    85 
       
    86 //
       
    87 EXPORT_C TImCodecQP::TImCodecQP() : iPlainCharList(TPtrC8()), iEncodeCharList(TPtrC8())
       
    88 	{
       
    89 	iQPCharacter=KImcvEquals;
       
    90 	}
       
    91 
       
    92 //
       
    93 TBool TImCodecQP::SmartBreak( TInt written, const TDesC8& pSource )
       
    94 	{
       
    95 	TLex8 source( pSource );
       
    96 
       
    97 	// only check for whether we should break if the current char is breakable
       
    98 	if ( !IsBreakable(source.Peek()) )
       
    99 		return EFalse;
       
   100 
       
   101  	// scan ahead looking for the next breakable char.
       
   102 
       
   103 	source.Inc();
       
   104 	TBool found = EFalse;
       
   105 	TInt encodingOffset=(IsPlain(source.Peek()) ? 0 : 2);
       
   106 	while ( !found && !source.Eos() )
       
   107 		{
       
   108 		found = IsBreakable(source.Peek());
       
   109 		if (!found)
       
   110 			{
       
   111 			encodingOffset+=(IsPlain(source.Peek()) ? 0 : 2);
       
   112 			source.Inc();
       
   113 			}
       
   114 		}
       
   115 
       
   116 	// there's another breakable char before the end of the text 
       
   117 	// - we need to break now if it's too far away
       
   118 	// but only if the non-breakable text fits on a line itself.
       
   119 
       
   120 	return ((written+source.Offset()+encodingOffset) > KMaxIMailBodyLineLength-4);
       
   121 	}
       
   122 
       
   123 //
       
   124 EXPORT_C TInt TImCodecQP::Encode( const TDesC8& aInputLine, TDes8& rOutputLine)
       
   125 	{
       
   126 	 // number of characters written to the current line.
       
   127 	TInt written=0; 
       
   128 
       
   129 	// Used to check we do not 'fold' a line after encountering an ESC character.
       
   130 	TInt escapeChar=0;
       
   131 
       
   132 	// number of characters introduced into the line by the encoding mechanism.
       
   133 	TInt localPaddingCount=0; 
       
   134 	
       
   135 	TChar nextChar=0;
       
   136 
       
   137 	// buffer used for preparing the hex encoding of a non-printable char
       
   138 	TBuf8<5> formatted; 
       
   139 	
       
   140 	TLex8 lexSource(aInputLine);
       
   141 	TDes8& ptr = rOutputLine;
       
   142 	TInt ptrEnd = ptr.MaxLength();
       
   143 
       
   144 	if (!lexSource.Eos())
       
   145 		{
       
   146 		lexSource.Get();
       
   147 		nextChar = lexSource.Peek();
       
   148 		lexSource.Inc(-1);
       
   149 		}
       
   150 
       
   151 	while (written<KImMailMaxBufferSize-2 && !lexSource.Eos())
       
   152 		{
       
   153 		if (written>=KMaxIMailBodyLineLength-3 && !escapeChar)
       
   154 			{
       
   155 			// force a soft line break.
       
   156 			__ASSERT_ALWAYS( ptr.Length()+4< ptr.MaxLength(), gPanic(KPanicDescriptorToSmall) );
       
   157 			ptr.Append(iQPCharacter);
       
   158 			ptr.Append(KImcvCRLF);
       
   159 			written+=3; localPaddingCount+=3;
       
   160 			break;
       
   161 			}
       
   162 
       
   163 		TChar peek = lexSource.Peek();
       
   164 
       
   165 		if (peek==KImcvESC)
       
   166 			escapeChar=3;
       
   167 
       
   168 		if ( SmartBreak(written,lexSource.Remainder()) && !escapeChar)
       
   169 			{
       
   170 			AddSoftLineBreak( ptr, localPaddingCount, written);
       
   171 			break;
       
   172 			}
       
   173 		else if ( IsPlain(peek) && peek!=KImcvSP && peek!=KImcvEquals )
       
   174 			// simple case, printable character
       
   175 			{
       
   176 			__ASSERT_ALWAYS( ptr.Length()+1<ptrEnd, gPanic(KPanicDescriptorToSmall) );
       
   177 			ptr.Append(peek);
       
   178 			written++;
       
   179 			}
       
   180 		else if ( peek==KImcvTab || peek==KImcvSP )
       
   181 			// Tab or space, need to check for immediate EOL so we can keep the space character
       
   182 			{
       
   183 			TChar thisChar =lexSource.Get();
       
   184 			TChar nextChar =(lexSource.Eos() ? (TChar)0 : lexSource.Get());
       
   185 
       
   186 			if (nextChar==KImcvCR && lexSource.Peek()==KImcvLF)
       
   187 				// Encode space, as EOL follows.
       
   188 				{
       
   189 				__ASSERT_ALWAYS( ptr.Length()+5<ptrEnd, gPanic(KPanicDescriptorToSmall) );
       
   190 				formatted.Format( KImcvQPFormatString, (TUint) thisChar );
       
   191 				formatted.UpperCase();
       
   192 				ptr.Append( formatted );
       
   193 
       
   194 				// also skip EOL the characters we just allowed for
       
   195 				written+=5;
       
   196 				localPaddingCount+=2;
       
   197 				break;
       
   198 				}
       
   199 			else
       
   200 				// no EOL, just carry on after the whitespace
       
   201 				{
       
   202 				__ASSERT_ALWAYS( ptr.Length()+1<ptrEnd, gPanic(KPanicDescriptorToSmall) );
       
   203 				ptr.Append( thisChar );
       
   204 				written++;
       
   205 				lexSource.Inc(-1);
       
   206 				if (nextChar)
       
   207 					lexSource.Inc(-1);
       
   208 				}
       
   209 			}
       
   210 		else if (peek==KImcvCR && nextChar==KImcvLF)
       
   211 			// Do not encode.
       
   212 			{
       
   213 			__ASSERT_ALWAYS( ptr.Length()+2<ptrEnd, gPanic(KPanicDescriptorToSmall) );
       
   214 			ptr.Append(KImcvCRLF);
       
   215 			written+=2;
       
   216 			lexSource.Inc();
       
   217 			break;
       
   218 			}
       
   219 		else if ( (TUint8)peek==iQPCharacter )
       
   220 			// '=' in source text
       
   221 			{
       
   222 			__ASSERT_ALWAYS( ptr.Length()+3<ptrEnd, gPanic(KPanicDescriptorToSmall) );
       
   223 			ptr.Append( KImcvQPEqualsSign );
       
   224 			written += 3;
       
   225 			localPaddingCount+=2;
       
   226 			}
       
   227 		else if (peek==KImcvTab || peek==KImcvHyphen || peek==KImcvSP)
       
   228 			{
       
   229 			__ASSERT_ALWAYS( ptr.Length()+1<ptrEnd, gPanic(KPanicDescriptorToSmall) );
       
   230 			ptr.Append( peek );
       
   231 			written++;
       
   232 			}
       
   233 		else
       
   234 			// non-printable char, must encode with Hex value
       
   235 			{
       
   236 			__ASSERT_ALWAYS( ptr.Length()+3<ptrEnd, gPanic(KPanicDescriptorToSmall) );
       
   237 			formatted.Format( KImcvQPEncoded, (TUint) peek );
       
   238 			formatted.UpperCase();
       
   239 			ptr.Append(formatted);
       
   240 			written += 3;
       
   241 			localPaddingCount += 2;
       
   242 			}
       
   243 		
       
   244 		// advance to next source character	
       
   245 		lexSource.Inc();
       
   246 		if (escapeChar)
       
   247 			escapeChar--;
       
   248 
       
   249 		// check whether we should give up without creating all the output
       
   250 		// non-quotable char to come & we're nearly at max length.
       
   251 
       
   252 		TChar thisChar = lexSource.Get();
       
   253 
       
   254 		// just in case we're pointing at the last character
       
   255 		nextChar = (lexSource.Eos() ? (TChar)0 : lexSource.Peek());
       
   256 		if (thisChar != 0)
       
   257 			lexSource.Inc(-1);
       
   258 
       
   259 		} // while
       
   260 
       
   261 	return written-localPaddingCount;
       
   262 	}
       
   263 
       
   264 //
       
   265 EXPORT_C TInt TImCodecQP::Decode( const TDesC8& aSrcString, TDes8& rDestString )
       
   266 	{
       
   267 	TInt error = KErrNone;
       
   268 
       
   269 	__ASSERT_DEBUG(aSrcString.Length(), gPanic(KPanicInvalidSMTPLine));
       
   270 
       
   271 	rDestString = KNullDesC8;
       
   272 
       
   273 	TPtrC8 source( aSrcString.Ptr(), aSrcString.Length() );
       
   274 	const TUint8* pSource = source.Ptr();
       
   275 	const TUint8* pEnd = pSource+aSrcString.Length();
       
   276 	
       
   277 	// find out if this is a blank line, if so then we'll add a paragraph delimiter instead
       
   278 	// assume it's blank and then look for non-blank characters
       
   279 	// avoid the CRLF at the end of the line (we know it's there thanks to the assertion above)
       
   280 
       
   281 	TBool blankLine = ETrue; 
       
   282 	while (pSource < pEnd-2) 
       
   283 		{
       
   284 		if (*pSource!=KImcvSP && *pSource!=KImcvTab)
       
   285 			{
       
   286 			blankLine = EFalse;
       
   287 			break;
       
   288 			}
       
   289 		pSource++;
       
   290 		}
       
   291 
       
   292 	if ( blankLine )
       
   293 		{
       
   294 		rDestString.Copy( aSrcString );
       
   295 		return KErrNone;
       
   296 		}
       
   297 
       
   298 	TInt outputLength=0;
       
   299 	TUint8 loBits;
       
   300 	TUint8 hiBits;
       
   301 	TUint8 asciiValue;
       
   302 	pSource = source.Ptr();	// reset to start of source data
       
   303 	const TUint8 zero = '0';
       
   304 	const TUint8 alphaAdjust = 55;  // 'A' is ascii 65 so we need to subtract 55 from 
       
   305 									// alphabetical hex digits to get their numeric value
       
   306 	while( pSource < pEnd )
       
   307 		{
       
   308 		if (*pSource != iQPCharacter )
       
   309 			{
       
   310 			//  Quoted character or Attachment bound, just bung it on & move to the next one
       
   311 			// *ptr++ = *pSource;
       
   312 			outputLength++;
       
   313 			rDestString.Append( *pSource );
       
   314 			}
       
   315 		else	// check for encoded character
       
   316 			{
       
   317 			// start looking at the next two characters, if they are there.
       
   318 
       
   319 			if ( pSource+2 < pEnd )
       
   320 				{
       
   321 				pSource++;
       
   322 
       
   323 				// check for '=' at EOL => this is a soft break, so remove it
       
   324 				if (*pSource != KImcvCR) 
       
   325 					{
       
   326 					if(*pSource != KImcvLF) 
       
   327 						{
       
   328 					 	 // now decode hex value into ASCII code : hi-order bits come first
       
   329 						 hiBits = (TUint8)(0x0F & (IsDigit( *pSource ) ? (TUint8)(*pSource-zero) : (TUint8)(*pSource-alphaAdjust)));
       
   330 						 pSource++;
       
   331 						 loBits = (TUint8)(0x0F & (IsDigit( *pSource ) ? (TUint8)(*pSource-zero) : (TUint8)(*pSource-alphaAdjust)));
       
   332 						 asciiValue = (TUint8)( (hiBits<<4) + loBits);
       
   333 						 // bung the character thus formed onto the decoded string
       
   334 						 rDestString.Append( asciiValue );
       
   335 						 // *ptr++ = asciiValue;
       
   336 						 outputLength++;
       
   337 						}
       
   338 					}
       
   339 				else
       
   340 					{
       
   341 					pSource++;
       
   342 					if(*pSource != KImcvLF)
       
   343 						{
       
   344 						error=KErrCorrupt;
       
   345 						pSource-=2;
       
   346 						rDestString.Append( *pSource );
       
   347 						pSource++;
       
   348 						rDestString.Append( *pSource );
       
   349 						pSource++;
       
   350 						outputLength+=2;
       
   351 						}
       
   352 					}
       
   353 				}
       
   354 			else
       
   355 				{
       
   356 				// copy the rest of the data & use up the input string in the process.
       
   357 
       
   358 				while (pSource < pEnd)
       
   359 					{
       
   360 					error=KErrCorrupt; // not QP compliant
       
   361 					//*ptr++ = *pSource++;
       
   362 					outputLength++;
       
   363 					rDestString.Append( *pSource );
       
   364 					pSource++;
       
   365 					}
       
   366 				}
       
   367 			} // check for '=' char
       
   368 		
       
   369 		pSource++;  // next source charactery
       
   370 	} // while
       
   371 
       
   372 	rDestString.SetLength(outputLength);
       
   373 
       
   374 	return error;
       
   375 	}
       
   376 
       
   377 
       
   378 // Not used. Remove in 6.3
       
   379 //
       
   380 EXPORT_C TInt TImCodecQP::EncodeRichText( const TDesC8& aInputLine, TDes8& rOutputLine)
       
   381 	{
       
   382 	TInt written=0;  // number of characters written to the current line
       
   383 	TInt localPaddingCount=0; // number of characters introduced into the line by the encoding mechanism
       
   384 	
       
   385 	// buffer used for preparing the hex encoding of a non-printable char
       
   386 	TBuf8<5> formatted; 
       
   387 	
       
   388 	TLex8 lexSource(aInputLine);
       
   389 	TDes8& ptr = rOutputLine;
       
   390 	TInt ptrEnd = ptr.MaxLength();
       
   391 
       
   392 	while (written < KMaxIMailBodyLineLength-3 &&!lexSource.Eos())
       
   393 		{
       
   394 		if ( SmartBreak(written,lexSource.Remainder()) )
       
   395 			{
       
   396 			AddSoftLineBreak(ptr, localPaddingCount, written);
       
   397 			break;
       
   398 			}
       
   399 
       
   400 		TChar peek = lexSource.Peek();
       
   401 		if ( IsPlain(peek)  && peek!=KImcvSP )
       
   402 			// simple case, printable character
       
   403 			{
       
   404 			__ASSERT_ALWAYS( ptr.Length()+1<ptrEnd, gPanic(KPanicDescriptorToSmall) );
       
   405 			ptr.Append(peek);
       
   406 			written++;
       
   407 			}
       
   408 		else if ( peek==KImcvTab || peek==KImcvSP )
       
   409 			// Tab or space, need to check for immediate EOL so we can keep the space character
       
   410 			{
       
   411 			TChar thisChar = (lexSource.Eos() ? (TChar)0 : lexSource.Get());
       
   412 
       
   413 			if ( lexSource.Peek()==ETextParagraphDelimiter )
       
   414 				{
       
   415 				__ASSERT_ALWAYS( ptr.Length()+5<ptrEnd, gPanic(KPanicDescriptorToSmall) );
       
   416 				formatted.Format( KImcvQPFormatString, (TUint) thisChar );
       
   417 				formatted.UpperCase();
       
   418 				ptr.Append( formatted );
       
   419 				ptr.Append(KImcvCRLF);
       
   420 
       
   421 				// also skip EOL the characters we just allowed for
       
   422 				written+=7;
       
   423 				localPaddingCount+=4;
       
   424 
       
   425 				// advance to next source character	
       
   426 				lexSource.Inc();
       
   427 				break;
       
   428 				}
       
   429 			else
       
   430 				// no EOL, just carry on after the whitespace
       
   431 				{
       
   432 				__ASSERT_ALWAYS( ptr.Length()+1<ptrEnd, gPanic(KPanicDescriptorToSmall) );
       
   433 				ptr.Append( thisChar );
       
   434 				written++;
       
   435 				lexSource.Inc(-1);
       
   436 				}
       
   437 			}
       
   438 		else if ( (TUint8)peek==iQPCharacter )
       
   439 			// '=' in source text
       
   440 			{
       
   441 			//is there enough space to encoded a char and put a soft break on the end.
       
   442 			if(written > KMaxIMailBodyLineLength-6)
       
   443 				break;
       
   444 
       
   445 			__ASSERT_ALWAYS( ptr.Length()+3<ptrEnd, gPanic(KPanicDescriptorToSmall) );
       
   446 			ptr.Append( KImcvQPEqualsSign );
       
   447 			written += 3;
       
   448 			localPaddingCount+=2;
       
   449 			}
       
   450 		else if (peek<KImcvSP  && peek!=KImcvLF && peek !=KImcvCR )
       
   451 			// check for CEditableText control character
       
   452 			{
       
   453 			TChar replacement = ReplacementChar(peek);
       
   454 			if (replacement)
       
   455 				{
       
   456 				__ASSERT_ALWAYS( ptr.Length()+1<ptrEnd, gPanic(KPanicDescriptorToSmall) );
       
   457 				ptr.Append( replacement );
       
   458 				written++;
       
   459 				}
       
   460 			else if ( lexSource.Peek()==ETextParagraphDelimiter )
       
   461 				{
       
   462 				ptr.Append(KImcvCRLF);
       
   463 				written+=2;
       
   464 				localPaddingCount+=1;
       
   465 				break;
       
   466 				}
       
   467 			else
       
   468 				localPaddingCount-=1;
       
   469 			}
       
   470 		else
       
   471 			// non-printable char, must encode with Hex value
       
   472 			{
       
   473 			//is there enough space to encoded a char and put a soft break on the end
       
   474 			if(written > KMaxIMailBodyLineLength-6)
       
   475 				{
       
   476 				if (written+3 < KMaxIMailBodyLineLength)
       
   477 					{
       
   478 					AddSoftLineBreak(ptr, localPaddingCount, written);
       
   479 					}
       
   480 				break;
       
   481 				}
       
   482 			__ASSERT_ALWAYS( ptr.Length()+3<ptrEnd, gPanic(KPanicDescriptorToSmall) );
       
   483 			formatted.Format( KImcvQPEncoded, (TUint) peek );
       
   484 			formatted.UpperCase();
       
   485 			ptr.Append(formatted);
       
   486 			written += 3;
       
   487 			localPaddingCount += 2;
       
   488 			}
       
   489 		
       
   490 		// advance to next source character	
       
   491 		lexSource.Inc();
       
   492 
       
   493 		// check whether we should give up without creating all the output
       
   494 		// non-quotable char to come & we're nearly at max length.
       
   495 
       
   496 		TChar thisChar = lexSource.Get();
       
   497 		// just in case we're pointing at the last character
       
   498 		TChar nextChar = (lexSource.Eos() ? (TChar)0 : lexSource.Peek());
       
   499 		if (thisChar != 0)
       
   500 			lexSource.Inc(-1);
       
   501 
       
   502 		if ( !IsPlain( thisChar ) && (written >= KMaxIMailBodyLineLength-2) 
       
   503 			|| ( thisChar==KImcvSP ||  thisChar==KImcvTab) 
       
   504 			&& nextChar==CEditableText::EParagraphDelimiter 
       
   505 			&& (written >= KMaxIMailBodyLineLength-3) ) // whitespace just before linebreak
       
   506 			break;
       
   507 		} // while
       
   508 
       
   509 	rOutputLine.SetLength( written );
       
   510 
       
   511 	return 	(written-localPaddingCount);
       
   512 	}
       
   513 
       
   514 
       
   515 EXPORT_C TInt TImCodecQP::DecodeRichText( const TDesC8& aSrcString, TDes& rDestString )
       
   516 	{
       
   517 	TInt error = KErrNone;
       
   518 
       
   519 	__ASSERT_DEBUG(aSrcString.Length()>=2&&aSrcString[aSrcString.Length()-2]==KImcvCR&&aSrcString[aSrcString.Length()-1]==KImcvLF, gPanic(KPanicInvalidSMTPLine));
       
   520 
       
   521 	rDestString = KNullDesC;
       
   522 
       
   523 	TPtrC8 source( aSrcString.Ptr(), aSrcString.Length() );
       
   524 	const TUint8* pSource = source.Ptr();
       
   525 	const TUint8* pEnd = pSource+aSrcString.Length();
       
   526 	
       
   527 	// find out if this is a blank line, if so then we'll add a paragraph delimiter instead
       
   528 	TBool blankLine = ETrue; // assume it's blank and then look for non-blank characters
       
   529 	while (pSource < pEnd-2) // avoid the CRLF at the end of the line (we know it's there thanks to the assertion above)
       
   530 		{
       
   531 		if (*pSource!=KImcvSP && *pSource!=KImcvTab)
       
   532 			{
       
   533 			blankLine = EFalse;
       
   534 			break;
       
   535 			}
       
   536 		else
       
   537 			pSource++;
       
   538 		}
       
   539 
       
   540 	if ( blankLine )
       
   541 		rDestString.Copy( aSrcString )
       
   542 		;	
       
   543 	else
       
   544 		{
       
   545 		TInt outputLength=0;
       
   546 		TUint8 loBits;
       
   547 		TUint8 hiBits;
       
   548 		TUint8 asciiValue;
       
   549 		pSource = source.Ptr();	// reset to start of source data
       
   550 		const TUint8 zero = '0';
       
   551 		const TUint8 alphaAdjust = 55;  // 'A' is ascii 65 so we need to subtract 55 from 
       
   552 										// alphabetical hex digits to get their numeric value
       
   553 		while( pSource < pEnd )
       
   554 			{
       
   555 			// check for encoded character
       
   556 			if (*pSource == iQPCharacter )
       
   557 				{
       
   558 				// start looking at the next two characters, if they are there
       
   559 				if ( pSource+2 < pEnd )
       
   560 					{
       
   561 					pSource++;
       
   562 					// check for '=' at EOL => this is a soft break, so remove it
       
   563 					if (*pSource != KImcvCR) 
       
   564 						{
       
   565 						// now decode hex value into ASCII code : hi-order bits come first
       
   566 						hiBits = (TUint8)(0x0F & (IsDigit( *pSource ) ? (TUint8)(*pSource-zero) : (TUint8)(*pSource-alphaAdjust)));
       
   567 						pSource++;
       
   568 						loBits = (TUint8)(0x0F & (IsDigit( *pSource ) ? (TUint8)(*pSource-zero) : (TUint8)(*pSource-alphaAdjust)));
       
   569 						asciiValue = (TUint8)( (hiBits<<4) + loBits);
       
   570 						// bung the character thus formed onto the decoded string
       
   571 						rDestString.Append( asciiValue );
       
   572 						// *ptr++ = asciiValue;
       
   573 						outputLength++;
       
   574 						}
       
   575 					else
       
   576 						{
       
   577 						pSource++;
       
   578 						if(*pSource != KImcvLF)
       
   579 							{
       
   580 							error=KErrCorrupt;
       
   581 							pSource-=2;
       
   582 							rDestString.Append( *pSource );
       
   583 							pSource++;
       
   584 							rDestString.Append( *pSource );
       
   585 							pSource++;
       
   586 							outputLength+=2;
       
   587 							}
       
   588 						}
       
   589 					}
       
   590 				else
       
   591 					{
       
   592 					// copy the rest of the data & use up the input string in the process
       
   593 					while (pSource < pEnd)
       
   594 						{
       
   595 						error=KErrCorrupt; // not QP compliant
       
   596 						//*ptr++ = *pSource++;
       
   597 						outputLength++;
       
   598 						rDestString.Append( *pSource );
       
   599 						pSource++;
       
   600 						}
       
   601 					}
       
   602 				} // check for '=' char
       
   603 			else
       
   604 				{
       
   605 				if ( *pSource == KImcvCR && (pSource+1 < pEnd && *(pSource+1) == KImcvLF))
       
   606 					{
       
   607 					// this is a hard CRLF, so replace it with a Paragraph Delimiter
       
   608 					
       
   609 					// *ptr++ = ETextParagraphDelimiter;
       
   610 					rDestString.Append( (TChar) CEditableText::EParagraphDelimiter );
       
   611 					outputLength++;
       
   612 					
       
   613 					// ... and skip an extra char (the LF)
       
   614 					pSource++;
       
   615 					}
       
   616 				else
       
   617 					{
       
   618 					//  Quoted character or Attachment bound, just bung it on & move to the next one
       
   619 					// *ptr++ = *pSource;
       
   620 					outputLength++;
       
   621 					rDestString.Append( *pSource );
       
   622 					}
       
   623 				}
       
   624 			// next source character
       
   625 			pSource++;
       
   626 			} // while
       
   627 		rDestString.SetLength(outputLength);
       
   628 		} // else
       
   629 	return error;
       
   630 	}
       
   631 
       
   632 
       
   633 //---------------------------------------------------------------------------------
       
   634 //              Class TImFileCodec Functions
       
   635 //---------------------------------------------------------------------------------
       
   636 	
       
   637 
       
   638 TInt TImFileCodec::PostfixNextLine(TDes8&  rOutputLine, TInt& rPaddingCount)
       
   639 	{
       
   640 	return BlankLine(rOutputLine, rPaddingCount);
       
   641 	}
       
   642 
       
   643 
       
   644 TInt TImFileCodec::PrefixNextLineL(TDes8& /* rOutputLine*/, const TFileName& /*aName*/, TInt& /*rPaddingCount*/)
       
   645 	{
       
   646 	return KImAttFinished;
       
   647 	}
       
   648 
       
   649 
       
   650 void TImFileCodec::Initialise()
       
   651 	{
       
   652 	iPostfixState=0;
       
   653 	iPrefixState=0;
       
   654 	}
       
   655 
       
   656 //---------------------------------------------------------------------------------
       
   657 //              Class TImCodecB64 Functions
       
   658 //---------------------------------------------------------------------------------
       
   659 
       
   660 
       
   661 EXPORT_C TImCodecB64::TImCodecB64(): iShiftStored(0), iMaskShiftStored(ESix)
       
   662 	{}
       
   663 
       
   664 
       
   665 // Returns ETrue if aSrcString is not long enough to decode fully, resulting in the storage of
       
   666 // the last character and requiring another aSrcString (poss 0 length) to be passed to it to 
       
   667 // clear this character. 
       
   668 // Returns EFalse if the line was decoded OK or the end of the encoded file is reached ie "="
       
   669 //
       
   670 EXPORT_C TBool TImCodecB64::Decode(const TDesC8& aSrcString, TDes8& rDestString)
       
   671 	{
       
   672 	TInt decodedInt=0;
       
   673 	TInt8 offsetChar=0;
       
   674 	TUint8 decodedChar=0;
       
   675 	 
       
   676 	// Clears the destination string
       
   677 	rDestString.Zero();
       
   678 
       
   679 	// Initialise variables
       
   680 	const TUint8* srcStringPtr=aSrcString.Ptr();
       
   681 	const TUint8* srcStringEnd=aSrcString.Length()+srcStringPtr;
       
   682 	TUint8* destStringPtr=(TUint8*)rDestString.Ptr();
       
   683 	TUint8* destStringPtrBase=destStringPtr;
       
   684 
       
   685 	TInt maskShift=iMaskShiftStored;
       
   686 	TInt shiftStorage=iShiftStored;
       
   687 	
       
   688 	// Main character process loop
       
   689 	while(srcStringPtr<srcStringEnd)	
       
   690 		{
       
   691 		offsetChar=(TInt8)(*srcStringPtr-KImcvLookUpStartOffset);
       
   692 		srcStringPtr++;
       
   693 
       
   694 		// Check for valid B64 character		
       
   695 		if((offsetChar>=0)&&(offsetChar<80))
       
   696 			{
       
   697 			// Read in next character and B64 decode
       
   698 			decodedInt=AsciiToBase64[offsetChar];
       
   699 
       
   700 			// Exits when a PAD char is reached
       
   701 			if(decodedInt==EPadChar)
       
   702 				{
       
   703 				rDestString.SetLength((TInt)(destStringPtr-destStringPtrBase));
       
   704 				return EFalse;
       
   705 				}
       
   706 
       
   707 			// Ensures the first 2 chars of 4 are received before processing
       
   708 			if(maskShift==ESix)
       
   709 				maskShift=EFour;
       
   710 			else
       
   711 				{
       
   712 				shiftStorage=shiftStorage<<ESix;
       
   713 				shiftStorage=shiftStorage|decodedInt;
       
   714 				decodedChar=(TUint8)((shiftStorage>>maskShift)&EEightBitMask);
       
   715 				
       
   716 				if((maskShift-=ETwo)<EZero)
       
   717 					maskShift=ESix; 
       
   718 				
       
   719 				*destStringPtr++=decodedChar;
       
   720 				}
       
   721 			shiftStorage=decodedInt;
       
   722 			}
       
   723 		}
       
   724 	iShiftStored=shiftStorage;
       
   725 	iMaskShiftStored=maskShift;
       
   726 	
       
   727 	rDestString.SetLength((TInt)(destStringPtr-destStringPtrBase));
       
   728 	
       
   729 	return maskShift<ESix;
       
   730 	}
       
   731 
       
   732 EXPORT_C TInt TImCodecB64::Encode(const TDesC8& aSrcString, TDes8& rDestString)
       
   733 	{
       
   734 	return DoEncode(aSrcString, rDestString, EFalse);
       
   735 	}
       
   736 
       
   737 EXPORT_C void TImCodecB64::Initialise()
       
   738 	{
       
   739 	iMaskShiftStored=ESix;
       
   740 	}
       
   741 
       
   742 TInt TImCodecB64::DoEncode(const TDesC8& aSrcString, TDes8& rDestString, TBool aInsertLineBreaks)
       
   743 	{
       
   744 	// Clears the destination string
       
   745 	rDestString.Zero();
       
   746 	
       
   747 	// Initialise variables
       
   748 	const TUint8* srcStringPtr=aSrcString.Ptr();
       
   749 	const TUint8* srcStringEnd=aSrcString.Length()+srcStringPtr;
       
   750 	TUint8* destStringPtr=(TUint8*)rDestString.Ptr();
       
   751 	TUint8* destStringPtrBase=destStringPtr;
       
   752 
       
   753 	TInt character=0;
       
   754 	TUint8 encodedChar=0;
       
   755 	TInt charStorage=0;
       
   756  	TInt maskShift=EZero;
       
   757 	TInt destStringCharNum = 0;
       
   758 
       
   759 	while(srcStringPtr<=srcStringEnd)
       
   760 		{
       
   761 		// maskShift is used as a char read counter
       
   762 		if(maskShift==ESix)
       
   763 			{
       
   764 			// If the 3rd char read is also the last char then the while loop
       
   765 			// is broken on the next check.
       
   766 			if(srcStringPtr==srcStringEnd)
       
   767 				srcStringPtr++;
       
   768 			maskShift=EZero;
       
   769 			character=0;   
       
   770 			}
       
   771 		else
       
   772 			{
       
   773 			if(srcStringPtr==srcStringEnd)
       
   774 				character=0;
       
   775 			else
       
   776 				character=*srcStringPtr;
       
   777 
       
   778 			srcStringPtr++;
       
   779 			// Shifts charStorage ready for the next char
       
   780 			charStorage=charStorage<<8;
       
   781 			maskShift+=ETwo;
       
   782 			}
       
   783 		charStorage=charStorage|character;
       
   784 		// Shifts the mask to the correct bit location
       
   785 		// Masks (AND's) the valid bits from charStorage
       
   786 		// Shifts the valid bits into the low order 8bits
       
   787 		// Converts to BASE64 char, Casts the result to an unsigned char (which it should be ?....I hope)
       
   788 		encodedChar=(TUint8)Base64ToAscii[((charStorage>>maskShift)&ESixBitMask)];
       
   789 
       
   790 		*destStringPtr++=encodedChar;
       
   791 		destStringCharNum++;
       
   792 
       
   793 		// Add a CRLF every KMaxB64EncodedCharsPerLine characters so as not to exceed the line length
       
   794 		// limitation specified in RFC 2822.
       
   795 		if (aInsertLineBreaks && destStringCharNum == KMaxB64EncodedCharsPerLine)
       
   796 			{
       
   797 			destStringCharNum = 0;
       
   798 			*destStringPtr++ = '\r';
       
   799 			*destStringPtr++ = '\n';
       
   800 			}
       
   801 		}
       
   802 	
       
   803 	// Check for not enough chars and pad if required
       
   804 	if (maskShift==EFour)
       
   805 		{
       
   806 		*destStringPtr++=KImcvConvEquals;
       
   807 		*destStringPtr++=KImcvConvEquals;
       
   808 		}
       
   809 	else
       
   810 		if(maskShift==ESix)
       
   811 			*destStringPtr++=KImcvConvEquals;	
       
   812 			
       
   813 	rDestString.SetLength((TInt)(destStringPtr-destStringPtrBase));
       
   814 	return ((TInt)(srcStringPtr-srcStringEnd));
       
   815 	}
       
   816 
       
   817 TInt TImCodecB64WithLineBreaks::Encode(const TDesC8& aSrcString, TDes8& rDestString)
       
   818    	{
       
   819 	return DoEncode(aSrcString, rDestString, ETrue);
       
   820    	}
       
   821 
       
   822 //---------------------------------------------------------------------------------
       
   823 //              Class TImCodecUU Functions
       
   824 //---------------------------------------------------------------------------------
       
   825 
       
   826 
       
   827 EXPORT_C TImCodecUU::TImCodecUU()
       
   828 	{}
       
   829 
       
   830 
       
   831 // returns ETrue if aSrcString is not long enough, relative to its line length character.
       
   832 // or if an invalid UU encoded character is found.
       
   833 // returns EFalse if the line was decoded OK
       
   834 //
       
   835 EXPORT_C TBool TImCodecUU::Decode(const TDesC8& aSrcString, TDes8& rDestString)
       
   836 	{
       
   837 	// Clears the destination string
       
   838 	rDestString.Zero();
       
   839 
       
   840 	// Initialise variables
       
   841 	const TUint8* srcStringPtr=aSrcString.Ptr();
       
   842 	TInt numEncChrs=*srcStringPtr++-ESpace;
       
   843 	TInt maskShift=ESix;
       
   844 	TInt numDecChrs=0;
       
   845 	TInt shiftStorage=0;
       
   846 	TInt character=0;
       
   847 	TUint8 decodedChar=0;
       
   848 	
       
   849 	// Checks if the srcString is atleast long enough to decode.
       
   850 	if((numEncChrs*4)>((aSrcString.Length()-1)*3)) return ETrue;
       
   851 
       
   852 	// Main character process loop
       
   853 	while(numDecChrs<numEncChrs)	
       
   854 		{
       
   855 		// Read in next character
       
   856 		character=*srcStringPtr++;
       
   857 
       
   858 		// Check for UU character validity
       
   859 		if((character<ESpace)||(character>EBackQuote)) return ETrue;
       
   860 
       
   861 		// Protocol thing		
       
   862 		if(character==EBackQuote)
       
   863 			character=ESpace;
       
   864 
       
   865 		character-=ESpace;
       
   866 		
       
   867 		// Ensures the first 2 chars of 4 are received before processing
       
   868 		if(maskShift==ESix)
       
   869 			maskShift=EFour;
       
   870 		else
       
   871 			{
       
   872 			shiftStorage=shiftStorage<<ESix;
       
   873 			shiftStorage=shiftStorage|character;
       
   874 
       
   875 			decodedChar=(TUint8)((shiftStorage>>maskShift)&EEightBitMask);
       
   876 			maskShift=((maskShift==EZero)? ESix:(maskShift-ETwo)); 
       
   877 				
       
   878 			rDestString.Append(decodedChar);
       
   879 			numDecChrs++;
       
   880 			}
       
   881 		shiftStorage=character;
       
   882 		}
       
   883 	return EFalse;
       
   884 	}
       
   885 
       
   886 
       
   887 EXPORT_C TInt TImCodecUU::Encode(const TDesC8& aSrcString, TDes8& rDestString)
       
   888 	{
       
   889 	// Clears the destination string
       
   890 	rDestString.Zero();
       
   891 	
       
   892 	// Initialise variables
       
   893 	const TUint8* srcStringPtr=aSrcString.Ptr();
       
   894 	const TInt srcLength=aSrcString.Length();
       
   895 	const TUint8* srcStringEnd=srcStringPtr+srcLength;
       
   896 	TInt charStorage=0;
       
   897 	TInt maskShift=EZero;
       
   898 	TInt character=0;
       
   899 	TUint8 encodedChar=0;
       
   900 	TInt destStringCharNum = 0;
       
   901 	TInt srcStringBytesRemaining = 0;
       
   902 
       
   903    	while(srcStringPtr<=srcStringEnd)
       
   904    		{
       
   905 		// Add unencoded length to start of line as per UU specification.
       
   906 		if (destStringCharNum == 0)
       
   907 			{
       
   908 			srcStringBytesRemaining = srcStringEnd - srcStringPtr;
       
   909 			if ( srcStringBytesRemaining < KMaxUUUnEncodedCharsPerLine ) 
       
   910 				rDestString.Append(static_cast<TUint8>(srcStringBytesRemaining) + ESpace);
       
   911 			else
       
   912 				rDestString.Append(KMaxUUUnEncodedCharsPerLine + ESpace);
       
   913 			}
       
   914 
       
   915 		if(maskShift==ESix)
       
   916 			{
       
   917 			// If the 3rd char read is also the last char then the while loop
       
   918 			// is broken on the next check.
       
   919 			if(srcStringPtr==srcStringEnd)
       
   920 				srcStringPtr++;
       
   921 			character=0;
       
   922 			maskShift=EZero;
       
   923 			}
       
   924 		else
       
   925 			{
       
   926 			if(srcStringPtr==srcStringEnd)
       
   927 				character=0;
       
   928 			else
       
   929 				character=*srcStringPtr;
       
   930 
       
   931 			srcStringPtr++;
       
   932 			charStorage=charStorage<<8;
       
   933 			maskShift+=ETwo;
       
   934 			}
       
   935 		charStorage=charStorage|character;
       
   936 		// Shifts the mask to the correct bit location
       
   937 		// Masks (AND's) the valid bits
       
   938 		// Shifts the valid bits into the low order 8bits
       
   939 		// Adds 32 (SPACE), Casts the result to an unsigned char (which it should be ?....I hope)
       
   940 		encodedChar=(TUint8)(((charStorage>>maskShift)&ESixBitMask)+ESpace);
       
   941 
       
   942 		// Protocol thing		
       
   943 		if(encodedChar==ESpace)
       
   944 			encodedChar=EBackQuote;
       
   945 
       
   946 		rDestString.Append(encodedChar);
       
   947 		++destStringCharNum;
       
   948 
       
   949 		// Add a CRLF every KMaxUUEncodedCharsPerLine characters so as not to exceed the line length
       
   950 		// limitation recommended for UUE.
       
   951 		if (destStringCharNum == KMaxUUEncodedCharsPerLine)
       
   952 			{
       
   953 			destStringCharNum = 0;
       
   954 			rDestString.Append(KImcvCRLF);
       
   955 			}
       
   956 		}
       
   957 
       
   958 	return ((TInt)(srcStringPtr-srcStringEnd));
       
   959 	}
       
   960 
       
   961 
       
   962 TInt TImCodecUU::PrefixNextLineL( TDes8& rOutputLine, const TFileName& aName, TInt& rPaddingCount )
       
   963 	{
       
   964 	rOutputLine.Append( KImcvUueStart );
       
   965 	rOutputLine.Append( KImcvUue644 );
       
   966 	AppendFilenameL( rOutputLine, aName );
       
   967 	rPaddingCount=rOutputLine.Length();
       
   968 	return 1;
       
   969 	}
       
   970 
       
   971 TInt TImCodecUU::PostfixNextLine( TDes8& rOutputLine, TInt& rPaddingCount )
       
   972 	{
       
   973 	switch( iPostfixState )
       
   974 		{
       
   975 		case EInvertedComma:
       
   976 			rOutputLine.Append( KImcvInvertedComma );
       
   977 			break;
       
   978 		case EEndString:
       
   979 			rOutputLine = KImcvUueEnd;
       
   980 			break;
       
   981 		}
       
   982 	
       
   983 	iPostfixState++;
       
   984 	rPaddingCount=rOutputLine.Length();
       
   985 
       
   986 	return (iPostfixState==EEndOfPostfix ? KImAttFinished : KErrNone);
       
   987 	}
       
   988 
       
   989 
       
   990 
       
   991 void TImCodecUU::AppendFilenameL( TDes8& rOutputLine, const TFileName& aName)
       
   992 	{
       
   993 	HBufC8* buf = HBufC8::NewLC( aName.Length() );
       
   994 	buf->Des().Copy( aName );
       
   995 	rOutputLine.Append(KImcvSpace);
       
   996 	rOutputLine.Append( *buf );
       
   997 	CleanupStack::PopAndDestroy(); // buf
       
   998 	}
       
   999 
       
  1000 
       
  1001 
       
  1002 
       
  1003 //---------------------------------------------------------------------------------
       
  1004 //              Class CImConvertHeader Functions
       
  1005 //
       
  1006 // Utility class, providing functionality for encoding/decoding header fields.
       
  1007 // Requires use of Charconv "Wrapper" class.
       
  1008 //------------------------------------------------------------------------------
       
  1009 
       
  1010 /**
       
  1011 @publishedPartner
       
  1012 @released
       
  1013 */
       
  1014 EXPORT_C CImConvertHeader* CImConvertHeader::NewL(CImConvertCharconv& aConverter)
       
  1015 	{
       
  1016 	CImConvertHeader* self = new (ELeave) CImConvertHeader (aConverter);
       
  1017 	CleanupStack::PushL(self);
       
  1018 	self->ConstructL();
       
  1019 	CleanupStack::Pop(self);
       
  1020 	return self;
       
  1021 	}
       
  1022 
       
  1023 CImConvertHeader::CImConvertHeader(CImConvertCharconv& aConverter) : 
       
  1024 	iCharConv (aConverter)
       
  1025 	{
       
  1026 	}
       
  1027 
       
  1028 CImConvertHeader::~CImConvertHeader() 
       
  1029 	{
       
  1030 	iHeader = NULL;
       
  1031 	}
       
  1032 
       
  1033 void CImConvertHeader::ConstructL() 
       
  1034 	{
       
  1035 	iQPCodec.AddEncodeChar(KImcvEncodeCharacterList);
       
  1036 
       
  1037 	// Default setting.
       
  1038 	iCharConv.PrepareToConvertToFromOurCharsetL(iCharConv.DefaultCharset());
       
  1039 	}
       
  1040 
       
  1041 EXPORT_C void CImConvertHeader::SetMessageType(TBool aIsMIME)
       
  1042 	{
       
  1043 	isMIMEMessageHeader=aIsMIME;
       
  1044 	}
       
  1045 
       
  1046 EXPORT_C void CImConvertHeader::SetOverrideCharset(TUint aCharset)
       
  1047 /**
       
  1048 Sets the override character set to use when decoding the 8 bit data. Zero
       
  1049 indicates the charset not to be used.
       
  1050 
       
  1051 @param aCharset
       
  1052 The new character set to use as an overriding character set.
       
  1053 */
       
  1054 	{
       
  1055 	iOverrideCharset = aCharset;
       
  1056 	}
       
  1057 
       
  1058 EXPORT_C TUint CImConvertHeader::OverrideCharset() const
       
  1059 /**
       
  1060 Retrieves the override character set that will be used when decoding the 8 bit
       
  1061 data. A character set value of zero indicates no overriding character set will
       
  1062 be used.
       
  1063 */
       
  1064 	{
       
  1065 	return iOverrideCharset;
       
  1066 	}
       
  1067 
       
  1068 //------------------------------------------------------------------------------
       
  1069 
       
  1070 EXPORT_C void CImConvertHeader::DecodeAllHeaderFieldsL(CImHeader& rHeader)
       
  1071 	{
       
  1072 	iHeader = &rHeader;
       
  1073 
       
  1074 	iHeader->SaveEncodedHeadersL();
       
  1075 	
       
  1076 	// If Header field does not have a Mime info, but header has encoded words, then 
       
  1077 	// we need to parse it accordingly. 
       
  1078 	TBool nonMime = EFalse; 
       
  1079 	if (!isMIMEMessageHeader) 
       
  1080 		{ 
       
  1081 		isMIMEMessageHeader = ETrue; 
       
  1082 		nonMime = ETrue; 
       
  1083 		}
       
  1084 
       
  1085 	// FROM:
       
  1086 	iEncodingInfo.SetField(TImHeaderEncodingInfo::EFrom);
       
  1087 	DecodeFieldL( rHeader.From());
       
  1088 
       
  1089 	// SUBJECT:
       
  1090 	iEncodingInfo.SetField(TImHeaderEncodingInfo::ESubject);
       
  1091 	DecodeFieldL( rHeader.Subject());
       
  1092 
       
  1093 	// REPLYTO:
       
  1094 	iEncodingInfo.SetField(TImHeaderEncodingInfo::EReplyTo);
       
  1095 	DecodeFieldL( rHeader.ReplyTo());
       
  1096 
       
  1097 	// TO:
       
  1098 	iEncodingInfo.SetField(TImHeaderEncodingInfo::ETo);
       
  1099 	DecodeRecipientListL(rHeader.ToRecipients());
       
  1100 
       
  1101 	// CC:
       
  1102 	iEncodingInfo.SetField(TImHeaderEncodingInfo::ECc);
       
  1103 	DecodeRecipientListL(rHeader.CcRecipients());
       
  1104 
       
  1105 	// BCC:
       
  1106 	iEncodingInfo.SetField(TImHeaderEncodingInfo::EBcc);
       
  1107 	DecodeRecipientListL(rHeader.BccRecipients());
       
  1108 
       
  1109 	if(nonMime) 
       
  1110 		{ 
       
  1111 		isMIMEMessageHeader = EFalse; 
       
  1112 		} 	
       
  1113 		
       
  1114 	iHeader = NULL; // iHeader is not used outside non-exported function DecodeFieldL
       
  1115 	}
       
  1116 
       
  1117 
       
  1118 void CImConvertHeader::DecodeFieldL(const TDesC& aField)
       
  1119 	{
       
  1120 	HBufC* buf = HBufC::NewLC(aField.Size());
       
  1121 	TPtr ptr(buf->Des());
       
  1122 	DecodeHeaderFieldL(aField, ptr);
       
  1123 
       
  1124 	switch (iEncodingInfo.Field())
       
  1125 		{
       
  1126 	case TImHeaderEncodingInfo::EFrom:
       
  1127 		iHeader->SetFromL(*buf);
       
  1128 		break;
       
  1129 	case TImHeaderEncodingInfo::ESubject:
       
  1130 		iHeader->SetSubjectL(*buf);
       
  1131 		break;
       
  1132 	case TImHeaderEncodingInfo::EReplyTo:
       
  1133 		iHeader->SetReplyToL(*buf);
       
  1134 		break;
       
  1135 	default:
       
  1136 		__ASSERT_DEBUG(1, User::Invariant());
       
  1137 		}
       
  1138 	CleanupStack::PopAndDestroy( ); // buf
       
  1139 	}
       
  1140 
       
  1141 
       
  1142 void CImConvertHeader::DecodeRecipientListL(CDesCArray& aArray)
       
  1143 	{
       
  1144 	HBufC* buf = NULL; 
       
  1145 	TInt i = aArray.Count();
       
  1146 	while (i--)
       
  1147 		{
       
  1148 		iEncodingInfo.SetArrayValue(i);
       
  1149 
       
  1150 		if (!(aArray[i]).Length())
       
  1151 			continue; // Should really delete them some how
       
  1152 
       
  1153 		buf = HBufC::NewLC(aArray[i].Length());
       
  1154 		TPtr ptr(buf->Des());
       
  1155 
       
  1156 		DecodeHeaderFieldL(aArray[i], ptr);
       
  1157 		aArray.Delete(i);
       
  1158 		aArray.InsertL(i, *buf);
       
  1159 
       
  1160 		CleanupStack::PopAndDestroy( ); // buf
       
  1161 		}
       
  1162 	}
       
  1163 
       
  1164 /**
       
  1165 Search for one or more encoded words in aLine
       
  1166 
       
  1167 @publishedPartner
       
  1168 @released
       
  1169 */
       
  1170 
       
  1171  EXPORT_C void CImConvertHeader::DecodeHeaderFieldL(const TDesC16& aBufIn, TDes& aBufOut)
       
  1172 
       
  1173 	{
       
  1174 	// input should be 8bit, possible loss of data otherwise.
       
  1175 	HBufC8* buffer8 = HBufC8::NewLC( aBufIn.Length() );
       
  1176 	buffer8->Des().Copy( aBufIn );
       
  1177 
       
  1178 	if (isMIMEMessageHeader)
       
  1179     	
       
  1180     	DecodeHeaderFieldL( *buffer8, aBufOut);
       
  1181 
       
  1182 	else
       
  1183 		 DecodeNonMIMEHeaderFieldL( *buffer8, aBufOut);
       
  1184 
       
  1185 
       
  1186 
       
  1187 	CleanupStack::PopAndDestroy( ); // buffer8
       
  1188 	}
       
  1189 
       
  1190 /**
       
  1191 Search for one or more encoded words in aLine
       
  1192 
       
  1193 @publishedPartner
       
  1194 @released
       
  1195 */
       
  1196  EXPORT_C void CImConvertHeader::DecodeHeaderFieldL(const TDesC8& aBufIn, TDes& aBufOut)
       
  1197 	{
       
  1198 	__ASSERT_DEBUG(aBufIn.Size() <= aBufOut.MaxSize(), User::Invariant());
       
  1199 	aBufOut.SetLength(0);
       
  1200 
       
  1201 	TBool wordExists = ETrue;
       
  1202 	TBool decoded = EFalse;
       
  1203 	TInt rem = 0;
       
  1204 	TPtrC8 encodedWord8(aBufIn);
       
  1205 	TChar QMark = KImcvQuestionMark;
       
  1206 	TInt spaces = 0;
       
  1207 	TLex8 lex(aBufIn);
       
  1208 
       
  1209 	while (wordExists)
       
  1210 		{
       
  1211 		wordExists = EFalse;
       
  1212 
       
  1213 		lex.SkipSpaceAndMark();
       
  1214 		spaces = lex.TokenLength();
       
  1215 
       
  1216 		// Get next Encoded word
       
  1217 		while (lex.Peek() != KImcvEquals && !lex.Eos())
       
  1218 			{
       
  1219 			lex.Inc();
       
  1220 			}
       
  1221 
       
  1222 		if (lex.Eos())
       
  1223 			{
       
  1224 			break;	
       
  1225 			}
       
  1226 
       
  1227 		lex.Inc();
       
  1228 		if (lex.Peek() == QMark)
       
  1229 			{
       
  1230 			// We have the start of an encoded word..
       
  1231 			// Copy over all data marked prior to word
       
  1232 			lex.Inc(-1);
       
  1233 
       
  1234 			if (spaces==lex.TokenLength())
       
  1235 				{
       
  1236 				// contiguous encoded-words, spaces removed in decoded word.
       
  1237 				iEncodingInfo.SetAddSpace(ETrue);
       
  1238 				}
       
  1239 			else
       
  1240 				{
       
  1241 				do
       
  1242 					{
       
  1243 					lex.Inc(-1);
       
  1244 					}	
       
  1245 				while (lex.Peek()==KImcvSpaceChar || lex.Peek()==KImcvTab);
       
  1246 				lex.Inc(); 	
       
  1247 				if (!lex.Eos() && 
       
  1248 					(lex.Peek()==KImcvSpaceChar || lex.Peek()==KImcvTab) ) // Get back to space
       
  1249 					{
       
  1250 					lex.Inc();	
       
  1251 					}
       
  1252 				TPtrC8 marked = lex.MarkedToken();
       
  1253 				Append(aBufOut, marked);
       
  1254 
       
  1255 				}
       
  1256 
       
  1257 			lex.SkipSpaceAndMark(); // Start of encoded word
       
  1258 
       
  1259 			//--Need to check two question marks within encoded word --
       
  1260 			lex.Inc(2);
       
  1261 			while ( lex.Peek() != QMark && !lex.Eos() )
       
  1262 				{
       
  1263 				lex.Inc();
       
  1264 				}
       
  1265 			
       
  1266 			if (lex.Peek() != QMark)
       
  1267 				{
       
  1268 				break; // incorrectly formed encoded-word
       
  1269 				}
       
  1270 			
       
  1271 			if (!lex.Eos())
       
  1272 				{
       
  1273 				lex.Inc();
       
  1274 				}
       
  1275 			else
       
  1276 				{
       
  1277 				break;	
       
  1278 				}
       
  1279 				
       
  1280 			if (!lex.Eos())
       
  1281 				{
       
  1282 				lex.Inc();
       
  1283 				}				
       
  1284 			else
       
  1285 				{
       
  1286 				break;
       
  1287 				}
       
  1288 				
       
  1289 			if (!lex.Eos() && lex.Peek() != QMark)
       
  1290 				{
       
  1291 				break; // incorrectly formed encoded-word
       
  1292 				}
       
  1293 				
       
  1294 			lex.Inc();
       
  1295 			
       
  1296 			while ( lex.Peek() != QMark && !lex.Eos() )
       
  1297 				{
       
  1298 				lex.Inc();
       
  1299 				}
       
  1300 			
       
  1301 			if (lex.Peek() != QMark)
       
  1302 				{
       
  1303 				break; // incorrectly formed encoded-word
       
  1304 				}
       
  1305 			
       
  1306 			if (!lex.Eos())
       
  1307 				{
       
  1308 				lex.Inc();
       
  1309 				}
       
  1310 			else
       
  1311 				{
       
  1312 				break;	
       
  1313 				}
       
  1314 			
       
  1315 			if (lex.Peek() != KImcvEquals)
       
  1316 				{
       
  1317 				break; // incorrectly formed encoded-word
       
  1318 				}
       
  1319 				
       
  1320 			if (!lex.Eos())
       
  1321 				{
       
  1322 				lex.Inc();
       
  1323 				}
       
  1324 			else
       
  1325 				{
       
  1326 				break;	
       
  1327 				}
       
  1328 			//---------------------------------------------------------
       
  1329 
       
  1330 			encodedWord8.Set(lex.MarkedToken());
       
  1331 
       
  1332 			wordExists = ETrue;
       
  1333 			}
       
  1334 
       
  1335 		if (wordExists)
       
  1336 			{
       
  1337 			// If found ...
       
  1338 			decoded=ETrue;
       
  1339 			HBufC* decodedWord = HBufC::NewLC(encodedWord8.Length());
       
  1340 
       
  1341 			TPtr decodedPtr(decodedWord->Des());
       
  1342  			if ( DecodeWordL(encodedWord8, decodedPtr, rem) )
       
  1343 				{
       
  1344 				// replace decoded string with new string
       
  1345 				TUint offset = aBufOut.Length();
       
  1346 
       
  1347 
       
  1348 				// Store encoding information in Header object.
       
  1349 				iEncodingInfo.SetEncodedLength(lex.TokenLength());
       
  1350 				iEncodingInfo.SetOffset(offset);
       
  1351 				iEncodingInfo.SetLength(decodedPtr.Length());
       
  1352 
       
  1353 				if (iHeader)
       
  1354 					{
       
  1355 					iHeader->AddEncodingInfoL(iEncodingInfo);			
       
  1356 					}
       
  1357 					
       
  1358 				}
       
  1359 
       
  1360 			aBufOut.Append( decodedPtr );
       
  1361 
       
  1362 			CleanupStack::PopAndDestroy(); //  decodedWord;
       
  1363 			}	
       
  1364 		} // while
       
  1365 
       
  1366 	lex.UnGetToMark();
       
  1367 	if (decoded && lex.MarkedOffset())
       
  1368 		{
       
  1369 		lex.UnGet();
       
  1370 		if (lex.Peek()==KImcvSpaceChar || lex.Peek()==KImcvTab)
       
  1371 			{
       
  1372 			lex.Mark();
       
  1373 			}			
       
  1374 		}
       
  1375 
       
  1376 	if(decoded==EFalse)
       
  1377 		{
       
  1378 		DecodeNonMIMEHeaderFieldL(aBufIn,aBufOut);
       
  1379 
       
  1380 		}
       
  1381  	else
       
  1382 		{
       
  1383 		TPtrC8 marked = lex.RemainderFromMark();
       
  1384   	    Append(aBufOut, marked);
       
  1385 
       
  1386  		}
       
  1387 }
       
  1388 
       
  1389 
       
  1390 // For non-MIME case, System default being ASCII normally 
       
  1391 //
       
  1392  EXPORT_C void CImConvertHeader::DecodeNonMIMEHeaderFieldL(const TDesC8& aBufIn, TDes& aBufOut)
       
  1393 
       
  1394 	{
       
  1395 	__ASSERT_DEBUG(aBufIn.Size() <= aBufOut.MaxSize(), User::Invariant());
       
  1396 
       
  1397 	TUint charset;
       
  1398 
       
  1399 	(iOverrideCharset != 0) ? 
       
  1400 		(charset = iOverrideCharset) : (charset = iCharConv.DefaultCharset());
       
  1401 
       
  1402 	if (iCharConv.PrepareToConvertToFromOurCharsetL(charset)== EFalse)
       
  1403 		{
       
  1404 		// Charset not available, don't decode.
       
  1405 		aBufOut.Copy(aBufIn);
       
  1406 		}
       
  1407 
       
  1408 	// Character set conversion
       
  1409 	TInt unconvertedChars;
       
  1410 	TInt pos;
       
  1411 	iCharConv.ConvertToOurCharsetL(aBufIn, aBufOut, unconvertedChars, pos);
       
  1412 
       
  1413 }
       
  1414 
       
  1415 
       
  1416 
       
  1417 // aBufIn is of the form "=?" "charset" "?" "Encoding" "?" "Encoding Text" "?="
       
  1418 // Decode the 'Encoding Text' based on the information in 'Encoding' and 'charset'
       
  1419 // and pass back in aBufOut
       
  1420 
       
  1421 //
       
  1422   TBool CImConvertHeader::DecodeWordL(const TDesC8& aBufIn, TDes& aBufOut,  TInt rRemainder)
       
  1423 	{
       
  1424 	rRemainder=0;
       
  1425       HBufC8* dataBuf8 = HBufC8::NewLC(aBufOut.MaxLength());
       
  1426 
       
  1427 
       
  1428 	const TUint8* ptr = aBufIn.Ptr();	
       
  1429 
       
  1430 	__ASSERT_DEBUG( (*ptr == KImcvEquals) && (*(ptr+1) == KImcvQuestionMark),User::Invariant());
       
  1431 
       
  1432 	// Extract the charset string and store
       
  1433 	TInt i;
       
  1434 	for(i = 2; *(ptr+i) != KImcvQuestionMark ; i++)
       
  1435 		;
       
  1436 
       
  1437 	TUint uid;
       
  1438 	if (iOverrideCharset != 0)
       
  1439 		{
       
  1440 		uid = iOverrideCharset;
       
  1441 		}
       
  1442 	else
       
  1443 		{
       
  1444 		TPtrC8 buf8(ptr+2, i-2);
       
  1445 		uid = iCharConv.GetMimeCharsetUidL(buf8);
       
  1446 		}
       
  1447 
       
  1448 	if (!uid || !iCharConv.PrepareToConvertToFromOurCharsetL(uid))
       
  1449 		{
       
  1450 		// Charset not available, dont decode.
       
  1451         aBufOut.Copy(aBufIn);
       
  1452  	  	CleanupStack::PopAndDestroy(dataBuf8); 
       
  1453 		return EFalse;
       
  1454 		}
       
  1455 
       
  1456 	iEncodingInfo.SetCharsetUid(uid);
       
  1457 
       
  1458 	// Extract the Encoding string and store
       
  1459 	for(i++; *(ptr+i) != KImcvQuestionMark ; i++)
       
  1460 		;
       
  1461 	TPtrC8 buf28(ptr+i-1, 1);
       
  1462 	iEncodingInfo.SetEncodingType(buf28); 	// Currently encoding is either Q or B
       
  1463 
       
  1464 
       
  1465 	// Now at the encoding text
       
  1466 	TInt j;
       
  1467 	for(j = i+1; *(ptr+j) != KImcvQuestionMark ; j++)
       
  1468 		;
       
  1469 
       
  1470 	// Intermediate buffer for decoding, prior to converting
       
  1471 
       
  1472       HBufC8* decodeBuf8 = HBufC8::NewLC(aBufOut.MaxLength());
       
  1473 
       
  1474 	decodeBuf8->Des().Copy( aBufIn.Mid(i+1, j -i-1));
       
  1475 
       
  1476    	// Depending on type of encoding Q or B, decode.
       
  1477 
       
  1478 	TPtr8 dataPtr8(dataBuf8->Des());
       
  1479 
       
  1480 	switch (iEncodingInfo.EncodingType())
       
  1481 		{
       
  1482 		case TImHeaderEncodingInfo::EBase64 :
       
  1483 			iB64Codec.Decode( *decodeBuf8, dataPtr8 );
       
  1484 			break;
       
  1485 		case TImHeaderEncodingInfo::EQP :
       
  1486 			// Replace all underscores in text with SPACE.
       
  1487 			iQPCodec.Decode( *decodeBuf8, dataPtr8 );
       
  1488 
       
  1489 			i=dataPtr8.Length();
       
  1490 			while (i--)
       
  1491 				{
       
  1492 				if (dataPtr8[i] == KImcvUnderScore)
       
  1493 					dataPtr8[i] = KImcvSpaceChar;	
       
  1494 				}
       
  1495 			break;
       
  1496 		default:
       
  1497 			dataBuf8->Des().Copy(*decodeBuf8); 
       
  1498 			break;
       
  1499 		}
       
  1500 
       
  1501 	// Character set conversion
       
  1502 	TInt unconvertedChars, pos;
       
  1503 	rRemainder = iCharConv.ConvertToOurCharsetL(*dataBuf8, aBufOut, unconvertedChars, pos);
       
  1504 
       
  1505 	CleanupStack::PopAndDestroy(decodeBuf8);
       
  1506 	CleanupStack::PopAndDestroy(dataBuf8); 
       
  1507 	return (rRemainder < 0) ? EFalse:ETrue;
       
  1508 	}
       
  1509 /**
       
  1510 Convert function used for non-MIME messages.
       
  1511 
       
  1512 @publishedPartner
       
  1513 @released
       
  1514 */
       
  1515 EXPORT_C void CImConvertHeader::ConvertHeaderFieldL(const TDesC16& aBufIn, RBuf8& aBufOut, TBool aIsAddressField)
       
  1516 	{
       
  1517 	// Don't make use of the unconverted char info. 
       
  1518 	//Assume text has been checked for non ascii characters. 
       
  1519 
       
  1520 	// Need to identify the email address
       
  1521 	TInt start=0;
       
  1522 	TInt end=0;
       
  1523 
       
  1524 	if (ExtractTextToEncode(aBufIn, start, end, aIsAddressField)==EFalse)
       
  1525 	    aBufOut.Copy(aBufIn);
       
  1526 	else
       
  1527 		{
       
  1528 		// clear out buffer
       
  1529 		aBufOut.Zero();
       
  1530 		TInt unconvertedChars;
       
  1531 		TInt pos;
       
  1532 		iCharConv.ConvertFromOurCharsetL( aBufIn.Mid(start, end-start+1), aBufOut, unconvertedChars, pos);
       
  1533   
       
  1534 		if (start>0)
       
  1535 			{
       
  1536 			// Copy over text prior to bit needing encoding
       
  1537 			aBufOut.ReAllocL(aBufOut.Length() + aBufIn.Length());
       
  1538 			Insert( aBufOut, aBufIn.Left(start));
       
  1539 
       
  1540 			}
       
  1541 		
       
  1542 		if (end<aBufIn.Length())
       
  1543 			{
       
  1544 			// Copy over text after bit needing encoding
       
  1545 		 
       
  1546             aBufOut.ReAllocL(aBufOut.Length() + (aBufIn.Length()-end-1));
       
  1547 			aBufOut.Append(aBufIn.Right(aBufIn.Length()-end-1));
       
  1548 
       
  1549 			}
       
  1550 		}
       
  1551 	}
       
  1552 
       
  1553 
       
  1554 /**
       
  1555 @publishedPartner
       
  1556 @released
       
  1557 */
       
  1558 EXPORT_C void CImConvertHeader::EncodeHeaderFieldL(const TDesC& aBufIn, RBuf8& aBufOut,				
       
  1559                 CArrayFix<TImHeaderEncodingInfo>* aInfoArray, TInt aState, TInt aArrayVal)
       
  1560 	{
       
  1561 	// In case not requiring encoding, already ascii
       
  1562    // allocate enough space to copy data
       
  1563 	aBufOut.ReAllocL(aBufIn.Length());
       
  1564 	aBufOut.Copy(aBufIn);
       
  1565 
       
  1566 	for (TInt i=0; i < aInfoArray->Count(); i++)
       
  1567 		{
       
  1568 		if ( (aInfoArray->At(i).Field() == (TImHeaderEncodingInfo::TFieldList) aState)
       
  1569 								&& ((*aInfoArray)[i].ArrayValue() == (TInt)aArrayVal) )
       
  1570 			{
       
  1571 			GetCharsetAndEncodeDataL( aBufIn, aBufOut, (*aInfoArray)[i]);
       
  1572 			}
       
  1573 		}
       
  1574 	}
       
  1575 
       
  1576 /**
       
  1577  This function has to encode without any prestored information.
       
  1578  Encodes from UNICODE, to UTF-7
       
  1579 
       
  1580 @publishedPartner
       
  1581 @released
       
  1582 */
       
  1583 EXPORT_C void CImConvertHeader::EncodeHeaderFieldL(const TDesC& aBufIn, RBuf8&  aBufOut,
       
  1584 				                                   const TUint aCharset, const TImHeaderEncodingInfo::TEncodingType aType, TBool aIsAddressField)
       
  1585 	{
       
  1586 	TImHeaderEncodingInfo infoArray;
       
  1587 
       
  1588 	aBufOut.ReAllocL(aBufIn.Length());
       
  1589 	aBufOut.Copy(aBufIn);
       
  1590 
       
  1591 	infoArray.SetCharsetUid(aCharset);
       
  1592 	infoArray.SetEncodingType(aType);
       
  1593 	
       
  1594 	TInt startOfEncoding = 0;
       
  1595 	TInt endOfEncoding = 0;
       
  1596 	if(ExtractTextToEncode(aBufIn, startOfEncoding, endOfEncoding, aIsAddressField))
       
  1597 		{
       
  1598 		infoArray.SetOffset(startOfEncoding);
       
  1599 		infoArray.SetLength(endOfEncoding - startOfEncoding + 1);
       
  1600 		GetCharsetAndEncodeDataL(aBufIn, aBufOut, infoArray);	
       
  1601 		}
       
  1602 	}
       
  1603 
       
  1604 // Return the offset in the text buffer for the text portion of the header field
       
  1605 //
       
  1606 TBool CImConvertHeader::ExtractTextToEncode(const TDesC& aBufIn, TInt& rStart, TInt& rEnd, TBool aIsAddressField)
       
  1607 	{
       
  1608 	TInt startOfEncoding = 0;
       
  1609 	TInt endOfEncoding = 0;
       
  1610 	TBool mustEncode = EFalse;
       
  1611 	TBool mustEncodeThisWord=EFalse;
       
  1612 
       
  1613 	// Check aField for non ascii characters - encode. Return in rEncodedField.
       
  1614 
       
  1615 	TInt len=aBufIn.Length();
       
  1616 	TInt i=0;
       
  1617 	for (;i < len;i++)
       
  1618 		{
       
  1619 		TChar inChar = aBufIn[i];
       
  1620 		if (inChar==KImcvSpaceChar || inChar==KImcvQuote || inChar==KImcvTab)
       
  1621 			{
       
  1622 			if (mustEncodeThisWord)
       
  1623 				endOfEncoding=i-1;
       
  1624 			else if (!mustEncode)
       
  1625 				startOfEncoding=i+1; 
       
  1626 			mustEncodeThisWord=EFalse;
       
  1627 			}
       
  1628 		else if (inChar==KImcvLeftChevron && aIsAddressField)
       
  1629 			{
       
  1630 			if (mustEncodeThisWord)
       
  1631 				{
       
  1632 				endOfEncoding=i-1;
       
  1633 				mustEncodeThisWord=EFalse;
       
  1634 				}
       
  1635 			if (mustEncode)
       
  1636 				break; // already have word to encode, now at an address
       
  1637 			}
       
  1638 		else if (inChar==KImcvRightChevron && aIsAddressField)
       
  1639 			{
       
  1640 			startOfEncoding=i+1; 
       
  1641 			}
       
  1642 		else if ( !IsAscii(inChar) )
       
  1643 			{
       
  1644 			mustEncode = ETrue;
       
  1645 			mustEncodeThisWord=ETrue;
       
  1646 			}
       
  1647 		}
       
  1648 
       
  1649 	if (mustEncodeThisWord)
       
  1650 		endOfEncoding=i-1;
       
  1651 
       
  1652 	rStart=startOfEncoding;
       
  1653 	rEnd=endOfEncoding;
       
  1654 	return mustEncode;
       
  1655 	}
       
  1656 		                                               
       
  1657 void CImConvertHeader::GetCharsetAndEncodeDataL(const TDesC&  aBufIn,
       
  1658 									RBuf8& aBufOut, TImHeaderEncodingInfo& aInfo)
       
  1659 	{
       
  1660 	// Work out which character set to use, and get a string representation
       
  1661 	// of it.
       
  1662 	HBufC8* charsetName=iCharConv.GetMimeCharsetTextStringL(aInfo.CharsetUid());
       
  1663 
       
  1664 	TUint charset=aInfo.CharsetUid();
       
  1665 	if (charset==KCharacterSetIdentifierIso88591)
       
  1666 		charset=KCharacterSetIdentifierCodePage1252;
       
  1667 	
       
  1668 	if (!charsetName || !iCharConv.PrepareToConvertToFromOurCharsetL(charset))
       
  1669 		{
       
  1670 		delete charsetName; 
       
  1671 		charsetName=NULL;
       
  1672 
       
  1673 		// Problem with charset Uid, use default character set.
       
  1674 		charset=iCharConv.DefaultCharset();
       
  1675 		aInfo.SetCharsetUid(charset);
       
  1676 		charsetName=iCharConv.GetMimeCharsetTextStringL(charset);
       
  1677 		if (charset==KCharacterSetIdentifierIso88591)
       
  1678 			charset=KCharacterSetIdentifierCodePage1252;
       
  1679 		__ASSERT_ALWAYS(iCharConv.PrepareToConvertToFromOurCharsetL(charset), User::Invariant());
       
  1680 		}
       
  1681 
       
  1682 	CleanupStack::PushL(charsetName);
       
  1683 	__ASSERT_ALWAYS(charsetName, gPanic(KPanicInvalidDefaultCharacterSet) );
       
  1684 
       
  1685 	// Create a buffer to use to store the encoded word
       
  1686 	HBufC8* encodedWordBuffer = HBufC8::NewL(aBufOut.MaxSize());
       
  1687 	RBuf8 encodedWord(encodedWordBuffer);
       
  1688 	encodedWord.CleanupClosePushL();
       
  1689 
       
  1690 	EncodeWordL(aBufIn, aBufOut, aInfo, *charsetName, encodedWord);
       
  1691 
       
  1692 	CleanupStack::PopAndDestroy(2, charsetName);  // charset name, encoded word
       
  1693 	}
       
  1694 
       
  1695 
       
  1696 void CImConvertHeader::EncodeWordL(const TDesC& aBufIn, 
       
  1697 								   RBuf8& aBufOut, TImHeaderEncodingInfo& aInfo,
       
  1698 								   const TDesC8& aCharsetName, RBuf8& aEncodedWord)
       
  1699 	{
       
  1700 	TInt max = KEncodedWordMaxLength - KMaxEncodedInformationLength -
       
  1701 		aCharsetName.Length() - KMaxHeaderFieldNameLength;
       
  1702 
       
  1703 	TBool splitAndRetry = ETrue;
       
  1704 
       
  1705 	// We will convert the word to the required character set, and perform any
       
  1706 	// encoding (base64, quoted-printable) required. At each stage we check whether
       
  1707 	// the buffer has exceeded the maximum length allowed for a line. If so, we
       
  1708 	// cut the buffer into two halves and encode each half separately.
       
  1709 
       
  1710 	if (aInfo.Length() <= max)
       
  1711 		{
       
  1712 		// Identify the part of the input buffer that will be encoded
       
  1713 		TPtrC data = aBufIn.Mid(aInfo.Offset(), aInfo.Length());
       
  1714 
       
  1715 		// Perform the conversion to the required character set
       
  1716 		DoCharsetConversionL(data, aEncodedWord);
       
  1717 
       
  1718 		if (aEncodedWord.Length() <= max)
       
  1719 			{
       
  1720 			// Perform any base64 / quoted printable encoding
       
  1721 			DoEncodingL(aEncodedWord, aInfo);
       
  1722 
       
  1723 			if (aEncodedWord.Length() <= max)
       
  1724 				{
       
  1725 				// We have managed to do all the steps without the buffer exceeding
       
  1726 				// the maximum line length
       
  1727 	  			splitAndRetry = EFalse;
       
  1728 				}
       
  1729 			}
       
  1730 		}
       
  1731 
       
  1732 	if (splitAndRetry)
       
  1733 		{
       
  1734 		TInt len = aInfo.Length()/2;
       
  1735 		TUint16 offset = (TUint16) aInfo.Offset();
       
  1736 		TUint16 length = (TUint16) aInfo.Length();
       
  1737 
       
  1738 		aInfo.SetOffset(offset+len);
       
  1739 		aInfo.SetLength(length-len);
       
  1740 		EncodeWordL(aBufIn, aBufOut, aInfo, aCharsetName, aEncodedWord);
       
  1741 		aBufOut.ReAllocL(aBufOut.MaxLength()+1);
       
  1742 		aBufOut.Insert(offset+len,KImcvSpace);
       
  1743 
       
  1744 		aInfo.SetOffset(offset);
       
  1745 		aInfo.SetLength(len);
       
  1746 		EncodeWordL(aBufIn, aBufOut, aInfo, aCharsetName, aEncodedWord);
       
  1747 
       
  1748 		aInfo.SetLength(length);
       
  1749 		}
       
  1750 	else
       
  1751 		{
       
  1752 		// Delete unencoded data, prior to putting in encoded data
       
  1753 		aBufOut.Delete(aInfo.Offset(), aInfo.Length());
       
  1754 		aBufOut.ReAllocL(aBufOut.MaxLength()-aInfo.Length());
       
  1755 		AddEncodedWordInfoL(aEncodedWord, aBufOut, aInfo, aCharsetName);
       
  1756 		aEncodedWord.Zero();
       
  1757 		}
       
  1758 	}
       
  1759 
       
  1760 
       
  1761 TBool CImConvertHeader::DoCharsetConversionL(const TDesC& aDataToConvert, RBuf8& aEncodedWord)
       
  1762 	{
       
  1763 	TBool convertOk = ETrue;
       
  1764 
       
  1765 	TInt unconvertedChars, pos;
       
  1766 	TInt excessChars;
       
  1767 	TInt lastExcessChars = 0;
       
  1768 	TBool failNextTimeExcessCharsStaySame = EFalse;
       
  1769 	TBool finishedConvert = EFalse;
       
  1770 
       
  1771 	while (!finishedConvert)
       
  1772 		{
       
  1773 		excessChars = iCharConv.ConvertFromOurCharsetL(aDataToConvert, aEncodedWord, unconvertedChars, pos);
       
  1774 
       
  1775 		if (excessChars == 0)
       
  1776 			{
       
  1777 			finishedConvert = ETrue;
       
  1778 			}
       
  1779 		else if (excessChars == CCnvCharacterSetConverter::EErrorIllFormedInput)
       
  1780 			{
       
  1781 			User::Leave(KErrCorrupt);
       
  1782 			}
       
  1783 		else
       
  1784 			{
       
  1785 			// We did not convert all the characters in the buffer. This is
       
  1786 			// probably because the output buffer is not large enough.
       
  1787 			// If the number of characters left unconverted this time is the same
       
  1788 			// as last time, then perhaps the conversion is failing for other
       
  1789 			// reasons. To avoid getting stuck like this forever, we will only
       
  1790 			// allow this to happen once.
       
  1791 
       
  1792 			if (excessChars == lastExcessChars)
       
  1793 				{
       
  1794 				if (failNextTimeExcessCharsStaySame)
       
  1795 					{
       
  1796 					finishedConvert = ETrue;
       
  1797 					convertOk = EFalse;
       
  1798 					}
       
  1799 				else
       
  1800 					{
       
  1801 					failNextTimeExcessCharsStaySame = ETrue;
       
  1802 					}
       
  1803 				}
       
  1804 			else
       
  1805 				{
       
  1806 					failNextTimeExcessCharsStaySame = EFalse;
       
  1807 				}
       
  1808 
       
  1809 			// If we are going around again, increase the size of the output buffer
       
  1810 			if (!finishedConvert)
       
  1811 				{
       
  1812 				aEncodedWord.ReAllocL(aEncodedWord.MaxSize() + KImMaxLengthForEncodedChar);
       
  1813 				lastExcessChars = excessChars;
       
  1814 				}
       
  1815 			}
       
  1816 		}
       
  1817 
       
  1818 	return convertOk;
       
  1819 	}
       
  1820 
       
  1821 void CImConvertHeader::DoEncodingL(RBuf8& aEncodedWord, TImHeaderEncodingInfo& aInfo)
       
  1822 	{
       
  1823 	// Take a copy of the encoded word so far. This will be used as the
       
  1824 	// input to the encoding routines
       
  1825 	HBufC8* dataToEncode = HBufC8::NewLC(aEncodedWord.Length());
       
  1826 	dataToEncode->Des().Copy(aEncodedWord);
       
  1827 	aEncodedWord.Zero();
       
  1828 
       
  1829 	if (aInfo.EncodingType() == TImHeaderEncodingInfo::EBase64)
       
  1830 		{
       
  1831 		// Increase the size of the buffer to allow for the base64 encoding.
       
  1832 		// Base64 takes three 8 bit octets and encodes them into four 6 bit
       
  1833 		// characters.
       
  1834 		aEncodedWord.ReAllocL((((*dataToEncode).Length() + 2) / 3) * 4);
       
  1835 
       
  1836 		iB64Codec.Encode(*dataToEncode, aEncodedWord);
       
  1837 		}
       
  1838 	else if (aInfo.EncodingType() == TImHeaderEncodingInfo::EQP)
       
  1839 		{
       
  1840 		// Worst case scenario is that each character in the buffer has to be
       
  1841 		// encoded to its hex equivalent with preceding '=' sign. Also added an
       
  1842 		// extra byte becuase the QP encoder expects the buffer to be one longer
       
  1843 		// than required.
       
  1844 		aEncodedWord.ReAllocL(((*dataToEncode).Length() * 3) + 1);
       
  1845 
       
  1846 		// Replace all underscores in text with SPACE.
       
  1847 		for(TInt i=0; i < (*dataToEncode).Length(); i++)
       
  1848 			{
       
  1849 			if ((*dataToEncode)[i] == KImcvSpaceChar)
       
  1850 				dataToEncode->Des()[i] = KImcvUnderScore;	
       
  1851 			}
       
  1852 		 iQPCodec.Encode(*dataToEncode, aEncodedWord);
       
  1853 		}
       
  1854 	else
       
  1855 		aEncodedWord.Copy(*dataToEncode);
       
  1856 
       
  1857 	CleanupStack::PopAndDestroy(); // dataToEncode
       
  1858 	}
       
  1859 
       
  1860 
       
  1861 TInt CImConvertHeader::AddEncodedWordInfoL(const TDesC8& aEncodedWord, RBuf8& aBufOut,
       
  1862 									TImHeaderEncodingInfo& aInfo, const TDesC8& aCharsetName)
       
  1863 	{
       
  1864 	// Encoded data 'in place' in OutBuf.
       
  1865 
       
  1866 	// Add BEFORE encode data
       
  1867 	TInt offset = aInfo.Offset();
       
  1868 	TInt charsetSize = aCharsetName.Size();
       
  1869 		
       
  1870 	// Convert based on iCharSet and iEncoding
       
  1871 	
       
  1872 	// allocate enough space for encoded word plus extra encoding tokens
       
  1873 	// KImMaxLengthForEncodedWordAndExtraEncodingTokens = size of '?=' + '?' + ('B' or 'Q') + '?' + '?=' + ' '
       
  1874 	aBufOut.ReAllocL(aBufOut.MaxSize() + KImMaxLengthForEncodedWordAndExtraEncodingTokens + charsetSize + aEncodedWord.Size());
       
  1875 	aBufOut.Insert( offset, KImcvEncodedWordStart);
       
  1876 
       
  1877 	// KImcvEncodedWordStart = 2
       
  1878 	// Other numerical values are from the encoded word characters
       
  1879 	// =? .. ?.. ? .. ?=
       
  1880 
       
  1881 	aBufOut.Insert( offset + 2, aCharsetName);
       
  1882 	aBufOut.Insert( offset + 2 + charsetSize, KImcvQuestionMarkString);
       
  1883 
       
  1884 
       
  1885 	if (aInfo.EncodingType() == TImHeaderEncodingInfo::EBase64)
       
  1886     	{
       
  1887 		aBufOut.Insert( offset + 2 + charsetSize+1, KImcvB);
       
  1888 		}
       
  1889 	else
       
  1890 		{	
       
  1891 		aBufOut.Insert( offset + 2 + charsetSize+1, KImcvQ);
       
  1892 		}
       
  1893 
       
  1894 	aBufOut.Insert( offset + 2 + charsetSize+2, KImcvQuestionMarkString);
       
  1895 
       
  1896 	offset += 2 + charsetSize + 3;
       
  1897 
       
  1898 	aBufOut.Insert( offset, aEncodedWord );
       
  1899 
       
  1900 	aBufOut.Insert( offset + aEncodedWord.Length(), KImcvEncodedWordEnd);
       
  1901 
       
  1902 	TInt returnOffset = offset + aEncodedWord.Length() + 2;
       
  1903 
       
  1904 	if (aInfo.AddSpace())
       
  1905 		{
       
  1906     	aBufOut.Insert( aInfo.Offset(), KImcvSpace);
       
  1907 
       
  1908 		returnOffset++;
       
  1909 		}
       
  1910 
       
  1911 	// Return end of encoding offset.
       
  1912 	return returnOffset;
       
  1913 	}
       
  1914 
       
  1915 
       
  1916 
       
  1917 // Check aData to see if it has any partial 'encoded-word's.
       
  1918 // ie a string of the gotm '=? ... ? ... ?=' which is incomplete.
       
  1919 // Return length of new string, up to the start of the partial encoded word.
       
  1920 //
       
  1921 EXPORT_C TBool CImConvertHeader::FindEncodedWord(TPtrC8& aData, TInt& aInit, TInt& rStart, TInt& rEnd)
       
  1922 	{
       
  1923 	TBool found = EFalse;
       
  1924 
       
  1925 	TPtrC8 data = aData.Mid(aInit);
       
  1926 	rStart = data.Find(KImcvEncodedWordStart);
       
  1927 	rEnd = data.Length();
       
  1928 	if (rStart != KErrNotFound)
       
  1929 		{
       
  1930 		found = ETrue;
       
  1931 
       
  1932 		TInt i;
       
  1933 		TInt j = 0;
       
  1934 
       
  1935 		// Check for the three question marks
       
  1936 		for (i = rStart+2; i < data.Length(); i++)
       
  1937 			{
       
  1938 			if (data[i] == KImcvQuestionMark)	
       
  1939 				j++;
       
  1940 			if (j == 3)
       
  1941 				break; 
       
  1942 			}
       
  1943 
       
  1944 		if (j != 3)
       
  1945 			found = EFalse;	// Have encountered an incomplete encoded-word
       
  1946 
       
  1947 		// Check last ? is followed by =
       
  1948 		rEnd = i+1;
       
  1949 		if ( rEnd > data.Length() || data[rEnd] != KImcvEquals )
       
  1950 			found = EFalse;	// Have encountered an incomplete encoded-word
       
  1951 		} // if
       
  1952 
       
  1953  	return found;
       
  1954 	}
       
  1955 
       
  1956 
       
  1957 TBool CImConvertHeader::IsAscii( TUint aChar ) const
       
  1958 	{
       
  1959 	return ( ((aChar >= 32) && (aChar <= 126)));
       
  1960 	};
       
  1961 
       
  1962 // function for adding 8 bit descriptor onto a 16bit descritpr.
       
  1963 //
       
  1964 void CImConvertHeader::Append(TDes& aBuffer, const TDesC8& aAddition)
       
  1965 //----------------------------------------------------------------------------------------
       
  1966 	{
       
  1967 	TInt addLen = aAddition.Length();
       
  1968 	TInt bufLen = aBuffer.Length();
       
  1969 
       
  1970 	aBuffer.SetLength(bufLen+addLen);
       
  1971 	for(TInt i = 0; i < addLen; i++)
       
  1972 		aBuffer[bufLen+i] = aAddition[i];
       
  1973 	}
       
  1974 
       
  1975 
       
  1976 void CImConvertHeader::Insert(TDes8& aBuffer, const TDesC16& aInsert)
       
  1977 	{
       
  1978 	TInt addLen = aInsert.Length();
       
  1979 	TInt bufLen = aBuffer.Length();
       
  1980 	TInt origAddLen=addLen;
       
  1981 
       
  1982 	aBuffer.SetLength(bufLen+addLen);
       
  1983 
       
  1984 
       
  1985 	while (bufLen > addLen)
       
  1986 		{
       
  1987 		aBuffer[bufLen+addLen-1] = aBuffer[bufLen-1];
       
  1988 		bufLen--;
       
  1989 		}
       
  1990 
       
  1991 	while (addLen > bufLen)
       
  1992 		{
       
  1993 		aBuffer[addLen-1] = (TUint8) aInsert[addLen-1];
       
  1994 		addLen--;
       
  1995 		}
       
  1996 
       
  1997 	// Assert bufLen==addLen
       
  1998 	while(bufLen)
       
  1999 		{
       
  2000 		aBuffer[bufLen+origAddLen-1] = aBuffer[bufLen-1];
       
  2001 		aBuffer[bufLen-1] = (TUint8) aInsert[bufLen-1];
       
  2002 		bufLen--;
       
  2003 		}
       
  2004 
       
  2005 
       
  2006 	}
       
  2007 
       
  2008 
       
  2009