home *** CD-ROM | disk | FTP | other *** search
/ Prima Shareware 3 / DuCom_Prima-Shareware-3_cd1.bin / PROGRAMO / delphi / TSMTP / MIME.PAS < prev    next >
Encoding:
Pascal/Delphi Source File  |  1996-04-26  |  10.5 KB  |  473 lines

  1. unit Mime;
  2.  
  3. interface
  4.  
  5. uses Classes, Windows, SysUtils, Forms, Dialogs, Registry;
  6.  
  7. const
  8.   MaxChars = 57;
  9.  
  10. type
  11.   TBinBytes = array[1..MaxChars] of byte;
  12.   TTxtBytes = array[1..2*MaxChars] of byte;
  13.   T24Bits = array[0..8*MaxChars] of boolean;
  14.  
  15. EUUInvalidCharacter = class(Exception)
  16.   constructor Create;
  17. end;
  18.  
  19.  EMIMEError = class(Exception);
  20.  
  21.  
  22.   TBase64 = class
  23.   private
  24.     TextStream : TStringList;
  25.     Stream : TStream;
  26.     CurSection : byte;
  27.     A24Bits : T24Bits;
  28.     FOnProgress : TNotifyEvent;
  29.     FOnStart : TNotifyEvent;
  30.     FOnEnd : TNotifyEvent;
  31.     function GenerateTxtBytes(tb : TBinBytes; NumOfBytes : byte) : string;
  32.     procedure GenerateBinBytes(InS : ShortString; BufPtr : pointer;
  33.                                var BytesGenerated : word);
  34.     function ByteFromTable(Ch : Char) : byte;
  35.     procedure DoProgress(Sender : TObject);
  36.     procedure DoStart(Sender : TObject);
  37.     procedure DoEnd(Sender : TObject);
  38.   public
  39.     Progress : Integer;
  40.     ProgressStep : Integer;
  41.     Canceled : boolean;
  42.     Table : string;
  43.     constructor Create(AStream : TStream; ATextStream : TStringList);
  44.     procedure Encode;
  45.     procedure Decode;
  46.     property OnProgress : TNotifyEvent read FOnProgress
  47.                              write FOnProgress;
  48.     property OnStart : TNotifyEvent read FOnStart write FOnStart;
  49.     property OnEnd : TNotifyEvent read FOnEnd write FOnEnd;
  50.   end;
  51.  
  52.   TQuotedPrintable = class(TComponent)
  53.   private
  54.     { Private declarations }
  55.   protected
  56.     { Protected declarations }
  57.     Stream : TStream;
  58.     Lines : TStringList;
  59.     procedure ReplaceHiChars(var s : ShortString);
  60.     procedure ReplaceHex(var s : ShortString);
  61.     procedure ReformatParagraph(Buf : PChar; Len : Integer;
  62.                TL : TStringList);
  63.   public
  64.     { Public declarations }
  65.     Canceled : boolean;
  66.     constructor Create(AStream : TStream; ALines : TStringList);
  67.     procedure Encode;
  68.     procedure Decode;
  69.   published
  70.     { Published declarations }
  71.   end;
  72.  
  73. function GetContentType(const FileName : string) : string;
  74. function MakeUniqueID : string;
  75.  
  76. implementation
  77.  
  78. constructor EUUInvalidCharacter.Create;
  79. begin
  80.   inherited Create('Invalid character in the input file');
  81. end;
  82.  
  83. {implementation for TBase64}
  84. constructor TBase64.Create(AStream : TStream; ATextStream : TStringList);
  85. begin
  86.   inherited Create;
  87.   Stream:=AStream;
  88.   TextStream:=ATextStream;
  89.   ProgressStep:=10;
  90.   Table:='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
  91.   FillChar(A24Bits,SizeOf(A24Bits),0);
  92. end;
  93.  
  94. procedure TBase64.DoProgress(Sender : TObject);
  95. begin
  96.   if Assigned(FOnProgress) then
  97.     FOnProgress(Sender);
  98. end;
  99.  
  100. procedure TBase64.DoStart(Sender : TObject);
  101. begin
  102.   if Assigned(FOnStart) then
  103.     FOnStart(Sender);
  104. end;
  105.  
  106. procedure TBase64.DoEnd(Sender : TObject);
  107. begin
  108.   if Assigned(FOnEnd) then
  109.     FOnEnd(Sender);
  110. end;
  111.  
  112. function TBase64.GenerateTxtBytes(tb : TBinBytes; NumOfBytes : byte) : string;
  113. var
  114.   i,j,k,b,m : word;
  115.   s : string;
  116. begin
  117.   k:=0;
  118.   FillChar(A24Bits,SizeOf(T24Bits),0);
  119.   for i:=1 to MaxChars do
  120.   begin
  121.     b:=tb[i];
  122.     for j:=7 DownTo 0 do
  123.     begin
  124.       m:=1 shl j;
  125.       if (b and m = m) then
  126.         A24Bits[k]:=true;
  127.       Inc(k);
  128.     end;
  129.   end;
  130.   s:=''; k:=0; m:=4*(MaxChars div 3);
  131.   for i:=1 to m do
  132.   begin
  133.     b:=0;
  134.     for j:=5 DownTo 0 do
  135.     begin
  136.       if A24Bits[k] then b:= b or (1 shl j);
  137.       Inc(k);
  138.     end;
  139.     s:=Concat(s,Table[b+1]);
  140.   end;
  141.   if (NumOfBytes=MaxChars) or (NumOfBytes mod 3=0) then
  142.      SetLength(s,4*NumOfBytes div 3)
  143.   else
  144.   begin
  145.     SetLength(s,4*NumOfBytes div 3+1);
  146.     while (Length(s) mod 4)<>0 do
  147.       s:=Concat(s,'=');
  148.   end;
  149.   Result:=s;
  150. end;
  151.  
  152. procedure TBase64.Encode;
  153. var
  154.   BytesRead : word;
  155.   ABinBytes : TBinBytes;
  156.   Total : LongInt;
  157. begin
  158.   DoStart(Self);
  159.   TextStream.Clear;
  160.   Progress:=0; Total:=0; Canceled:=false;
  161.   try
  162.     repeat
  163.       FillChar(ABinBytes,SizeOf(TBinBytes),0);
  164.       BytesRead:=Stream.Read(ABinBytes,MaxChars);
  165.       Inc(Total,BytesRead);
  166.       TextStream.Add(GenerateTxtBytes(ABinBytes,BytesRead));
  167.       Progress:=Round(100*Total/Stream.Size);
  168.       if Progress mod ProgressStep = 0 then
  169.          DoProgress(Self);
  170.       Application.ProcessMessages;
  171.     until (BytesRead<MaxChars) or Canceled;
  172.   finally
  173.     Progress:=100;
  174.     DoProgress(Self);
  175.     if Canceled then TextStream.Clear;
  176.     DoEnd(Self);
  177.   end;
  178. end;
  179.  
  180. function TBase64.ByteFromTable(Ch : Char) : byte;
  181. var
  182.   i : byte;
  183. begin
  184.   i:=1;
  185.   while (Ch<>Table[i]) and (i<=64) do Inc(i);
  186.   if i>64 then
  187.   begin
  188.     Result:=0;
  189.     if Ch<>'=' then
  190.       raise EUUInvalidCharacter.Create;
  191.   end
  192.   else
  193.     Result:=i-1;
  194. end;
  195.  
  196. procedure TBase64.GenerateBinBytes(InS : ShortString; BufPtr : pointer;
  197.                           var BytesGenerated : word);
  198. var
  199.   i,j,k,b,m : word;
  200.   ActualLen : byte;
  201. begin
  202.   FillChar(BufPtr^,MaxChars,0);
  203.   FillChar(A24Bits,SizeOf(T24Bits),0);
  204.   k:=0;
  205.   for i:=1 to Length(InS) do
  206.   begin
  207.     b:=ByteFromTable(InS[i]);
  208.     for j:=5 DownTo 0 do
  209.     begin
  210.       m:=1 shl j;
  211.       if (b and m = m) then
  212.         A24Bits[k]:=true;
  213.       Inc(k);
  214.     end;
  215.   end;
  216.   k:=0;
  217.   if Length(InS)<>4*MaxChars div 3 then
  218.   begin
  219.     ActualLen:=3*Length(InS) div 4;
  220.     while InS[Length(InS)]='=' do
  221.     begin
  222.       Dec(ActualLen);
  223.       Delete(InS,Length(InS),1);
  224.     end;
  225.   end
  226.   else
  227.     ActualLen:=MaxChars;
  228.   for i:=1 to ActualLen do
  229.   begin
  230.     b:=0;
  231.     for j:=7 DownTo 0 do
  232.     begin
  233.       if A24Bits[k] then b:= b or (1 shl j);
  234.       Inc(k);
  235.     end;
  236.     byte(PChar((PChar(BufPtr)+i-1))^):=b;
  237.   end;
  238.   BytesGenerated:=i-1;
  239. end;
  240.  
  241. procedure TBase64.Decode;
  242. var
  243.   BytesGenerated : word;
  244.   s : ShortString;
  245.   p : pointer;
  246.   i : LongInt;
  247. begin
  248.   DoStart(Self);
  249.   Progress:=0;
  250.   Canceled:=false;
  251.   i:=0;
  252.   try
  253.     GetMem(p,MaxChars);
  254.     repeat
  255.       FillChar(p^,MaxChars,0);
  256.       s:=TextStream[i];
  257.       GenerateBinBytes(s,p,BytesGenerated);
  258.       Stream.Write(p^,BytesGenerated);
  259.       Progress:=Round(100*i/(TextStream.Count-1));
  260.       if Progress mod ProgressStep = 0 then
  261.          DoProgress(Self);
  262.       Application.ProcessMessages;
  263.       Inc(i);
  264.     until (i>=TextStream.Count);
  265.   finally
  266.     Progress:=100;
  267.     DoProgress(Self);
  268.     FreeMem(p,MaxChars);
  269.     DoEnd(Self);
  270.   end;
  271. end;
  272.  
  273. {implementation for TQuotedPrintable}
  274.  
  275. const
  276.   BufSize=$6000;
  277.  
  278. constructor TQuotedPrintable.Create(AStream : TStream; ALines : TStringList);
  279. begin
  280.   Stream:=AStream;
  281.   Lines:=ALines;
  282.   Canceled:=false;
  283. end;
  284.  
  285. procedure TQuotedPrintable.ReplaceHiChars(var s : ShortString);
  286. var
  287.   sLen : byte absolute s;
  288.   i : byte;
  289. begin
  290.   i:=1;
  291.   while i<sLen do
  292.   begin
  293.     if Ord(s[i]) in [0..31,61,128..255] then
  294.     begin
  295.       Insert(Concat('=',IntToHex(Ord(s[i]),2)),s,i+1);
  296.       Delete(s,i,1);
  297.       Inc(i,2);
  298.     end;
  299.     Inc(i);
  300.   end;
  301. end;
  302.  
  303. procedure TQuotedPrintable.ReformatParagraph(Buf : PChar; Len : Integer;
  304.           TL : TStringList);
  305. var
  306.   cp,sp : PChar;
  307.   s : ShortString;
  308.   sLen : byte absolute s;
  309.   Finished : boolean;
  310. begin
  311.   sp:=Buf;
  312.   TL.Clear;
  313.   repeat
  314.     cp:=sp+Len;
  315.     Finished:=cp>StrEnd(Buf);
  316.     if Finished then cp:=StrEnd(Buf)
  317.     else
  318.     begin
  319.       while (cp^<>' ') and (cp>sp) do Dec(cp);
  320.       if cp=sp then
  321.         cp:=sp+Len;
  322.     end;
  323.     sLen:=cp-sp;
  324.     move(sp^,s[1],sLen);
  325.     if not Finished then s:=Concat(s,'=');
  326.     ReplaceHiChars(s);
  327.     TL.Add(s);
  328.     sp:=cp;
  329.   until Finished;
  330. end;
  331.  
  332. procedure TQuotedPrintable.Encode;
  333. var
  334.   j : Integer;
  335.   Ch : Char;
  336.   Buf : PChar;
  337.   Finished : boolean;
  338.   TempLines : TStringList;
  339. begin
  340.   Buf:=StrAlloc(BufSize);
  341.   TempLines:=TStringList.Create;
  342.   try
  343.     repeat
  344.       {Read a paragraph}
  345.       j:=0;
  346.       FillChar(Buf^,BufSize,0);
  347.       repeat
  348.         if j>=BufSize then
  349.           raise EMIMEError.Create('Paragraph is too large');
  350.         Stream.Read(Ch,1);
  351.         if Stream.Position=Stream.Size then
  352.         begin
  353.           Finished:=true;
  354.           move(Ch,(Buf+j)^,1);
  355.           Inc(j);
  356.         end
  357.         else
  358.         if Ch in [^M,^J] then
  359.         begin
  360.           Finished:=true;
  361.           Stream.Read(Ch,1);
  362.           if not (Ch in [^M,^J])
  363.             then Stream.Position:=Stream.Position-1;
  364.         end
  365.         else
  366.         begin
  367.           Finished:=false;
  368.           move(Ch,(Buf+j)^,1);
  369.           Inc(j);
  370.         end;
  371.         Application.ProcessMessages;
  372.       until Finished;
  373.       ReformatParagraph(Buf,65,TempLines);
  374.       if TempLines.Count=0 then Lines.Add('')
  375.         else Lines.AddStrings(TempLines);
  376.     until (Stream.Position=Stream.Size) or Canceled;
  377.   finally
  378.     TempLines.Free;
  379.     StrDispose(Buf);
  380.   end;
  381. end;
  382.  
  383. procedure TQuotedPrintable.ReplaceHex(var s : ShortString);
  384. var
  385.   i : byte;
  386.   sLen : byte absolute s;
  387.   Hex : byte;
  388. begin
  389.   i:=1;
  390.   while i<sLen do
  391.   begin
  392.     if (s[i]='=') then
  393.     begin
  394.       try
  395.         Hex:=StrToInt('$'+Copy(s,i+1,2));
  396.         Delete(s,i,3);
  397.         Insert(Char(Hex),s,i);
  398.       except
  399.         on EConvertError do {Do nothing}
  400.           else raise;
  401.       end;
  402.     end;
  403.     Inc(i);
  404.   end;
  405. end;
  406.  
  407. procedure TQuotedPrintable.Decode;
  408. var
  409.   Buf : PChar;
  410.   i : Integer;
  411.   Finished : boolean;
  412.   s : ShortString;
  413.   sLen : byte absolute s;
  414. begin
  415.   Buf:=StrAlloc(BufSize);
  416.   i:=-1;
  417.   try
  418.     repeat
  419.       FillChar(Buf^,BufSize,0);
  420.       repeat
  421.         Inc(i);
  422.         s:=Lines[i];
  423.         ReplaceHex(s);
  424.         Finished:=(sLen=0) or (s[sLen]<>'=');
  425.         if not Finished then Dec(sLen)
  426.           else s:=Concat(s,^M^J);
  427.         s:=Concat(s,#00);
  428.         if StrLen(Buf)+sLen>=BufSize then
  429.           raise EMIMEError.Create('Paragraph is too large');
  430.         StrCat(Buf,@s[1]);
  431.       until Finished;
  432.       Stream.Write(Buf^,StrLen(Buf));
  433.       Application.ProcessMessages;
  434.     until (i=Lines.Count-1) or Canceled;
  435.   finally
  436.     StrDispose(Buf);
  437.   end;
  438. end;
  439.  
  440. function GetContentType(const FileName : string) : string;
  441. var
  442.   Key : string;
  443. begin
  444.   Result:='';
  445.   with TRegistry.Create do
  446.   try
  447.     RootKey:=HKEY_CLASSES_ROOT;
  448.     Key:=ExtractFileExt(FileName);
  449.     if KeyExists(Key) then
  450.     begin
  451.       OpenKey(Key,false);
  452.       Result:=ReadString('Content Type');
  453.       CloseKey;
  454.     end;
  455.   finally
  456.     if Result='' then
  457.       Result:='application/octet-stream';
  458.     free;
  459.   end;
  460. end;
  461.  
  462. function MakeUniqueID : string;
  463. var
  464.   i : Integer;
  465. begin
  466.   Randomize;
  467.   Result:='';
  468.   for i:=1 to 8 do
  469.     Result:=Concat(Result,IntToStr(Random(9)));
  470. end;
  471.  
  472. end.
  473.