@@ -284,151 +284,158 @@ destructor TRESTDWMessageDecoderMIME.Destroy;
284284
285285Function TRESTDWMessageDecoderMIME.ReadBody (ADestStream : TStream;
286286 Var VMsgEnd : Boolean) : TRESTDWMessageDecoder;
287- Var
288- LContentType,
289- LContentTransferEncoding,
290- LLine,
291- LBinaryLineBreak,
292- LBuffer, // Needed for binhex4 because cannot decode line-by-line.
293- LBoundaryStart,
294- LBoundaryEnd : String;
295- LIsThisTheFirstLine, // Needed for binary encoding
296- LIsBinaryContentTransferEncoding : Boolean;
297- LDecoder : TRESTDWDecoder;
298- Begin
299- LIsThisTheFirstLine := True;
300- VMsgEnd := False;
301- Result := Nil ;
302- If FBodyEncoded Then
303- Begin
304- LContentType := TRESTDWMessage(Owner).ContentType;
305- LContentTransferEncoding := TRESTDWMessage(Owner).ContentTransferEncoding;
306- End
307- Else
308- Begin
309- LContentType := FHeaders.Values[' Content-Type' ]; { Do not Localize}
310- LContentTransferEncoding := FHeaders.Values[' Content-Transfer-Encoding' ]; { Do not Localize}
311- End ;
312- If LContentTransferEncoding = ' ' Then
313- Begin
314- If IsHeaderMediaType(LContentType, ' application/mac-binhex40' ) Then { Do not Localize}
315- LContentTransferEncoding := ' binhex40' { do not localize}
316- Else If Not IsHeaderMediaType(LContentType, ' application/octet-stream' ) Then { Do not Localize}
317- LContentTransferEncoding := ' 7bit' ; { do not localize}
318- End
319- Else If IsHeaderMediaType(LContentType, ' multipart' ) Then { do not localize}
320- Begin
321- If PosInStrArray(LContentTransferEncoding, [' 7bit' , ' 8bit' , ' binary' ], False) = -1 Then { do not localize}
322- LContentTransferEncoding := ' ' ;
323- End ;
324- If TextIsSame(LContentTransferEncoding, ' base64' ) Then { Do not Localize}
325- LDecoder := TRESTDWDecoderMIMELineByLine.Create(Nil )
326- Else If TextIsSame(LContentTransferEncoding, ' quoted-printable' ) Then { Do not Localize}
327- LDecoder := TRESTDWDecoderQuotedPrintable.Create(Nil )
328- Else If TextIsSame(LContentTransferEncoding, ' binhex40' ) Then { Do not Localize}
329- LDecoder := TRESTDWDecoderBinHex4.Create (Nil )
330- Else
331- LDecoder := nil ;
332- Try
333- If LDecoder <> Nil Then
334- LDecoder.DecodeBegin(ADestStream);
335- If MIMEBoundary <> ' ' Then
336- Begin
337- LBoundaryStart := ' --' + MIMEBoundary; { Do not Localize}
338- LBoundaryEnd := LBoundaryStart + ' --' ; { Do not Localize}
339- End ;
340- If LContentTransferEncoding <> ' ' Then
341- Begin
342- Case PosInStrArray(LContentTransferEncoding, [' 7bit' , ' quoted-printable' , ' base64' , ' 8bit' , ' binary' ], False) Of { do not localize}
343- 0 ..2 : LIsBinaryContentTransferEncoding := False;
344- 3 ..4 : LIsBinaryContentTransferEncoding := True;
345- Else
346- LIsBinaryContentTransferEncoding := True;
347- LContentTransferEncoding := ' ' ;
348- End ;
349- End
350- Else
351- LIsBinaryContentTransferEncoding := True;
352- Repeat
353- If Not FProcessFirstLine Then
354- Begin
355- If LIsBinaryContentTransferEncoding Then
356- Begin
357- LLine := ReadLnRFC(VMsgEnd, EOL, ' .' ); { do not localize}
358- LBinaryLineBreak := EOL;
359- End
360- Else
361- LLine := ReadLnRFC(VMsgEnd, LF, ' .' ); { do not localize}
362- End
363- Else
364- Begin
365- LLine := FFirstLine;
366- FFirstLine := ' ' ; { Do not Localize}
367- FProcessFirstLine := False;
368- // Do not use ADELIM since always ends with . (standard)
369- If LLine = ' .' Then
370- Begin { Do not Localize}
371- VMsgEnd := True;
372- Break;
373- End ;
374- If TextStartsWith(LLine, ' ..' ) Then
375- Delete(LLine, 1 , 1 );
376- End ;
377- If VMsgEnd Then
378- Break;
379- If MIMEBoundary <> ' ' Then
380- Begin
381- If TextIsSame(LLine, LBoundaryStart) Then
382- Begin
383- Result := TRESTDWMessageDecoderMIME.Create(Owner);
384- Break;
385- End ;
386- If TextIsSame(LLine, LBoundaryEnd) Then
387- Begin
388- If Owner is TRESTDWMessage Then
389- TRESTDWMessage(Owner).MIMEBoundary.Pop;
390- Break;
391- End ;
392- End ;
393- If LDecoder = Nil Then
287+ var
288+ LContentType, LContentTransferEncoding: string;
289+ LDecoder: TRESTDWDecoder;
290+ LBytes : TRESTDWBytes;
291+ LLine: string;
292+ LBuffer: string; // Needed for binhex4 because cannot decode line-by-line.
293+ LIsThisTheFirstLine: Boolean; // Needed for binary encoding
294+ BoundaryStart, BoundaryEnd: string;
295+ IsBinaryContentTransferEncoding: Boolean;
296+ begin
297+ LIsThisTheFirstLine := True;
298+ VMsgEnd := False;
299+ Result := nil ;
300+ if FBodyEncoded then begin
301+ LContentType := TRESTDWMessage(Owner).ContentType;
302+ LContentTransferEncoding := TRESTDWMessage(Owner).ContentTransferEncoding;
303+ end else begin
304+ LContentType := FHeaders.Values[' Content-Type' ]; { Do not Localize}
305+ LContentTransferEncoding := FHeaders.Values[' Content-Transfer-Encoding' ]; { Do not Localize}
306+ end ;
307+ if LContentTransferEncoding = ' ' then begin
308+ if IsHeaderMediaType(LContentType, ' application/mac-binhex40' ) then begin { Do not Localize}
309+ LContentTransferEncoding := ' binhex40' ; { do not localize}
310+ end ;
311+ end ;
312+
313+ // RLebeau 08/17/09 - According to RFC 2045 Section 6.4:
314+ // "If an entity is of type "multipart" the Content-Transfer-Encoding is not
315+ // permitted to have any value other than "7bit", "8bit" or "binary"."
316+ //
317+ // However, came across one message where the "Content-Type" was set to
318+ // "multipart/related" and the "Content-Transfer-Encoding" was set to
319+ // "quoted-printable". Outlook and Thunderbird were apparently able to parse
320+ // the message correctly, but Indy was not. So let's check for that scenario
321+ // and ignore illegal "Content-Transfer-Encoding" values if present...
322+
323+ if IsHeaderMediaType(LContentType, ' multipart' ) and (LContentTransferEncoding <> ' ' ) then { do not localize}
324+ begin
325+ if PosInStrArray(LContentTransferEncoding, [' 7bit' , ' 8bit' , ' binary' ], False) = -1 then begin { do not localize}
326+ LContentTransferEncoding := ' ' ;
327+ end ;
328+ end ;
329+
330+ if TextIsSame(LContentTransferEncoding, ' base64' ) then begin { Do not Localize}
331+ LDecoder := TRESTDWDecoderMIMELineByLine.Create(nil );
332+ end else if TextIsSame(LContentTransferEncoding, ' quoted-printable' ) then begin { Do not Localize}
333+ LDecoder := TRESTDWDecoderQuotedPrintable.Create(nil );
334+ end else if TextIsSame(LContentTransferEncoding, ' binhex40' ) then begin { Do not Localize}
335+ LDecoder := TRESTDWDecoderBinHex4.Create(nil );
336+ end else begin
337+ LDecoder := nil ;
338+ end ;
339+ Try
340+ if LDecoder <> nil then begin
341+ LDecoder.DecodeBegin(ADestStream);
342+ end ;
343+
344+ if MIMEBoundary <> ' ' then begin
345+ BoundaryStart := ' --' + MIMEBoundary; { Do not Localize}
346+ BoundaryEnd := BoundaryStart + ' --' ; { Do not Localize}
347+ end ;
348+
349+ case PosInStrArray(LContentTransferEncoding, [' 7bit' , ' quoted-printable' , ' base64' , ' 8bit' , ' binary' ], False) of { do not localize}
350+ 0 ..2 : IsBinaryContentTransferEncoding := False;
351+ 3 ..4 : IsBinaryContentTransferEncoding := True;
352+ else
353+ // According to RFC 2045 Section 6.4:
354+ // "Any entity with an unrecognized Content-Transfer-Encoding must be
355+ // treated as if it has a Content-Type of "application/octet-stream",
356+ // regardless of what the Content-Type header field actually says."
357+ IsBinaryContentTransferEncoding := True;
358+ end ;
359+ Repeat
360+ if not FProcessFirstLine then begin
361+ if IsBinaryContentTransferEncoding then
362+ LBytes := ReadLnRFCB(VMsgEnd, EOL, ' .' ) { do not localize}
363+ Else
364+ LLine := ReadLnRFC(VMsgEnd);
365+ end else begin
366+ LLine := FFirstLine;
367+ FFirstLine := ' ' ; { Do not Localize}
368+ FProcessFirstLine := False;
369+ // Do not use ADELIM since always ends with . (standard)
370+ if LLine = ' .' then begin { Do not Localize}
371+ VMsgEnd := True;
372+ Break;
373+ end ;
374+ if TextStartsWith(LLine, ' ..' ) then begin
375+ Delete(LLine, 1 , 1 );
376+ end ;
377+ end ;
378+ If (IsBinaryContentTransferEncoding) Then
379+ Begin
380+ If Length(LBytes) > 0 Then
381+ ADestStream.WriteBuffer(LBytes[0 ], Length(LBytes));
382+ SetLength(LBytes, 0 );
383+ If (VMsgEnd) Then
384+ Break;
385+ End ;
386+ // New boundary - end self and create new coder
387+ if MIMEBoundary <> ' ' then begin
388+ if TextIsSame(LLine, BoundaryStart) then begin
389+ Result := TRESTDWMessageDecoderMIME.Create(Owner);
390+ Break;
391+ // End of all coders (not quite ALL coders)
392+ end ;
393+ if TextIsSame(LLine, BoundaryEnd) then begin
394+ // POP the boundary
395+ if Owner is TRESTDWMessage then begin
396+ TRESTDWMessage(Owner).MIMEBoundary.Pop;
397+ end ;
398+ Break;
399+ end ;
400+ end ;
401+ if Not Assigned(LDecoder) then
402+ Begin
403+ // Data to save, but not decode
404+ If Not IsBinaryContentTransferEncoding then
405+ If Assigned(ADestStream) then
406+ WriteStringToStream(ADestStream, LLine + EOL);
407+ end
408+ else
409+ begin
410+ // Data to decode
411+ // For TIdDecoderQuotedPrintable, we have to make sure all EOLs are
412+ // intact
413+ if LDecoder is TRESTDWDecoderQuotedPrintable then begin
414+ // For TIdDecoderQuotedPrintable, we have to make sure all EOLs are intact
415+ // LLine := LLine + EOF;
416+ LDecoder.Decode(LLine);
417+ end else if LDecoder is TRESTDWDecoderBinHex4 then begin
418+ // We cannot decode line-by-line because lines don't have a whole
419+ // number of 4-byte blocks due to the : inserted at the start of
420+ // the first line, so buffer the file...
421+ LBuffer := LBuffer + LLine;
422+ end else if LLine <> ' ' then begin
423+ LDecoder.Decode(LLine);
424+ end ;
425+ end ;
426+ Until False;
427+ If LDecoder <> Nil Then
394428 Begin
395- If LIsBinaryContentTransferEncoding Then
396- Begin { do not localize}
397- If LIsThisTheFirstLine Then
398- LIsThisTheFirstLine := False
399- Else
400- Begin
401- If Assigned(ADestStream) Then
402- WriteStringToStream(ADestStream, LBinaryLineBreak, -1 , 1 );
403- End ;
404- If Assigned(ADestStream) Then
405- WriteStringToStream(ADestStream, LLine, -1 , 1 );
406- End
407- Else
429+ If LDecoder Is TRESTDWDecoderBinHex4 Then
408430 Begin
409- If Assigned(ADestStream) Then
410- WriteStringToStream(ADestStream, LLine + EOL, - 1 , 1 );
431+ // Now decode the complete block...
432+ LDecoder.Decode(LBuffer );
411433 End ;
412- End
413- Else
414- Begin
415- If LDecoder Is TRESTDWDecoderQuotedPrintable Then
416- LDecoder.Decode(LLine + EOL)
417- Else If LDecoder Is TRESTDWDecoderBinHex4 Then
418- LBuffer := LBuffer + LLine
419- Else If LLine <> ' ' Then
420- LDecoder.Decode(LLine);
434+ LDecoder.DecodeEnd;
421435 End ;
422- Until False;
423- If LDecoder <> Nil Then
424- Begin
425- If LDecoder Is TRESTDWDecoderBinHex4 Then
426- LDecoder.Decode(LBuffer);
427- LDecoder.DecodeEnd;
428- End ;
429- Finally
430- FreeAndNil(LDecoder);
431- End ;
436+ Finally
437+ FreeAndNil(LDecoder);
438+ End ;
432439End ;
433440
434441Function TRESTDWMessageDecoderMIME.GetAttachmentFilename (Const AContentType,
0 commit comments