home *** CD-ROM | disk | FTP | other *** search
- {==============================================================================|
- | Project : Delphree - Synapse | 001.005.002 |
- |==============================================================================|
- | Content: MIME support procedures and functions |
- |==============================================================================|
- | The contents of this file are subject to the Mozilla Public License Ver. 1.1 |
- | (the "License"); you may not use this file except in compliance with the |
- | License. You may obtain a copy of the License at http://www.mozilla.org/MPL/ |
- | |
- | Software distributed under the License is distributed on an "AS IS" basis, |
- | WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for |
- | the specific language governing rights and limitations under the License. |
- |==============================================================================|
- | The Original Code is Synapse Delphi Library. |
- |==============================================================================|
- | The Initial Developer of the Original Code is Lukas Gebauer (Czech Republic).|
- | Portions created by Lukas Gebauer are Copyright (c)2000,2001. |
- | All Rights Reserved. |
- |==============================================================================|
- | Contributor(s): |
- |==============================================================================|
- | History: see HISTORY.HTM from distribution package |
- | (Found at URL: http://www.ararat.cz/synapse/) |
- |==============================================================================}
-
- unit MIMEpart;
-
- interface
-
- uses
- SysUtils, Classes,
- SynaChar, SynaCode, SynaUtil, MIMEinLn;
-
- type
-
- TMimePrimary = (MP_TEXT, MP_MULTIPART,
- MP_MESSAGE, MP_BINARY);
-
- TMimeEncoding = (ME_7BIT, ME_8BIT, ME_QUOTED_PRINTABLE,
- ME_BASE64, ME_UU, ME_XX);
-
- TMimePart = class(TObject)
- private
- FPrimary: string;
- FEncoding: string;
- FCharset: string;
- FPrimaryCode: TMimePrimary;
- FEncodingCode: TMimeEncoding;
- FCharsetCode: TMimeChar;
- FTargetCharset: TMimeChar;
- FSecondary: string;
- FDescription: string;
- FDisposition: string;
- FContentID: string;
- FBoundary: string;
- FFileName: string;
- FLines: TStringList;
- FDecodedLines: TMemoryStream;
- procedure SetPrimary(Value: string);
- procedure SetEncoding(Value: string);
- procedure SetCharset(Value: string);
- public
- constructor Create;
- destructor Destroy; override;
- procedure Clear;
- function ExtractPart(Value: TStringList; BeginLine: Integer): Integer;
- procedure DecodePart;
- procedure EncodePart;
- procedure MimeTypeFromExt(Value: string);
- published
- property Primary: string read FPrimary write SetPrimary;
- property Encoding: string read FEncoding write SetEncoding;
- property Charset: string read FCharset write SetCharset;
- property PrimaryCode: TMimePrimary read FPrimaryCode Write FPrimaryCode;
- property EncodingCode: TMimeEncoding read FEncodingCode Write FEncodingCode;
- property CharsetCode: TMimeChar read FCharsetCode Write FCharsetCode;
- property TargetCharset: TMimeChar read FTargetCharset Write FTargetCharset;
- property Secondary: string read FSecondary Write FSecondary;
- property Description: string read FDescription Write FDescription;
- property Disposition: string read FDisposition Write FDisposition;
- property ContentID: string read FContentID Write FContentID;
- property Boundary: string read FBoundary Write FBoundary;
- property FileName: string read FFileName Write FFileName;
- property Lines: TStringList read FLines;
- property DecodedLines: TMemoryStream read FDecodedLines;
- end;
-
- const
- MaxMimeType = 25;
- MimeType: array[0..MaxMimeType, 0..2] of string =
- (
- ('AU', 'audio', 'basic'),
- ('AVI', 'video', 'x-msvideo'),
- ('BMP', 'image', 'BMP'),
- ('DOC', 'application', 'MSWord'),
- ('EPS', 'application', 'Postscript'),
- ('GIF', 'image', 'GIF'),
- ('JPEG', 'image', 'JPEG'),
- ('JPG', 'image', 'JPEG'),
- ('MID', 'audio', 'midi'),
- ('MOV', 'video', 'quicktime'),
- ('MPEG', 'video', 'MPEG'),
- ('MPG', 'video', 'MPEG'),
- ('MP2', 'audio', 'mpeg'),
- ('MP3', 'audio', 'mpeg'),
- ('PDF', 'application', 'PDF'),
- ('PNG', 'image', 'PNG'),
- ('PS', 'application', 'Postscript'),
- ('QT', 'video', 'quicktime'),
- ('RA', 'audio', 'x-realaudio'),
- ('RTF', 'application', 'RTF'),
- ('SND', 'audio', 'basic'),
- ('TIF', 'image', 'TIFF'),
- ('TIFF', 'image', 'TIFF'),
- ('WAV', 'audio', 'x-wav'),
- ('WPD', 'application', 'Wordperfect5.1'),
- ('ZIP', 'application', 'ZIP')
- );
-
- function NormalizeHeader(Value: TStringList; var Index: Integer): string;
- function GenerateBoundary: string;
-
- implementation
-
- function NormalizeHeader(Value: TStringList; var Index: Integer): string;
- var
- s, t: string;
- n: Integer;
- begin
- s := Value[Index];
- Inc(Index);
- if s <> '' then
- while (Value.Count - 1) > Index do
- begin
- t := Value[Index];
- if t = '' then
- Break;
- for n := 1 to Length(t) do
- if t[n] = #9 then
- t[n] := ' ';
- if t[1] <> ' ' then
- Break
- else
- begin
- s := s + ' ' + Trim(t);
- Inc(Index);
- end;
- end;
- Result := s;
- end;
-
- {==============================================================================}
-
- constructor TMIMEPart.Create;
- begin
- inherited Create;
- FLines := TStringList.Create;
- FDecodedLines := TMemoryStream.Create;
- FTargetCharset := GetCurCP;
- end;
-
- destructor TMIMEPart.Destroy;
- begin
- FDecodedLines.Free;
- FLines.Free;
- inherited Destroy;
- end;
-
- {==============================================================================}
-
- procedure TMIMEPart.Clear;
- begin
- FPrimary := '';
- FEncoding := '';
- FCharset := '';
- FPrimaryCode := MP_TEXT;
- FEncodingCode := ME_7BIT;
- FCharsetCode := ISO_8859_1;
- FTargetCharset := GetCurCP;
- FSecondary := '';
- FDisposition := '';
- FContentID := '';
- FDescription := '';
- FBoundary := '';
- FFileName := '';
- FLines.Clear;
- FDecodedLines.Clear;
- end;
-
- {==============================================================================}
-
- function TMIMEPart.ExtractPart(Value: TStringList; BeginLine: Integer): Integer;
- var
- n, x, x1, x2: Integer;
- t: TStringList;
- s, su, b: string;
- st, st2: string;
- e: Boolean;
- fn: string;
- begin
- t := TStringlist.Create;
- try
- { defaults }
- FLines.Clear;
- Primary := 'text';
- FSecondary := 'plain';
- FDescription := '';
- Charset := 'US-ASCII';
- FFileName := '';
- Encoding := '7BIT';
-
- fn := '';
- x := BeginLine;
- b := FBoundary;
- { if multipart - skip pre-part }
- if b <> '' then
- while Value.Count > x do
- begin
- s := Value[x];
- Inc(x);
- if Pos('--' + b, s) = 1 then
- Break;
- end;
-
- { parse header }
- while Value.Count > x do
- begin
- s := NormalizeHeader(Value, x);
- if s = '' then
- Break;
- su := UpperCase(s);
- if Pos('CONTENT-TYPE:', su) = 1 then
- begin
- st := SeparateRight(su, ':');
- st2 := SeparateLeft(st, ';');
- Primary := SeparateLeft(st2, '/');
- FSecondary := SeparateRight(st2, '/');
- if (FSecondary = Primary) and (Pos('/', st2) < 1) then
- FSecondary := '';
- case FPrimaryCode of
- MP_TEXT:
- begin
- Charset := UpperCase(GetParameter(s, 'charset='));
- FFileName := GetParameter(s, 'name=');
- end;
- MP_MULTIPART:
- FBoundary := GetParameter(s, 'Boundary=');
- MP_MESSAGE:
- begin
- end;
- MP_BINARY:
- FFileName := GetParameter(s, 'name=');
- end;
- end;
- if Pos('CONTENT-TRANSFER-ENCODING:', su) = 1 then
- Encoding := SeparateRight(su, ':');
- if Pos('CONTENT-DESCRIPTION:', su) = 1 then
- FDescription := SeparateRight(s, ':');
- if Pos('CONTENT-DISPOSITION:', su) = 1 then
- begin
- FDisposition := SeparateRight(su, ':');
- FDisposition := Trim(SeparateLeft(FDisposition, ';'));
- fn := GetParameter(s, 'FileName=');
- end;
- if Pos('CONTENT-ID:', su) = 1 then
- FContentID := SeparateRight(s, ':');
- end;
-
- if (PrimaryCode = MP_BINARY) and (FFileName = '') then
- FFileName := fn;
- FFileName := InlineDecode(FFileName, getCurCP);
- FFileName := ExtractFileName(FFileName);
-
- { finding part content x1-begin x2-end }
- x1 := x;
- x2 := Value.Count - 1;
- { if multipart - end is before next boundary }
- if b <> '' then
- begin
- for n := x to Value.Count - 1 do
- begin
- x2 := n;
- s := Value[n];
- if Pos('--' + b, s) = 1 then
- begin
- Dec(x2);
- Break;
- end;
- end;
- end;
- { if content is multipart - content is delimited by their boundaries }
- if FPrimaryCode = MP_MULTIPART then
- begin
- for n := x to Value.Count - 1 do
- begin
- s := Value[n];
- if Pos('--' + FBoundary, s) = 1 then
- begin
- x1 := n;
- Break;
- end;
- end;
- for n := Value.Count - 1 downto x do
- begin
- s := Value[n];
- if Pos('--' + FBoundary, s) = 1 then
- begin
- x2 := n;
- Break;
- end;
- end;
- end;
- { copy content }
- for n := x1 to x2 do
- FLines.Add(Value[n]);
- Result := x2;
- { if content is multipart - find real end }
- if FPrimaryCode = MP_MULTIPART then
- begin
- e := False;
- for n := x2 + 1 to Value.Count - 1 do
- if Pos('--' + b, Value[n]) = 1 then
- begin
- e := True;
- Break;
- end;
- if not e then
- Result := Value.Count - 1;
- end;
- { if multipart - skip ending postpart}
- if b <> '' then
- begin
- x1 := Result;
- for n := x1 to Value.Count - 1 do
- begin
- s := Value[n];
- if Pos('--' + b, s) = 1 then
- begin
- s := TrimRight(s);
- x := Length(s);
- if x > 4 then
- if (s[x] = '-') and (S[x-1] = '-') then
- Result := Value.Count - 1;
- Break;
- end;
- end;
- end;
- finally
- t.Free;
- end;
- end;
-
- {==============================================================================}
-
- procedure TMIMEPart.DecodePart;
- const
- CRLF = #13#10;
- var
- n: Integer;
- s: string;
- begin
- FDecodedLines.Clear;
- for n := 0 to FLines.Count - 1 do
- begin
- s := FLines[n];
- case FEncodingCode of
- ME_7BIT:
- s := s + CRLF;
- ME_8BIT:
- begin
- s := CharsetConversion(s, FCharsetCode, FTargetCharset);
- s := s + CRLF;
- end;
- ME_QUOTED_PRINTABLE:
- begin
- if s = '' then
- s := CRLF
- else
- if s[Length(s)] <> '=' then
- s := s + CRLF;
- s := DecodeQuotedPrintable(s);
- if FPrimaryCode = MP_TEXT then
- s := CharsetConversion(s, FCharsetCode, FTargetCharset);
- end;
- ME_BASE64:
- begin
- if s <> '' then
- s := DecodeBase64(s);
- if FPrimaryCode = MP_TEXT then
- s := CharsetConversion(s, FCharsetCode, FTargetCharset);
- end;
- ME_UU:
- if s <> '' then
- s := DecodeUU(s);
- ME_XX:
- if s <> '' then
- s := DecodeXX(s);
- end;
- FDecodedLines.Write(Pointer(s)^, Length(s));
- end;
- FDecodedLines.Seek(0, soFromBeginning);
- end;
-
- {==============================================================================}
-
- procedure TMIMEPart.EncodePart;
- var
- l: TStringList;
- s, buff: string;
- n, x: Integer;
- begin
- if (FEncodingCode = ME_UU) or (FEncodingCode = ME_XX) then
- Encoding := 'base64';
- l := TStringList.Create;
- FLines.Clear;
- FDecodedLines.Seek(0, soFromBeginning);
- try
- case FPrimaryCode of
- MP_MULTIPART, MP_MESSAGE:
- FLines.LoadFromStream(FDecodedLines);
- MP_TEXT, MP_BINARY:
- if FEncodingCode = ME_BASE64 then
- begin
- while FDecodedLines.Position < FDecodedLines.Size do
- begin
- Setlength(Buff, 54);
- s := '';
- x := FDecodedLines.Read(pointer(Buff)^, 54);
- for n := 1 to x do
- s := s + Buff[n];
- if FPrimaryCode = MP_TEXT then
- s := CharsetConversion(s, FTargetCharset, FCharsetCode);
- s := EncodeBase64(s);
- FLines.Add(s);
- end;
- end
- else
- begin
- l.LoadFromStream(FDecodedLines);
- for n := 0 to l.Count - 1 do
- begin
- s := l[n];
- if FPrimaryCode = MP_TEXT then
- s := CharsetConversion(s, FTargetCharset, FCharsetCode);
- s := EncodeQuotedPrintable(s);
- FLines.Add(s);
- end;
- end;
-
- end;
- FLines.Add('');
- FLines.Insert(0, '');
- if FSecondary = '' then
- case FPrimaryCode of
- MP_TEXT:
- FSecondary := 'plain';
- MP_MULTIPART:
- FSecondary := 'mixed';
- MP_MESSAGE:
- FSecondary := 'rfc822';
- MP_BINARY:
- FSecondary := 'octet-stream';
- end;
- if FDescription <> '' then
- FLines.Insert(0, 'Content-Description: ' + FDescription);
- if FDisposition <> '' then
- begin
- s := '';
- if FFileName <> '' then
- s := '; FileName="' + FFileName + '"';
- FLines.Insert(0, 'Content-Disposition: ' + LowerCase(FDisposition) + s);
- end;
- if FContentID <> '' then
- FLines.Insert(0, 'Content-ID: ' + FContentID);
-
- case FEncodingCode of
- ME_7BIT:
- s := '7bit';
- ME_8BIT:
- s := '8bit';
- ME_QUOTED_PRINTABLE:
- s := 'Quoted-printable';
- ME_BASE64:
- s := 'Base64';
- end;
- case FPrimaryCode of
- MP_TEXT,
- MP_BINARY: FLines.Insert(0, 'Content-Transfer-Encoding: ' + s);
- end;
- case FPrimaryCode of
- MP_TEXT:
- s := FPrimary + '/' + FSecondary + '; charset=' + GetIDfromCP(FCharsetCode);
- MP_MULTIPART:
- s := FPrimary + '/' + FSecondary + '; boundary="' + FBoundary + '"';
- MP_MESSAGE:
- s := FPrimary + '/' + FSecondary + '';
- MP_BINARY:
- s := FPrimary + '/' + FSecondary + '; name="' + FFileName + '"';
- end;
- FLines.Insert(0, 'Content-type: ' + s);
- finally
- l.Free;
- end;
- end;
-
- {==============================================================================}
-
- procedure TMIMEPart.MimeTypeFromExt(Value: string);
- var
- s: string;
- n: Integer;
- begin
- Primary := '';
- FSecondary := '';
- s := UpperCase(ExtractFileExt(Value));
- if s = '' then
- s := UpperCase(Value);
- s := SeparateRight(s, '.');
- for n := 0 to MaxMimeType do
- if MimeType[n, 0] = s then
- begin
- Primary := MimeType[n, 1];
- FSecondary := MimeType[n, 2];
- Break;
- end;
- if Primary = '' then
- Primary := 'application';
- if FSecondary = '' then
- FSecondary := 'octet-string';
- end;
-
- {==============================================================================}
-
- procedure TMIMEPart.SetPrimary(Value: string);
- var
- s: string;
- begin
- FPrimary := Value;
- s := UpperCase(Value);
- FPrimaryCode := MP_BINARY;
- if Pos('TEXT', s) = 1 then
- FPrimaryCode := MP_TEXT;
- if Pos('MULTIPART', s) = 1 then
- FPrimaryCode := MP_MULTIPART;
- if Pos('MESSAGE', s) = 1 then
- FPrimaryCode := MP_MESSAGE;
- end;
-
- procedure TMIMEPart.SetEncoding(Value: string);
- var
- s: string;
- begin
- FEncoding := Value;
- s := UpperCase(Value);
- FEncodingCode := ME_7BIT;
- if Pos('8BIT', s) = 1 then
- FEncodingCode := ME_8BIT;
- if Pos('QUOTED-PRINTABLE', s) = 1 then
- FEncodingCode := ME_QUOTED_PRINTABLE;
- if Pos('BASE64', s) = 1 then
- FEncodingCode := ME_BASE64;
- if Pos('X-UU', s) = 1 then
- FEncodingCode := ME_UU;
- if Pos('X-XX', s) = 1 then
- FEncodingCode := ME_XX;
- end;
-
- procedure TMIMEPart.SetCharset(Value: string);
- begin
- FCharset := Value;
- FCharsetCode := GetCPFromID(Value);
- end;
-
- {==============================================================================}
-
- function GenerateBoundary: string;
- var
- x: Integer;
- begin
- Randomize;
- x := Random(MaxInt);
- Result := '--' + IntToHex(x, 8) + '_Synapse_message_boundary--';
- end;
-
- end.
-