Unit MimeDec

* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Author: François PIETTE Object: TMimeDecode is a component whose job is to decode MIME encoded EMail messages (file attach). You can use it for example to decode messages received with a POP3 component. MIME is described in RFC-1521. headers are described if RFC-822. EMail: francois.piette@ping.be francois.piette@rtfm.be WebSite: http://www.rtfm.be/fpiette Creation: March 08, 1998 Version: 1.04 Support: Use twsocket@rtfm.be mailing list. See website for details. Legal issues: Copyright (C) 1997 by François PIETTE This software is provided 'as-is', without any express or implied warranty. In no event will the author be held liable for any damages arising from the use of this software. Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: 1. The origin of this software must not be misrepresented, you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution. QUICK REFERENCE: ---------------- TMimeDecode take a file or a stream as input and produce several event when the message is parsed. each event can be used to display or to save to a file the message parts. Two methods can be called to decode either a file or a stream: procedure DecodeFile(FileName : String); procedure DecodeStream(aStream : TStream); During the decode process, the component trigger several events. You have to use those events to save data to a file or to display somehow on the user interface. Events are organized by groups of three for message header, part header and part data: Message header events: OnHeaderBegin OnHeaderLine OnHeaderEnd Part header events: OnPartHeaderBegin OnPartHeaderLine OnPartHeaderEnd Part data events: OnPartDataBegin OnPartDataLine OnPartDataEnd The 'Begin' event is triggered once just before the first item will occur. The 'Line' event is triggered for each item of the given type. The 'End' event is triggered once after the last item. For a multi-part message, we have this sequence: a) The message header OnHeaderBegin, then many OnHeaderLine, one for each line in the header. Lines can be continuated in the message. The event here is triggered with continuated lines concatenated (so it can be quite large !). After the last header line has been processed, the OnHeaderEnd is triggered once. b) The non-significant message part which can be empty. This is part 0. We get OnPartBegin once, then OnPartLine for each line and finally OnPartEnd once. c) The first significant part header with his three events, just like the message header: OnPartHeaderBegin, OnPartHeaderLine and OnPartHeaderEnd. d) The first significant part data with his three events: OnPartBegin once, OnPartLine for each line and OnPartEnd once at the end of the part. It's possible to have an empty part. This gives the OnPartBegin and OnPartEnd events and NO OnPartLine event. e) We can have many other parts. The sequence is always the same. We restart at point (b) here above for each part (header, then data). Note that there is often en empty part at the end of a message. TMimeDecode decode encoded parts using 'base64' and 'quoted-printable' methods. For those parts, the OnPartLine event will gives DECODED data. Other methods are passed not decoded. You can use the property ContentTransferEncoding to know which encoding method is used and add your own decoding mechanism. For each OnHeaderLine, OnPartHeaderLine and OnPartLine, you can find the actual data at the address pointed by the property CurrentData (a PChar). The reason for a PChar is that the data can be quite large. The data pointed is a null terminated string. You can get the length using StrLen, or convert to a string with StrPas. It is more efficient to process the data using a pointer. Using strings tends to copy the data several times. The OnPartLine event passes a PChar and a length to the handler. This actully point to the internal buffer and overwrite the original data (base64 and quote-printable method produce decoded data smaller tha encoded one). From the message header, the component extract the following values: From The message author. Not necessary the real author... Looks like "Francois Piette" Dest The message destination (To field, but To is a reserved word) Looks like "Francois Piette" Subject The message subject. Free text. Date The message date. Look like: Mon, 16 Feb 1998 12:45:11 -0800 ContentType 'multipart/mixed' or empty. For details about those header fields and others, read RFC-822 For each part, we have the following properties updated (the header is parsed on the fly): PartNumber Starting from 0 for the non-significant part PartLine Starting 1 for the first line of each part or header PartContentType Such as 'text/plain' or 'application/x-zip-compressed' PartCharset This is a complement for the PartContentType. ApplicationType When PartContentType is 'application/something', we get the 'something' extracted PartName This is the value for 'name=something' in the Content-Type header line. PartEncoding Encoding method (Content-Transfer-Encoding). Can be used to decode unsupported methods (supported methods are 'base64' and 'quoted-printable'. '7bit' and '8bit' does'nt generally require processing. PartDisposition Can be 'inline' or 'attachement' and is generally followed by a 'filename=something' PartFileName The specified filename in Content-Disposition header line. Be aware that the file name is not necessary suitable for windows ! Use it with caution... For details about those header fields and others, read RFC-1521. To write part data to files, you can either implement your own writing in the OnPartLine event handler, or use the DestStream property. If assigned, this property will be used to write the data. If not assigned, it will be ignore. To select a file name for each part, you can use the PartFileName property or the 'PartName' property or a comnination of both. But be aware that those value can be either missing or even invalid as a filename because the message was generated with another opertaing system which has different filename conventions. Updates: Apr 13, 1998 V1.01 Corrected a bug in ProcessLineBase64 which decoded one byte too much. Thanks to Rune Fredriksen . Apr 15, 1998 V1.02 Corrected bug in ProcessHeaderLine which retreived only the first word for each item. Added the ReturnPath property. Apr 24, 1998 V1.03 Removed the modification made in version 1.01 ! Apr 26, 1998 V1.04 Corrected a bug in ReallocMem with Delphi 1 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *

Classes

TMimeDecode -

Functions

Register - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *

Types

TMimeDecodePartLine

Constants

MimeDecodeVersion

Variables


Functions


procedure Register;

* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *

Types


TMimeDecodePartLine = procedure (Sender  : TObject;
                                     Data    : PChar;
                                     DataLen : Integer) of object

Constants

MimeDecodeVersion = 104


Variables