Mail2000.pas
上传用户:yjb1804
上传日期:2021-01-30
资源大小:3105k
文件大小:159k
源码类别:

Email服务器

开发平台:

Delphi

  1.     Exit;
  2.   FIsDecoded := True;
  3.   if FBody.Size = 0 then Exit;
  4.   Content := GetAttachInfo;
  5.   Encoding := LowerCase(GetLabelValue(_C_TE));
  6.   FDecoded.Clear;
  7.   if Encoding = _E_QP then
  8.   begin
  9.     GetMem(Buffer, FBody.Size+1);
  10.     StrLCopy(Buffer, FBody.Memory, FBody.Size);
  11.     Buffer[FBody.Size] := #0;
  12.     DecoLine := DecodeQuotedPrintable(Buffer);
  13.     FreeMem(Buffer);
  14.     GetMem(Buffer, Length(DecoLine)+1);
  15.     StrPCopy(Buffer, DecoLine);
  16.     FDecoded.Write(Buffer^, Length(DecoLine));
  17.     FreeMem(Buffer);
  18.   end
  19.   else
  20.   begin
  21.     if Encoding = _E_BA then
  22.     begin
  23.       nPos := 1;
  24.       SetLength(Data, FBody.Size);
  25.       FBody.Position := 0;
  26.       FBody.ReadBuffer(Data[1], FBody.Size);
  27.       while nPos >= 0 do
  28.       begin
  29.         DataLine(Data, DecoLine, nPos);
  30.         GetMem(Buffer, 132);
  31.         Size := DecodeLineBASE64(TrimSpace(DecoLine), Buffer);
  32.         if Size > 0 then
  33.           FDecoded.Write(Buffer^, Size);
  34.         FreeMem(Buffer);
  35.       end;
  36.     end
  37.     else
  38.     begin
  39.       if (Encoding = _E_UU) or (Encoding = _E_XU) then
  40.       begin
  41.         nPos := 1;
  42.         SetLength(Data, FBody.Size);
  43.         FBody.Position := 0;
  44.         FBody.ReadBuffer(Data[1], FBody.Size);
  45.         while nPos >= 0 do
  46.         begin
  47.           DataLine(Data, DecoLine, nPos);
  48.           GetMem(Buffer, 80);
  49.           Size := DecodeLineUUCODE(TrimSpace(DecoLine), Buffer);
  50.           FDecoded.Write(Buffer^, Size);
  51.           FreeMem(Buffer);
  52.         end;
  53.         EncodeBinary; // Convert to base64
  54.       end
  55.       else
  56.       begin
  57.         // 7bit, 8bit, binary and any other
  58.         GetMem(Buffer, FBody.Size);
  59.         FBody.Position := 0;
  60.         FBody.Read(Buffer^, FBody.Size);
  61.         FDecoded.Write(Buffer^, FBody.Size);
  62.         FreeMem(Buffer);
  63.       end;
  64.     end;
  65.   end;
  66. end;
  67. // Encode mail part
  68. procedure TMailPart.Encode(const ET: TEncodingType);
  69. begin
  70.   case ET of
  71.     etBase64: EncodeBinary;
  72.     etQuotedPrintable: EncodeText;
  73.     etNoEncoding:
  74.     begin
  75.       FDecoded.Position := 0;
  76.       FBody.Clear;
  77.       FBody.LoadFromStream(FDecoded);
  78.       SetLabelValue(_C_TE, '');
  79.     end;
  80.   end;
  81. end;
  82. // Encode mail part in quoted-printable
  83. procedure TMailPart.EncodeText;
  84. var
  85.   Buffer: String;
  86.   Encoded: String;
  87. begin
  88.   FBody.Clear;
  89.   SetLabelValue(_C_TE, _E_QP);
  90.   if FDecoded.Size > 0 then
  91.   begin
  92.     SetLength(Buffer, FDecoded.Size);
  93.     FDecoded.Position := 0;
  94.     FDecoded.ReadBuffer(Buffer[1], FDecoded.Size);
  95.     Encoded := EncodeQuotedPrintable(Buffer, False);
  96.     FBody.Write(Encoded[1], Length(Encoded));
  97.   end;
  98. end;
  99. // Encode mail part in base64
  100. procedure TMailPart.EncodeBinary;
  101. begin
  102.   EncodeBASE64(FBody, FDecoded);
  103.   SetLabelValue(_C_TE, _E_BA);
  104. end;
  105. { TMailPartList ============================================================== }
  106. // Retrieve an item from the list
  107. function TMailPartList.Get(const Index: Integer): TMailPart;
  108. begin
  109. Result := inherited Items[Index];
  110. end;
  111. // Finalize MailPartList
  112. destructor TMailPartList.Destroy;
  113. begin
  114.   inherited Destroy;
  115. end;
  116. { TMailRecipients ================================================================ }
  117. // Initialize MailRecipients
  118. constructor TMailRecipients.Create(MailMessage: TMailMessage2000; Field: String);
  119. begin
  120.   inherited Create;
  121.   FMessage := MailMessage;
  122.   FField := Field;
  123.   FNames := TStringList.Create;
  124.   FAddresses := TStringList.Create;
  125.   FCheck := -1;
  126. end;
  127. // Finalize MailRecipients
  128. destructor TMailRecipients.Destroy;
  129. begin
  130.   FNames.Free;
  131.   FAddresses.Free;
  132.   inherited Destroy;
  133. end;
  134. // Copy recipients to temporary string list
  135. procedure TMailRecipients.HeaderToStrings;
  136. var
  137.   Dests: String;
  138.   Loop, Occur, PL: Integer;
  139.   Quote: Boolean;
  140.   EndQuote: Char;
  141.   IsName: Boolean;
  142.   sName: String;
  143.   sAddress: String;
  144. begin
  145.   if Length(FMessage.FHeader.Text) = FCheck then
  146.     Exit;
  147.   Occur := 0;
  148.   PL := SearchStringList(FMessage.FHeader, FField+':', Occur);
  149.   FNames.Clear;
  150.   FAddresses.Clear;
  151.   while PL >= 0 do
  152.   begin
  153.     Dests := LabelValue(FMessage.FHeader[PL]);
  154.     FCheck := Length(FMessage.FHeader.Text);
  155.     sName := '';
  156.     sAddress := '';
  157.     Quote := False;
  158.     EndQuote := #0;
  159.     IsName := True;
  160.     for Loop := 1 to Length(Dests) do
  161.     begin
  162.       if ((not Quote) and (Dests[Loop] in ['"', '(']))
  163.       or (Quote and (Dests[Loop] = EndQuote)) then
  164.       begin
  165.         case Dests[Loop] of
  166.           '"': EndQuote := '"';
  167.           '(': EndQuote := ')';
  168.         end;
  169.         Quote := not Quote;
  170.         if Quote and IsName and (sName <> '') and (sAddress = '') then
  171.         begin
  172.           sAddress := TrimSpace(sName);
  173.           sName := '';
  174.         end;
  175.       end
  176.       else
  177.       begin
  178.         if (not Quote) and (Dests[Loop] in [',', ';']) then
  179.         begin
  180.           if sAddress = '' then
  181.           begin
  182.             FNames.Add('');
  183.             FAddresses.Add(TrimSpace(sName));
  184.           end
  185.           else
  186.           begin
  187.             FNames.Add(DecodeLine7Bit(TrimSpace(sName)));
  188.             FAddresses.Add(TrimSpace(sAddress));
  189.           end;
  190.           sName := '';
  191.           sAddress := '';
  192.           IsName := True;
  193.         end;
  194.         if IsName then
  195.         begin
  196.           if Quote then
  197.             sName := sName + Dests[Loop]
  198.           else
  199.             if not (Dests[Loop] in [',', ';', '<', '>']) then
  200.               sName := sName + Dests[Loop];
  201.         end
  202.         else
  203.         begin
  204.           if (not Quote) and (not (Dests[Loop] in [',', ';', '<', '>', #32])) then
  205.             sAddress := sAddress + Dests[Loop];
  206.         end;
  207.         if (not Quote) and (Dests[Loop] = '<') then
  208.           IsName := False;
  209.         if (not Quote) and (Dests[Loop] = '>') then
  210.           IsName := True;
  211.         if Quote and (sAddress <> '') then
  212.           IsName := True;
  213.       end;
  214.     end;
  215.     if Dests <> '' then
  216.     begin
  217.       if sAddress = '' then
  218.       begin
  219.         FNames.Add('');
  220.         FAddresses.Add(TrimSpace(sName));
  221.       end
  222.       else
  223.       begin
  224.         FNames.Add(DecodeLine7Bit(TrimSpace(sName)));
  225.         FAddresses.Add(TrimSpace(sAddress));
  226.       end;
  227.     end;
  228.     Inc(Occur);
  229.     PL := SearchStringList(FMessage.FHeader, FField+':', Occur);
  230.   end;
  231. end;
  232. // Replace recipients with temporary string list
  233. procedure TMailRecipients.StringsToHeader;
  234. var
  235.   Dests: String;
  236.   Loop: Integer;
  237. begin
  238.   repeat
  239.     FMessage.SetLabelValue(FField, '');
  240.   until SearchStringList(FMessage.FHeader, FField+':') < 0;
  241.   if FAddresses.Count > 0 then
  242.   begin
  243.     Dests := '';
  244.     for Loop := 0 to FAddresses.Count-1 do
  245.     begin
  246.       if TrimSpace(FNames[Loop]) <> '' then
  247.         Dests := Dests+'"'+EncodeLine7Bit(TrimSpace(FNames[Loop]), FMessage.FCharSet)+'"'#32'<'+TrimSpace(FAddresses[Loop])+'>'
  248.       else
  249.         Dests := Dests+'<'+TrimSpace(FAddresses[Loop])+'>';
  250.       if Loop < FAddresses.Count-1 then
  251.         Dests := Dests+','#32;
  252.     end;
  253.     FMessage.SetLabelValue(FField, Dests);
  254.   end
  255.   else
  256.   begin
  257.     FMessage.SetLabelValue(FField, '');
  258.   end;
  259.   FCheck := Length(FMessage.FHeader.Text);
  260. end;
  261. // Retrieve a name by index
  262. function TMailRecipients.GetName(const Index: Integer): String;
  263. begin
  264.   HeaderToStrings;
  265.   Result := FNames[Index];
  266. end;
  267. // Retrieve a address by index
  268. function TMailRecipients.GetAddress(const Index: Integer): String;
  269. begin
  270.   HeaderToStrings;
  271.   Result := FAddresses[Index];
  272. end;
  273. // Returns number of recipients
  274. function TMailRecipients.GetCount: Integer;
  275. begin
  276.   HeaderToStrings;
  277.   Result := FAddresses.Count;
  278. end;
  279. // Replace a name by index
  280. procedure TMailRecipients.SetName(const Index: Integer; const Name: String);
  281. begin
  282.   HeaderToStrings;
  283.   FNames[Index] := Name;
  284.   StringsToHeader;
  285. end;
  286. // Replace an address by index
  287. procedure TMailRecipients.SetAddress(const Index: Integer; const Address: String);
  288. begin
  289.   HeaderToStrings;
  290.   FAddresses[Index] := Address;
  291.   StringsToHeader;
  292. end;
  293. // Find an recipient by name
  294. function TMailRecipients.FindName(const Name: String): Integer;
  295. begin
  296.   HeaderToStrings;
  297.   Result := SearchStringList(FNames, Name);
  298. end;
  299. // Find an recipient by address
  300. function TMailRecipients.FindAddress(const Address: String): Integer;
  301. begin
  302.   HeaderToStrings;
  303.   Result := SearchStringList(FAddresses, Address);
  304. end;
  305. // Put all names on commatext
  306. function TMailRecipients.GetAllNames: String;
  307. begin
  308.   HeaderToStrings;
  309.   Result := FNames.CommaText;
  310. end;
  311. // Put all addresses on commatext
  312. function TMailRecipients.GetAllAddresses: String;
  313. begin
  314.   HeaderToStrings;
  315.   Result := FAddresses.CommaText;
  316. end;
  317. // Set all recipients from commatext
  318. procedure TMailRecipients.SetAll(const Names, Addresses: String);
  319. begin
  320.   FNames.CommaText := Names + ',';
  321.   FAddresses.CommaText := Addresses + ',';
  322.   FCheck := -1;
  323.   while FNames.Count < FAddresses.Count do
  324.     FNames.Add('');
  325.   while FAddresses.Count < FNames.Count do
  326.     FNames.Delete(FNames.Count-1);
  327.   StringsToHeader;
  328. end;
  329. // Add recipient names to TStrings
  330. procedure TMailRecipients.AddNamesTo(const Str: TStrings);
  331. begin
  332.   HeaderToStrings;
  333.   Str.AddStrings(FNames);
  334. end;
  335. // Add recipient addresses to TStrings
  336. procedure TMailRecipients.AddAddressesTo(const Str: TStrings);
  337. begin
  338.   HeaderToStrings;
  339.   Str.AddStrings(FAddresses);
  340. end;
  341. // Add a new recipient
  342. procedure TMailRecipients.Add(const Name, Address: String);
  343. begin
  344.   HeaderToStrings;
  345.   FNames.Add(Name);
  346.   FAddresses.Add(Address);
  347.   StringsToHeader;
  348. end;
  349. // Replace an recipient by index
  350. procedure TMailRecipients.Replace(const Index: Integer; const Name, Address: String);
  351. begin
  352.   HeaderToStrings;
  353.   FNames[Index] := Name;
  354.   FAddresses[Index] := Address;
  355.   StringsToHeader;
  356. end;
  357. // Delete an recipient by index
  358. procedure TMailRecipients.Delete(const Index: Integer);
  359. begin
  360.   HeaderToStrings;
  361.   FNames.Delete(Index);
  362.   FAddresses.Delete(Index);
  363.   StringsToHeader;
  364. end;
  365. // Delete all recipients
  366. procedure TMailRecipients.Clear;
  367. begin
  368.   FNames.Clear;
  369.   FAddresses.Clear;
  370.   FMessage.SetLabelValue(FField, '');
  371.   FCheck := Length(FMessage.FHeader.Text);
  372. end;
  373. { TMailMessage2000 =============================================================== }
  374. // Initialize MailMessage
  375. constructor TMailMessage2000.Create(AOwner: TComponent);
  376. begin
  377.   inherited Create(AOwner);
  378.   FAttachList := TMailPartList.Create;
  379.   FTextPlain := TStringList.Create;
  380.   FTextHTML := TStringList.Create;
  381.   FTextPlainPart := nil;
  382.   FTextHTMLPart := nil;
  383.   FMixedPart := nil;
  384.   FRelatedPart := nil;
  385.   FAlternativePart := nil;
  386.   FNeedRebuild := False;
  387.   FNeedNormalize := False;
  388.   FNeedFindParts := False;
  389.   FCharset := _CHARSET;
  390.   FNameCount := 0;
  391.   FOwnerMessage := Self;
  392.   FToList := TMailRecipients.Create(Self, 'To');
  393.   FCcList := TMailRecipients.Create(Self, 'Cc');
  394.   FBccList := TMailRecipients.Create(Self, 'Bcc');
  395.   FTextEncoding := etQuotedPrintable;
  396.   FAttachEncoding := etBase64;
  397.   FEmbedMethod := emContentLocation;
  398.   FContentLocationBase := 'http://localhost/';
  399. end;
  400. // Finalize MailMessage
  401. destructor TMailMessage2000.Destroy;
  402. begin
  403.   inherited Destroy;
  404.   FAttachList.Free;
  405.   FTextPlain.Free;
  406.   FTextHTML.Free;
  407.   FToList.Free;
  408.   FCcList.Free;
  409.   FBccList.Free;
  410. end;
  411. // Get a dest. name from a field
  412. procedure TMailMessage2000.GetSenderData(const Field: String; var Name, Address: String);
  413. var
  414.   Dests: String;
  415.   Loop: Integer;
  416.   Quote: Boolean;
  417.   Unknown: String;
  418.   EndQuote, Phase: Char;
  419. begin
  420.   Dests := TrimSpace(GetLabelValue(Field));
  421.   Name := '';
  422.   Address := '';
  423.   Unknown := '';
  424.   Quote := False;
  425.   EndQuote := #0;
  426.   Phase := 'U';
  427.   for Loop := 1 to Length(Dests) do
  428.   begin
  429.     if ((not Quote) and (Dests[Loop] in ['"', '(']))
  430.     or (Quote and (Dests[Loop] = EndQuote)) then
  431.     begin
  432.       case Dests[Loop] of
  433.         '"': EndQuote := '"';
  434.         '(': EndQuote := ')';
  435.       end;
  436.       Quote := not Quote;
  437.       if Quote then
  438.       begin
  439.         if Phase = 'U' then
  440.           Address := Unknown;
  441.         Phase := 'N';
  442.       end
  443.       else
  444.       begin
  445.         Phase := 'A';
  446.       end;
  447.     end
  448.     else
  449.     begin
  450.       if (not Quote) and (Dests[Loop] = '<') then
  451.       begin
  452.         if Phase = 'U' then
  453.           Name := Unknown;
  454.           
  455.         Phase := 'A';
  456.       end
  457.       else
  458.       begin
  459.         if (not Quote) and (Dests[Loop] = '>') then
  460.         begin
  461.           Phase := 'N';
  462.         end
  463.         else
  464.         begin
  465.           if Phase = 'A' then
  466.             Address := Address + Dests[Loop];
  467.           if Phase = 'N' then
  468.             Name := Name + Dests[Loop];
  469.           if Phase = 'U' then
  470.             Unknown := Unknown + Dests[Loop];
  471.         end;
  472.       end;
  473.     end;
  474.   end;
  475.   if Phase = 'U' then
  476.     Address := Unknown;
  477.   Name := DecodeLine7Bit(TrimSpace(Name));
  478.   Address := TrimSpace(Address);
  479. end;
  480. // Count the instances of 'Received' fields in header
  481. function TMailMessage2000.GetReceivedCount: Integer;
  482. begin
  483.   Result := 0;
  484.   while SearchStringList(FHeader, 'Received:', Result) >= 0 do
  485.     Inc(Result);
  486. end;
  487. // Retrieve a 'Received' field
  488. function TMailMessage2000.GetReceived(const Index: Integer): TReceived;
  489. var
  490.   Dests: String;
  491.   Loop: Integer;
  492.   Quote: Integer;
  493.   Value: String;
  494.   Field: TReceivedField;
  495. begin
  496.   Result.From := '';
  497.   Result.By := '';
  498.   Result.Address := '';
  499.   Result.Date := 0;
  500.   Dests := Trim(Copy(FHeader[SearchStringList(FHeader, 'Received', Index)], 10, 9999))+#1;
  501.   Value := '';
  502.   Field := reNone;
  503.   Quote := 0;
  504.   for Loop := 1 to Length(Dests) do
  505.   begin
  506.     if Dests[Loop] in ['(', '['] then
  507.       Inc(Quote);
  508.     if Dests[Loop] in [')', ']'] then
  509.       Dec(Quote);
  510.     if Quote < 0 then
  511.       Quote := 0;
  512.     if (not (Dests[Loop] in ['"', '<', '>', #39, ')', ']'])) and (Quote = 0) then
  513.     begin
  514.       if (Dests[Loop] = #32) and (Field = reNone) then
  515.       begin
  516.         if LowerCase(Trim(Value)) = 'from' then
  517.           Field := reFrom;
  518.         if LowerCase(Trim(Value)) = 'by' then
  519.           Field := reBy;
  520.         if LowerCase(Trim(Value)) = 'for' then
  521.           Field := reFor;
  522.         Value := '';
  523.       end;
  524.       if Dests[Loop] in [#32, ';'] then
  525.       begin
  526.         if (Trim(Value) <> '') and (Field in [reFrom, reBy, reFor]) then
  527.         begin
  528.           case Field of
  529.             reFrom: Result.From := Trim(Value);
  530.             reBy: Result.By := Trim(Value);
  531.             reFor: Result.Address := Trim(Value);
  532.           end;
  533.           Value := '';
  534.           Field := reNone;
  535.         end;
  536.       end;
  537.       if not (Dests[Loop] in [#32, ';']) then
  538.       begin
  539.         Value := Value + Dests[Loop];
  540.       end;
  541.       if Dests[Loop] = ';' then
  542.       begin
  543.         Value := Copy(Dests, Loop+1, Length(Dests));
  544.         Result.Date := MailDateToDelphiDate(Trim(Value));
  545.         Break;
  546.       end;
  547.     end;
  548.   end;
  549. end;
  550. // Add a 'Received:' in message header
  551. procedure TMailMessage2000.AddHop(const From, By, Aplic, Address: String);
  552. var
  553.   Text: String;
  554. begin
  555.   Text := 'Received:';
  556.   if From <> '' then
  557.     Text := Text + #32'from'#32+From;
  558.   if By <> '' then
  559.     Text := Text + #32'by'#32+By;
  560.   if Aplic <> '' then
  561.     Text := Text + #32'with'#32+Aplic;
  562.   if Address <> '' then
  563.     Text := Text + #32'for'#32'<'+Address+'>';
  564.   Text := Text + ';'#32+DelphiDateToMailDate(Now);
  565.   FHeader.Insert(0, Text);
  566. end;
  567. // Get the From: name
  568. function TMailMessage2000.GetFromName: String;
  569. var
  570.   Void: String;
  571. begin
  572.   GetSenderData(_FFR, Result, Void);
  573. end;
  574. // Get the From: address
  575. function TMailMessage2000.GetFromAddress: String;
  576. var
  577.   Void: String;
  578. begin
  579.   GetSenderData(_FFR, Void, Result);
  580. end;
  581. // Get the Reply-To: name
  582. function TMailMessage2000.GetReplyToName: String;
  583. var
  584.   Void: String;
  585. begin
  586.   GetSenderData(_FRT, Result, Void);
  587. end;
  588. // Get the Reply-To: address
  589. function TMailMessage2000.GetReplyToAddress: String;
  590. var
  591.   Void: String;
  592. begin
  593.   GetSenderData(_FRT, Void, Result);
  594. end;
  595. // Get the Retrun-Receipt name
  596. function TMailMessage2000.GetReceiptName: String;
  597. var
  598.   Void: String;
  599. begin
  600.   GetSenderData(_DNT, Result, Void);
  601. end;
  602. // Get the Return-Receipt address
  603. function TMailMessage2000.GetReceiptAddress: String;
  604. var
  605.   Void: String;
  606. begin
  607.   GetSenderData(_DNT, Void, Result);
  608. end;
  609. // Set the From: name/address
  610. procedure TMailMessage2000.SetFrom(const Name, Address: String);
  611. begin
  612.   if (Name <> '') and (Address <> '') then
  613.     SetLabelValue(_FFR, '"' + EncodeLine7Bit(Name, FCharset) + '" <' + Address + '>')
  614.   else
  615.     if Address <> '' then
  616.       SetLabelValue(_FFR, '<' + Address + '>')
  617.     else
  618.       SetLabelValue(_FFR, '');
  619. end;
  620. // Set the Reply-To: name/address
  621. procedure TMailMessage2000.SetReplyTo(const Name, Address: String);
  622. begin
  623.   if (Name <> '') and (Address <> '') then
  624.     SetLabelValue(_FRT, '"' + EncodeLine7Bit(Name, FCharset) + '" <' + Address + '>')
  625.   else
  626.     if Address <> '' then
  627.       SetLabelValue(_FRT, '<' + Address + '>')
  628.     else
  629.       SetLabelValue(_FRT, '');
  630. end;
  631. // Set the Return-Receipt name/address
  632. procedure TMailMessage2000.SetReceipt(const Name, Address: String);
  633. begin
  634.   if (Name <> '') and (Address <> '') then
  635.     SetLabelValue(_DNT, '"' + EncodeLine7Bit(Name, FCharset) + '" <' + Address + '>')
  636.   else
  637.     if Address <> '' then
  638.       SetLabelValue(_DNT, '<' + Address + '>')
  639.     else
  640.       SetLabelValue(_DNT, '');
  641. end;
  642. // Get the subject
  643. function TMailMessage2000.GetSubject: String;
  644. begin
  645.   try
  646.     Result := DecodeLine7Bit(GetLabelValue('Subject'));
  647.   except
  648.     on e:Exception do
  649.       MessageDlg('错误原因:' + #13#10#13#10+e.Message+#13#10,  mtError, [mbOK], 0);
  650.   end;
  651. end;
  652. // Set the subject
  653. procedure TMailMessage2000.SetSubject(const Subject: String);
  654. begin
  655.   SetLabelValue('Subject', EncodeLine7Bit(Subject, FCharset))
  656. end;
  657. // Get the mail priority
  658. function TMailMessage2000.GetPriority: TMailPriority;
  659. begin
  660.   Result := TMailPriority(StrToIntDef(GetToken(0, GetLabelValue(_XPRI), #32, '("', ')"'), 3)-1);
  661. end;
  662. // Set the mail priority
  663. procedure TMailMessage2000.SetPriority(const Priority: TMailPriority);
  664. begin
  665.   SetLabelValue(_XPRI, IntToStr(Ord(Priority)+1));
  666. end;
  667. // Get the date in TDateTime format
  668. function TMailMessage2000.GetDate: TDateTime;
  669. begin
  670.   Result := MailDateToDelphiDate(TrimSpace(GetLabelValue('Date')));
  671. end;
  672. // Set the date in RFC822 format
  673. procedure TMailMessage2000.SetDate(const Date: TDateTime);
  674. begin
  675.   SetLabelValue('Date', DelphiDateToMailDate(Date));
  676. end;
  677. // Get message id
  678. function TMailMessage2000.GetMessageId: String;
  679. begin
  680.   Result := GetLabelValue(_M_ID);
  681. end;
  682. // Set a unique message id (the parameter is just the host)
  683. procedure TMailMessage2000.SetMessageId(const MessageId: String);
  684. var
  685.   IDStr: String;
  686. begin
  687.   IDStr := '<'+FormatDateTime('yyyymmddhhnnss', Now)+'.'+TrimSpace(Format('%8x', [Random($FFFFFFFF)]))+'.'+TrimSpace(Format('%8x', [Random($FFFFFFFF)]))+'@'+MessageId+'>';
  688.   SetLabelValue(_M_ID, IDStr);
  689. end;
  690. // Searches for attached files and determines AttachList, TextPlain, TextHTML.
  691. procedure TMailMessage2000.FindParts;
  692.   function GetPart(Part: TMailPart): Boolean;
  693.     function GetText(Info: String): Boolean;
  694.     var
  695.       Buffer: PChar;
  696.     begin
  697.       Result := False;
  698.       if FTextPlainPart = nil then
  699.       begin
  700.         if (Info = _T_P) or (Info = _TEX) then
  701.         begin
  702.           if Part.Decode and (Part.Decoded.Size > 0) then
  703.           begin
  704.             FTextPlainPart := Part;
  705.             GetMem(Buffer, Part.FDecoded.Size+1);
  706.             StrLCopy(Buffer, Part.FDecoded.Memory, Part.FDecoded.Size);
  707.             Buffer[Part.FDecoded.Size] := #0;
  708.             FTextPlain.SetText(Buffer);
  709.             FreeMem(Buffer);
  710.             Result := True;
  711.           end;
  712.         end;
  713.       end;
  714.       if (FTextHTMLPart = nil) and (Info = _T_H) then
  715.       begin
  716.         if Part.Decode and (Part.Decoded.Size > 0) then
  717.         begin
  718.           FTextHTMLPart := Part;
  719.           GetMem(Buffer, Part.FDecoded.Size+1);
  720.           StrLCopy(Buffer, Part.FDecoded.Memory, Part.FDecoded.Size);
  721.           Buffer[Part.FDecoded.Size] := #0;
  722.           FTextHTML.SetText(Buffer);
  723.           FreeMem(Buffer);
  724.           Result := True;
  725.         end;
  726.       end;
  727.     end;
  728.   begin
  729.     Result := True;
  730.     // Check for multipart/mixed
  731.     if (FMixedPart = nil) and (Part.GetAttachInfo = _M_M) then
  732.     begin
  733.       FMixedPart := Part;
  734.       Exit;
  735.     end;
  736.     // Check for multipart/related
  737.     if (FRelatedPart = nil) and (Part.GetAttachInfo = _M_R) then
  738.     begin
  739.       FRelatedPart := Part;
  740.       Exit;
  741.     end;
  742.     // Check for multipart/alternative
  743.     if (FAlternativePart = nil) and (Part.GetAttachInfo = _M_A) then
  744.     begin
  745.       FAlternativePart := Part;
  746.       Exit;
  747.     end;
  748.     // Check for texts (when message is only one text)
  749.     if (Part = Self) and ((Copy(Part.GetAttachInfo, 1, Length(_TXT)) = _TXT) or (Part.GetAttachInfo = _TEX)) and (FSubPartList.Count = 0) then
  750.     begin
  751.       if GetText(Part.GetAttachInfo) then
  752.         Exit;
  753.     end;
  754.     // Check for texts (when message is only one text - no mime info)
  755.     if (Part = Self) and (Part.GetAttachInfo = '') and (FSubPartList.Count = 0) then
  756.     begin
  757.       if GetText(_T_P) then
  758.         Exit;
  759.     end;
  760.     // Check for texts (when message has one text plus attachs)
  761.     if (FMixedPart <> nil) and (Part.FOwnerPart = FMixedPart) and (FAlternativePart = nil) then
  762.     begin
  763.       if GetText(Part.GetAttachInfo) then
  764.         Exit;
  765.     end;
  766.     // Check for texts (when message one text with embedded)
  767.     if (FRelatedPart <> nil) and (Part.FOwnerPart = FRelatedPart) then
  768.     begin
  769.       if GetText(Part.GetAttachInfo) then
  770.         Exit;
  771.     end;
  772.     // Check for texts (when message has alternative texts)
  773.     if (FAlternativePart <> nil) and (Part.FOwnerPart = FAlternativePart) then
  774.     begin
  775.       if GetText(Part.GetAttachInfo) then
  776.         Exit;
  777.     end;
  778.     // If everything else failed, assume attachment
  779.     if Part.FSubPartList.Count = 0 then
  780.     begin
  781.       Part.FEmbedded := Part.FOwnerPart = FRelatedPart;
  782.       FAttachList.Add(Part);
  783.     end;
  784.   end;
  785.   procedure DecodeRec(MP: TMailPart);
  786.   var
  787.     Loop: Integer;
  788.   begin
  789.     if GetPart(MP) then
  790.     begin
  791.       for Loop := 0 to MP.FSubPartList.Count-1 do
  792.       begin
  793.         DecodeRec(MP.FSubPartList[Loop]);
  794.       end;
  795.     end;
  796.   end;
  797. begin
  798.   if not FNeedFindParts then
  799.     Exit;
  800.   FAttachList.Clear;
  801.   FTextPlainPart := nil;
  802.   FTextHTMLPart := nil;
  803.   FMixedPart := nil;
  804.   FRelatedPart := nil;
  805.   FAlternativePart := nil;
  806.   FTextPlain.Clear;
  807.   FTextHTML.Clear;
  808.   FNeedFindParts := False;
  809.   DecodeRec(Self);
  810. end;
  811. // Ajust parts to the Mail2000 standards
  812. procedure TMailMessage2000.Normalize(const Kind: TNormalizer = nrFirst);
  813. var
  814.   nLoop, nOcor: Integer;
  815.   SaveBody, TmpPart, TmpMixed, TmpRelated, TmpAlternative: TMailPart;
  816.   FName: String;
  817.   nTexts, nAttachs, nEmbedded: Integer;
  818.   procedure CreateMixed(Father: TMailPart);
  819.   begin
  820.     if Father = nil then
  821.     begin
  822.       SetLabelValue(_C_T, _M_M);
  823.       SetLabelParamValue(_C_T, _BDRY, '"'+GenerateBoundary+'_mixed"');
  824.       TmpMixed := Self;
  825.     end
  826.     else
  827.     begin
  828.       TmpMixed := TMailPart.Create(Self);
  829.       TmpMixed.FOwnerMessage := Self;
  830.       TmpMixed.FOwnerPart := Father;
  831.       TmpMixed.FParentBoundary := Father.GetBoundary;
  832.       TmpMixed.SetLabelValue(_C_T, _M_R);
  833.       TmpMixed.SetLabelParamValue(_C_T, _BDRY, '"'+GenerateBoundary+'_Mixed"');
  834.       Father.FSubPartList.Add(TmpMixed);
  835.     end;
  836.   end;
  837.   procedure CreateRelated(Father: TMailPart);
  838.   begin
  839.     if Father = nil then
  840.     begin
  841.       SetLabelValue(_C_T, _M_R);
  842.       SetLabelParamValue(_C_T, _BDRY, '"'+GenerateBoundary+'_related"');
  843.       TmpRelated := Self;
  844.     end
  845.     else
  846.     begin
  847.       TmpRelated := TMailPart.Create(Self);
  848.       TmpRelated.FOwnerMessage := Self;
  849.       TmpRelated.FOwnerPart := Father;
  850.       TmpRelated.FParentBoundary := Father.GetBoundary;
  851.       TmpRelated.SetLabelValue(_C_T, _M_R);
  852.       TmpRelated.SetLabelParamValue(_C_T, _BDRY, '"'+GenerateBoundary+'_related"');
  853.       Father.FSubPartList.Add(TmpRelated);
  854.     end;
  855.   end;
  856.   procedure CreateAlternative(Father: TMailPart);
  857.   begin
  858.     if Father = nil then
  859.     begin
  860.       SetLabelValue(_C_T, _M_A);
  861.       SetLabelParamValue(_C_T, _BDRY, '"'+GenerateBoundary+'_alternative"');
  862.       TmpAlternative := Self;
  863.     end
  864.     else
  865.     begin
  866.       TmpAlternative := TMailPart.Create(Self);
  867.       TmpAlternative.FOwnerMessage := Self;
  868.       TmpAlternative.FOwnerPart := Father;
  869.       TmpAlternative.FParentBoundary := Father.GetBoundary;
  870.       TmpAlternative.SetLabelValue(_C_T, _M_A);
  871.       TmpAlternative.SetLabelParamValue(_C_T, _BDRY, '"'+GenerateBoundary+'_alternative"');
  872.       Father.FSubPartList.Add(TmpAlternative);
  873.     end;
  874.   end;
  875.   procedure CreateTextPlain(Father: TMailPart);
  876.   begin
  877.     FTextPlainPart.Remove;
  878.     if Father = nil then
  879.     begin
  880.       SetLabelValue(_C_T, _T_P);
  881.       SetLabelValue(_C_D, _INLN);
  882.       FTextPlainPart.Decode;
  883.       FTextPlainPart.FDecoded.Position := 0;
  884.       FDecoded.LoadFromStream(FTextPlainPart.FDecoded);
  885.       Encode(FTextEncoding);
  886.       FTextPlainPart.Free;
  887.       FTextPlainPart := Self;
  888.     end
  889.     else
  890.     begin
  891.       FTextPlainPart.FOwnerPart := Father;
  892.       FTextPlainPart.FParentBoundary := Father.GetBoundary;
  893.       FTextPlainPart.SetLabelValue(_C_T, _T_P);
  894.       FTextPlainPart.SetLabelValue(_C_D, _INLN);
  895.       FTextPlainPart.Decode;
  896.       FTextPlainPart.Encode(FTextEncoding);
  897.       FTextPlainPart.SetLabelValue(_C_L, IntToStr(FTextPlainPart.FBody.Size));
  898.       FTextPlainPart.FSubPartList.Clear;
  899.       Father.FSubPartList.Add(FTextPlainPart);
  900.     end;
  901.   end;
  902.   procedure CreateTextHTML(Father: TMailPart);
  903.   begin
  904.     FTextHTMLPart.Remove;
  905.     if Father = nil then
  906.     begin
  907.       SetLabelValue(_C_T, _T_H);
  908.       SetLabelValue(_C_D, _INLN);
  909.       FTextHTMLPart.Decode;
  910.       FTextHTMLPart.FDecoded.Position := 0;
  911.       FDecoded.LoadFromStream(FTextHTMLPart.FDecoded);
  912.       Encode(FTextEncoding);
  913.       FTextHTMLPart.Free;
  914.       FTextHTMLPart := Self;
  915.     end
  916.     else
  917.     begin
  918.       FTextHTMLPart.FOwnerPart := Father;
  919.       FTextHTMLPart.FParentBoundary := Father.GetBoundary;
  920.       FTextHTMLPart.SetLabelValue(_C_T, _T_H);
  921.       FTextHTMLPart.SetLabelValue(_C_D, _INLN);
  922.       FTextHTMLPart.Decode;
  923.       FTextHTMLPart.Encode(FTextEncoding);
  924.       FTextHTMLPart.SetLabelValue(_C_L, IntToStr(FTextHTMLPart.FBody.Size));
  925.       FTextHTMLPart.FSubPartList.Clear;
  926.       Father.FSubPartList.Add(FTextHTMLPart);
  927.     end;
  928.   end;
  929.   procedure CreateAttachment(var Part: TMailPart; Father: TMailPart);
  930.   begin
  931.     Part.Remove;
  932.     if Part.GetLabelValue(_C_T) = '' then
  933.     begin
  934.       Part.SetLabelValue(_C_T, _A_OS);
  935.     end;
  936.     FName := Part.GetFileName;
  937.     if (FName = '') then
  938.     begin
  939.       FName := 'file_'+IntToStr(FNameCount)+GetMimeExtension(Part.GetLabelValue(_C_T));
  940.       Inc(FNameCount);
  941.     end;
  942.     Part.SetLabelValue(_XM2A, '"'+EncodeLine7Bit(FName, FCharSet)+'"');
  943.     if Part.FEmbedded then
  944.     begin
  945.       Part.SetLabelParamValue(_XM2A, _EMBD, 'yes');
  946.       case FEmbedMethod of
  947.         emContentID:
  948.           if Part.GetLabelValue(_C_ID) = '' then
  949.             Part.SetLabelValue(_C_ID, '<'+FName+'>');
  950.         emContentLocation:
  951.           Part.SetLabelValue(_C_LC, FContentLocationBase+FName);
  952.       end;
  953.       Part.SetLabelValue(_C_D, _INLN);
  954.       Part.FOwnerPart := TmpRelated;
  955.       Part.FParentBoundary := TmpRelated.GetBoundary;
  956.       TmpRelated.FSubPartList.Add(Part);
  957.     end
  958.     else
  959.     begin
  960.       Part.SetLabelParamValue(_XM2A, _EMBD, 'no');
  961.       if (Part.GetLabelParamValue(_C_T, _NAME) = '') then
  962.       begin
  963.         Part.SetLabelParamValue(_C_T, _NAME, '"'+EncodeLine7Bit(FName, FCharSet)+'"');
  964.       end;
  965.       if (Part.GetLabelParamValue(_C_D, _FLNM) = '') then
  966.       begin
  967.         Part.SetLabelParamValue(_C_D, _FLNM, '"'+EncodeLine7Bit(FName, FCharSet)+'"');
  968.       end;
  969.       if Father <> nil then
  970.       begin
  971.         Part.SetLabelValue(_C_D, _ATCH);
  972.         Part.FOwnerPart := Father;
  973.         Part.FParentBoundary := Father.GetBoundary;
  974.         Father.FSubPartList.Add(Part);
  975.       end
  976.       else
  977.       begin
  978.         // Search for "Content-"
  979.         nOcor := 0;
  980.         repeat
  981.         begin
  982.           nLoop := SearchStringList(Part.FHeader, _CONT, nOcor);
  983.           Inc(nOcor);
  984.           if nLoop >= 0 then
  985.             FHeader.Add(Part.FHeader[nLoop]);
  986.         end
  987.         until nLoop < 0;
  988.         // Search for "X-Mail2000-"
  989.         nOcor := 0;
  990.         repeat
  991.         begin
  992.           nLoop := SearchStringList(Part.FHeader, _X_M2, nOcor);
  993.           Inc(nOcor);
  994.           if nLoop >= 0 then
  995.             FHeader.Add(Part.FHeader[nLoop]);
  996.         end
  997.         until nLoop < 0;
  998.         if not Part.FIsDecoded then
  999.           Part.Decode; 
  1000.         Part.FDecoded.Position := 0;
  1001.         FDecoded.LoadFromStream(Part.FDecoded);
  1002.         Encode(etBase64);
  1003.         FAttachList.Delete(FAttachList.IndexOf(Part));
  1004.         FAttachList.Add(Self);
  1005.         Part.Free;
  1006.       end;
  1007.     end;
  1008.   end;
  1009. begin
  1010.   if (not FNeedNormalize) and (Kind = nrFirst) then
  1011.     Exit;
  1012.   FindParts;
  1013.   FNeedRebuild := True;
  1014.   FNeedNormalize := False;
  1015.   FNameCount := 0;
  1016.   nTexts := 0;
  1017.   nAttachs := 0;
  1018.   nEmbedded := 0;
  1019.   // What content has this mail?
  1020.   case Kind of
  1021.     nrAddText: Inc(nTexts);
  1022.     nrAddAttach: Inc(nAttachs);
  1023.     nrAddEmbedded: Inc(nEmbedded);
  1024.   end;
  1025.   if FTextPlainPart <> nil then
  1026.     Inc(nTexts);
  1027.   if FTextHTMLPart <> nil then
  1028.     Inc(nTexts);
  1029.   for nLoop := 0 to FAttachList.Count-1 do
  1030.     if FAttachList[nLoop].FEmbedded then
  1031.       Inc(nEmbedded)
  1032.     else
  1033.       Inc(nAttachs);
  1034.   // Save current main body
  1035.   if (FBody.Size > 0) then
  1036.   begin
  1037.     SaveBody := TMailPart.Create(Self);
  1038.     SaveBody.FBody.LoadFromStream(FBody);
  1039.     SaveBody.FOwnerMessage := Self;
  1040.     // Copy content fields from main header
  1041.     nOcor := 0;
  1042.     repeat
  1043.     begin
  1044.       nLoop := SearchStringList(FHeader, _CONT, nOcor);
  1045.       Inc(nOcor);
  1046.       if nLoop >= 0 then
  1047.         SaveBody.FHeader.Add(FHeader[nLoop]);
  1048.     end
  1049.     until nLoop < 0;
  1050.     // Classify main body
  1051.     if Self = FTextPlainPart then
  1052.       FTextPlainPart := SaveBody
  1053.     else
  1054.       if Self = FTextHTMLPart then
  1055.         FTextHTMLPart := SaveBody
  1056.       else
  1057.         if Self = FMixedPart then
  1058.           FMixedPart := SaveBody
  1059.         else
  1060.           if Self = FRelatedPart then
  1061.             FRelatedPart := SaveBody
  1062.           else
  1063.             if Self = FAlternativePart then
  1064.               FAlternativePart := SaveBody
  1065.             else
  1066.               if (FSubPartList.Count = 0) then
  1067.                 FAttachList.Add(SaveBody)
  1068.               else
  1069.                 SaveBody.Free;
  1070.   end;
  1071.   // If entire mail is an attach, remove from list.
  1072.   if FAttachList.IndexOf(Self) >= 0 then
  1073.     FAttachList.Delete(FAttachList.IndexOf(Self));
  1074.   // Create new multiparts
  1075.   SetLabelValue(_C_T, '');
  1076.   SetLabelValue(_C_TE, '');
  1077.   SetLabelValue(_C_D, '');
  1078.   SetLabelValue(_C_ID, '');
  1079.   SetLabelValue(_C_LC, '');
  1080.   SetLabelValue(_C_L, '');
  1081.   SetLabelValue(_M_V, '1.0');
  1082.   SetLabelValue(_X_M, _XMailer);
  1083.   SetLabelValue(_XM2A, '');
  1084.   TmpMixed := nil;
  1085.   TmpRelated := nil;
  1086.   TmpAlternative := nil;
  1087.   FTextFather := nil;
  1088.   // There are more than one attachment?
  1089.   if nAttachs > 1 then
  1090.   begin
  1091.     CreateMixed(nil);
  1092.     FTextFather := TmpMixed;
  1093.   end;
  1094.   // There are texts plus attachments?
  1095.   if (nAttachs > 0) and (nTexts > 0) then
  1096.   begin
  1097.     CreateMixed(nil);
  1098.     FTextFather := TmpMixed;
  1099.   end;
  1100.   // There are attachments and embedded attachments?
  1101.   if (nAttachs > 0) and (nEmbedded > 0) then
  1102.   begin
  1103.     CreateMixed(nil);
  1104.     FTextFather := TmpMixed;
  1105.   end;
  1106.   // There are embedded attachments?
  1107.   if nEmbedded > 0 then
  1108.   begin
  1109.     CreateRelated(TmpMixed);
  1110.     FTextFather := TmpRelated;
  1111.   end;
  1112.   // There are more than one text?
  1113.   if nTexts > 1 then
  1114.   begin
  1115.     CreateAlternative(FTextFather);
  1116.     FTextFather := TmpAlternative;
  1117.   end;
  1118.   // Normalize text parts
  1119.   if FTextPlainPart <> nil then
  1120.     CreateTextPlain(FTextFather);
  1121.   if FTextHTMLPart <> nil then
  1122.     CreateTextHTML(FTextFather);
  1123.   // Normalize attachments
  1124.   for nLoop := 0 to FAttachList.Count-1 do
  1125.   begin
  1126.     TmpPart := FAttachList[nLoop];
  1127.     CreateAttachment(TmpPart, TmpMixed);
  1128.   end;
  1129.   // Remove old multiparts
  1130.   if (FAlternativePart <> nil) and (FAlternativePart <> Self) then
  1131.   begin
  1132.     FAlternativePart.Remove;
  1133.     FAlternativePart.Free;
  1134.   end;
  1135.   if (FRelatedPart <> nil) and (FRelatedPart <> Self) then
  1136.   begin
  1137.     FRelatedPart.Remove;
  1138.     FRelatedPart.Free;
  1139.   end;
  1140.   if (FMixedPart <> nil) and (FMixedPart <> Self) then
  1141.   begin
  1142.     FMixedPart.Remove;
  1143.     FMixedPart.Free;
  1144.   end;
  1145.   FMixedPart := TmpMixed;
  1146.   FRelatedPart := TmpRelated;
  1147.   FAlternativePart := TmpAlternative;
  1148. end;
  1149. // Insert a text on message
  1150. procedure TMailMessage2000.PutText(Text: String; var Part: TMailPart; Content: String);
  1151. begin
  1152.   if Part = nil then
  1153.     Normalize(nrAddText)
  1154.   else
  1155.     Normalize(nrFirst);
  1156.   Text := AdjustLineBreaks(Text);
  1157.   if Part = nil then
  1158.   begin
  1159.     if FTextFather <> nil then
  1160.     begin
  1161.       Part := TMailPart.Create(Self);
  1162.       Part.FOwnerPart := FTextFather;
  1163.       Part.FOwnerMessage := Self.FOwnerMessage;
  1164.       Part.FParentBoundary := FTextFather.GetBoundary;
  1165.       // Keep texts on beginning of this section
  1166.       if LowerCase(Content) = _T_P then
  1167.       begin
  1168.         FTextFather.FSubPartList.Insert(0, Part);
  1169.       end
  1170.       else
  1171.       begin
  1172.         if LowerCase(Content) = _T_H then
  1173.         begin
  1174.           if FTextFather.FSubPartList.Items[0].GetAttachInfo = _T_P then
  1175.           begin
  1176.             FTextFather.FSubPartList.Insert(1, Part);
  1177.           end
  1178.           else
  1179.           begin
  1180.             FTextFather.FSubPartList.Insert(0, Part);
  1181.           end;
  1182.         end
  1183.         else
  1184.         begin
  1185.           FTextFather.FSubPartList.Add(Part);
  1186.         end;
  1187.       end;
  1188.     end
  1189.     else
  1190.     begin
  1191.       Part := Self;
  1192.     end;
  1193.   end;
  1194.   Part.Decoded.Clear;
  1195.   Part.Decoded.Write(Text[1], Length(Text));
  1196.   Part.Encode(FTextEncoding);
  1197.   Part.SetLabelValue(_C_T, Content);
  1198.   Part.SetLabelParamValue(_C_T, _CSET, '"'+FCharset+'"');
  1199.   Part.SetLabelValue(_C_D, _INLN);
  1200.   Part.SetLabelValue(_C_L, IntToStr(Part.FBody.Size));
  1201.   FNeedRebuild := True;
  1202. end;
  1203. // Remove a text from message
  1204. procedure TMailMessage2000.RemoveText(var Part: TMailPart);
  1205. begin
  1206.   Normalize(nrFirst);
  1207.   if Part <> nil then
  1208.   begin
  1209.     if Part <> Self then
  1210.     begin
  1211.       Part.Remove;
  1212.       Part.Free;
  1213.     end
  1214.     else
  1215.     begin
  1216.       FBody.Clear;
  1217.       FDecoded.Clear;
  1218.       SetLabelValue(_C_T, '');
  1219.       SetLabelValue(_C_TE, '');
  1220.       SetLabelValue(_C_D, '');
  1221.       SetLabelValue(_C_L, '');
  1222.       SetLabelValue(_XM2A, '');
  1223.     end;
  1224.   end;
  1225.   Part := nil;
  1226.   Normalize(nrForce);
  1227.   FNeedRebuild := True;
  1228. end;
  1229. // Replace or create a mailpart for text/plain
  1230. procedure TMailMessage2000.SetTextPlain(const Text: String);
  1231. begin
  1232.   PutText(Text, FTextPlainPart, _T_P);
  1233.   FTextPlain.Text := Text;
  1234. end;
  1235. // Replace or create a mailpart for text/html
  1236. procedure TMailMessage2000.SetTextHTML(const Text: String);
  1237. begin
  1238.   PutText(Text, FTextHTMLPart, _T_H);
  1239.   FTextHTML.Text := Text;
  1240. end;
  1241. // Remove text/plain mailpart
  1242. procedure TMailMessage2000.RemoveTextPlain;
  1243. begin
  1244.   if FTextPlainPart <> nil then
  1245.   begin
  1246.     RemoveText(FTextPlainPart);
  1247.     FTextPlain.Clear;
  1248.   end;
  1249. end;
  1250. // Remove text/html mailpart
  1251. procedure TMailMessage2000.RemoveTextHTML;
  1252. begin
  1253.   if FTextHTMLPart <> nil then
  1254.   begin
  1255.     RemoveText(FTextHTMLPart);
  1256.     FTextHTML.Clear;
  1257.   end;
  1258. end;
  1259. // Create a mailpart and encode the file
  1260. procedure TMailMessage2000.AttachFile(const FileName: String; const ContentType: String = ''; const IsEmbedded: Boolean = False);
  1261. var
  1262.   MemFile: TMemoryStream;
  1263. begin
  1264.   MemFile := TMemoryStream.Create;
  1265.   MemFile.LoadFromFile(FileName);
  1266.   AttachStream(MemFile, FileName, ContentType, IsEmbedded);
  1267.   MemFile.Free;
  1268. end;
  1269. // Create a mailpart and encode the string
  1270. procedure TMailMessage2000.AttachString(const Text, FileName: String; const ContentType: String = ''; const IsEmbedded: Boolean = False);
  1271. var
  1272.   MemFile: TMemoryStream;
  1273. begin
  1274.   MemFile := TMemoryStream.Create;
  1275.   MemFile.WriteBuffer(Text[1], Length(Text));
  1276.   AttachStream(MemFile, FileName, ContentType, IsEmbedded);
  1277.   MemFile.Free;
  1278. end;
  1279. // Create a mailpart and encode the stream
  1280. procedure TMailMessage2000.AttachStream(const AStream: TStream; const FileName: String; const ContentType: String = ''; const IsEmbedded: Boolean = False);
  1281. var
  1282.   Part, Father: TMailPart;
  1283. begin
  1284.   if IsEmbedded then
  1285.   begin
  1286.     Normalize(nrAddEmbedded);
  1287.     Father := FRelatedPart;
  1288.   end
  1289.   else
  1290.   begin
  1291.     Normalize(nrAddAttach);
  1292.     Father := FMixedPart;
  1293.   end;
  1294.   if Father <> nil then
  1295.   begin
  1296.     Part := TMailPart.Create(Self);
  1297.     Part.FOwnerMessage := Self;
  1298.     Part.FOwnerPart := Father;
  1299.     Part.FParentBoundary := Father.GetBoundary;
  1300.     Father.FSubPartList.Add(Part);
  1301.   end
  1302.   else
  1303.   begin
  1304.     Part := Self;
  1305.   end;
  1306.   AStream.Position := 0;
  1307.   Part.Decoded.LoadFromStream(AStream);
  1308.   Part.Decoded.Position := 0;
  1309.   Part.Encode(FAttachEncoding);
  1310.   if ContentType = '' then
  1311.     Part.SetLabelValue(_C_T, GetMimeType(ExtractFileName(FileName)))
  1312.   else
  1313.     Part.SetLabelValue(_C_T, ContentType);
  1314.   Part.SetLabelValue(_XM2A, '"'+EncodeLine7Bit(ExtractFileName(FileName), FCharSet)+'"');
  1315.   Part.SetLabelValue(_C_L, IntToStr(Part.FBody.Size));
  1316.   Part.FEmbedded := IsEmbedded;
  1317.   if IsEmbedded then
  1318.   begin
  1319.     Part.SetLabelValue(_C_D, _INLN);
  1320.     Part.SetLabelParamValue(_XM2A, _EMBD, 'yes');
  1321.     case FEmbedMethod of
  1322.       emContentID:
  1323.         Part.SetLabelValue(_C_ID, '<'+ ExtractFileName(FileName) +'>');
  1324.       emContentLocation:
  1325.         Part.SetLabelValue(_C_LC, FContentLocationBase + ExtractFileName(FileName));
  1326.     end;
  1327.   end
  1328.   else
  1329.   begin
  1330.     Part.SetLabelValue(_C_D, _ATCH);
  1331.     Part.SetLabelParamValue(_C_T, _NAME, '"'+EncodeLine7Bit(ExtractFileName(FileName), FCharSet)+'"');
  1332.     Part.SetLabelParamValue(_C_D, _FLNM, '"'+EncodeLine7Bit(ExtractFileName(FileName), FCharSet)+'"');
  1333.     Part.SetLabelParamValue(_XM2A, _EMBD, 'no');
  1334.   end;
  1335.   FAttachList.Add(Part);
  1336.   FNeedRebuild := True;
  1337. end;
  1338. // Remove attached file from message
  1339. procedure TMailMessage2000.DetachFile(const FileName: String);
  1340. var
  1341.   nLoop: Integer;
  1342. begin
  1343.   Normalize(nrFirst);
  1344.   for nLoop := 0 to FAttachList.Count-1 do
  1345.   begin
  1346.     if LowerCase(FAttachList[nLoop].FileName) = LowerCase(ExtractFileName(FileName)) then
  1347.     begin
  1348.       if FAttachList[nLoop] <> Self then
  1349.       begin
  1350.         FAttachList[nLoop].Remove;
  1351.         FAttachList[nLoop].Free;
  1352.       end
  1353.       else
  1354.       begin
  1355.         SetLabelValue(_C_T, '');
  1356.         SetLabelValue(_C_TE, '');
  1357.         SetLabelValue(_C_D, '');
  1358.         SetLabelValue(_C_L, '');
  1359.         SetLabelValue(_C_ID, '');
  1360.         SetLabelValue(_C_LC, '');
  1361.         SetLabelValue(_XM2A, '');
  1362.         FBody.Clear;
  1363.         FDecoded.Clear;
  1364.       end;
  1365.       FAttachList.Delete(nLoop);
  1366.       FNeedRebuild := True;
  1367.       Break;
  1368.     end;
  1369.   end;
  1370.   if not FNeedRebuild then
  1371.     raise Exception.CreateFmt(_E_ATFN, [Self.Name, FileName])
  1372.   else
  1373.     Normalize(nrForce);
  1374. end;
  1375. // Remove attached file from message by AttachList index
  1376. procedure TMailMessage2000.DetachFileIndex(const Index: Integer);
  1377. begin
  1378.   Normalize(nrFirst);
  1379.   if (Index < FAttachList.Count) and (Index >= 0) then
  1380.   begin
  1381.     if FAttachList[Index] <> Self then
  1382.     begin
  1383.       FAttachList[Index].Remove;
  1384.       FAttachList[Index].Free;
  1385.     end
  1386.     else
  1387.     begin
  1388.       SetLabelValue(_C_T, '');
  1389.       SetLabelValue(_C_TE, '');
  1390.       SetLabelValue(_C_D, '');
  1391.       SetLabelValue(_C_L, '');
  1392.       SetLabelValue(_C_ID, '');
  1393.       SetLabelValue(_C_LC, '');
  1394.       SetLabelValue(_XM2A, '');
  1395.       FBody.Clear;
  1396.       FDecoded.Clear;
  1397.     end;
  1398.     FAttachList.Delete(Index);
  1399.     FNeedRebuild := True;
  1400.     Normalize(nrForce);
  1401.   end
  1402.   else
  1403.     raise Exception.CreateFmt(_E_ATIN, [Self.Name]);
  1404. end;
  1405. // Find the part containing the specified attachment
  1406. function TMailMessage2000.GetAttach(const FileName: String): TMailPart;
  1407. var
  1408.   nLoop: Integer;
  1409. begin
  1410.   Normalize(nrFirst);
  1411.   Result := nil;
  1412.   for nLoop := 0 to FAttachList.Count-1 do
  1413.   begin
  1414.     if LowerCase(FAttachList[nLoop].FileName) = LowerCase(FileName) then
  1415.     begin
  1416.       Result := FAttachList[nLoop];
  1417.       Break;
  1418.     end;
  1419.   end;
  1420. end;
  1421. // Rebuild body text according to the mailparts
  1422. procedure TMailMessage2000.RebuildBody;
  1423. var
  1424.   sLine: String;
  1425.   procedure RebuildBodyRec(MP: TMailPart);
  1426.   var
  1427.     Loop: Integer;
  1428.     Line: Integer;
  1429.     Data: String;
  1430.     nPos: Integer;
  1431.   begin
  1432.     for Loop := 0 to MP.SubPartList.Count-1 do
  1433.     begin
  1434.       sLine := #13#10;
  1435.       FBody.Write(sLine[1], Length(sLine));
  1436.       sLine :=  '--'+MP.SubPartList[Loop].FParentBoundary+#13#10;
  1437.       FBody.Write(sLine[1], Length(sLine));
  1438.       for Line := 0 to MP.SubPartList[Loop].FHeader.Count-1 do
  1439.       begin
  1440.         if Length(MP.SubPartList[Loop].FHeader[Line]) > 0 then
  1441.         begin
  1442.           sLine := MP.SubPartList[Loop].FHeader[Line]+#13#10;
  1443.           FBody.Write(sLine[1], Length(sLine));
  1444.         end;
  1445.       end;
  1446.       sLine := #13#10;
  1447.       FBody.Write(sLine[1], Length(sLine));
  1448.       if MP.SubPartList[Loop].SubPartList.Count > 0 then
  1449.       begin
  1450.         RebuildBodyRec(MP.SubPartList[Loop]);
  1451.       end
  1452.       else
  1453.       begin
  1454.         SetLength(Data, MP.SubPartList[Loop].FBody.Size);
  1455.         if MP.SubPartList[Loop].FBody.Size > 0 then
  1456.         begin
  1457.           MP.SubPartList[Loop].FBody.Position := 0;
  1458.           MP.SubPartList[Loop].FBody.ReadBuffer(Data[1], MP.SubPartList[Loop].FBody.Size);
  1459.           nPos := 1;
  1460.           while nPos >= 0 do
  1461.           begin
  1462.             DataLine(Data, sLine, nPos);
  1463.             sLine := sLine;
  1464.             FBody.Write(sLine[1], Length(sLine));
  1465.           end;
  1466.         end;
  1467.       end;
  1468.     end;
  1469.     if MP.SubPartList.Count > 0 then
  1470.     begin
  1471.       sLine := #13#10;
  1472.       FBody.Write(sLine[1], Length(sLine));
  1473.       sLine := '--'+MP.SubPartList[0].FParentBoundary+'--'#13#10;
  1474.       FBody.Write(sLine[1], Length(sLine));
  1475.     end;
  1476.   end;
  1477. begin
  1478.   if not FNeedRebuild then
  1479.     Exit;
  1480.   if SubPartList.Count > 0 then
  1481.   begin
  1482.     FBody.Clear;
  1483.     sLine := _MIME_Msg;
  1484.     FBody.Write(sLine[1], Length(sLine));
  1485.     RebuildBodyRec(Self);
  1486.   end;
  1487.   SetLabelValue(_C_L, IntToStr(FBody.Size));
  1488.   FNeedRebuild := False;
  1489. end;
  1490. // Empty data stored in the object
  1491. procedure TMailMessage2000.Reset;
  1492. var
  1493.   Loop: Integer;
  1494. begin
  1495.   for Loop := 0 to FSubPartList.Count-1 do
  1496.     FSubPartList.Items[Loop].Destroy;
  1497.   FHeader.Clear;
  1498.   FBody.Clear;
  1499.   FDecoded.Clear;
  1500.   FSubPartList.Clear;
  1501.   FAttachList.Clear;
  1502.   FTextPlain.Clear;
  1503.   FTextHTML.Clear;
  1504.   FTextPlainPart := nil;
  1505.   FTextHTMLPart := nil;
  1506.   FMixedPart := nil;
  1507.   FRelatedPart := nil;
  1508.   FAlternativePart := nil;
  1509.   FNeedRebuild := False;
  1510.   FNeedNormalize := False;
  1511.   FNeedFindParts := False;
  1512.   FNameCount := 0;
  1513. end;
  1514. { TSocketTalk =================================================================== }
  1515. // Initialize TSocketTalk
  1516. constructor TSocketTalk.Create(AOwner: TComponent);
  1517. begin
  1518.   inherited Create(AOwner);
  1519.   FClientSocket := TClientSocket.Create(Self);
  1520.   FClientSocket.ClientType := ctNonBlocking;
  1521.   FClientSocket.OnRead := SocketRead;
  1522.   FClientSocket.OnDisconnect := SocketDisconnect;
  1523.   FClientSocket.Socket.OnErrorEvent := SocketError;
  1524.   FTimer := TTimer.Create(Self);
  1525.   FTimer.Enabled := False;
  1526.   FTimer.OnTimer := Timer;
  1527.   FTimeOut := 60;
  1528.   FLastResponse := '';
  1529.   FExpectedEnd := '';
  1530.   FDataSize := 0;
  1531.   FPacketSize := 0;
  1532.   FTalkError := teNoError;
  1533. end;
  1534. // Finalize TSocketTalk
  1535. destructor TSocketTalk.Destroy;
  1536. begin
  1537.   FClientSocket.Free;
  1538.   FTimer.Free;
  1539.   inherited Destroy;
  1540. end;
  1541. // Occurs when data is comming from the socket
  1542. procedure TSocketTalk.SocketRead(Sender: TObject; Socket: TCustomWinSocket);
  1543. var
  1544.   Buffer: String;
  1545.   BufLen: Integer;
  1546. begin
  1547.   SetLength(Buffer, Socket.ReceiveLength);
  1548.   BufLen := Socket.ReceiveBuf(Buffer[1], Length(Buffer));
  1549.   FLastResponse := FLastResponse + Copy(Buffer, 1, BufLen);
  1550.   FTalkError := teNoError;
  1551.   FTimer.Enabled := False;
  1552.   if Assigned(FOnReceiveData) then
  1553.   begin
  1554.     FOnReceiveData(Self, FSessionState, Buffer, FServerResult);
  1555.   end;
  1556.   if (FDataSize > 0) and Assigned(FOnProgress) then
  1557.   begin
  1558.     FOnProgress(Self.Owner, FDataSize, Length(FLastResponse));
  1559.   end;
  1560.   if (FExpectedEnd = '') or (Copy(FLastResponse, Length(FLastResponse)-Length(FExpectedEnd)+1, Length(FExpectedEnd)) = FExpectedEnd) then
  1561.   begin
  1562.     FTalkError := teNoError;
  1563.     FDataSize := 0;
  1564.     FExpectedEnd := '';
  1565.     FWaitingServer := False;
  1566.     if Assigned(FOnEndOfData) then
  1567.     begin
  1568.       FOnEndOfData(Self, FSessionState, FLastResponse, FServerResult);
  1569.     end;
  1570.     FSessionState := stNone;
  1571.   end
  1572.   else
  1573.   begin
  1574.     FTimer.Enabled := True;
  1575.   end;
  1576. end;
  1577. // Occurs when socket is disconnected
  1578. procedure TSocketTalk.SocketDisconnect(Sender: TObject; Socket: TCustomWinSocket);
  1579. begin
  1580.   if Assigned(FOnDisconnect) then
  1581.     FOnDisconnect(Self);
  1582.   FTimer.Enabled := False;
  1583.   FWaitingServer := False;
  1584.   FSessionState := stNone;
  1585.   FExpectedEnd := '';
  1586.   FDataSize := 0;
  1587.   FPacketSize := 0;
  1588. end;
  1589. // Occurs on socket error
  1590. procedure TSocketTalk.SocketError(Sender: TObject; Socket: TCustomWinSocket; ErrorEvent: TErrorEvent; var ErrorCode: Integer);
  1591. begin
  1592.   FTimer.Enabled := False;
  1593.   FTalkError := TTalkError(Ord(ErrorEvent));
  1594.   FDataSize := 0;
  1595.   FExpectedEnd := '';
  1596.   FWaitingServer := False;
  1597.   FServerResult := False;
  1598.   if Assigned(FOnSocketTalkError) then
  1599.   begin
  1600.     FOnSocketTalkError(Self, FSessionState, FTalkError);
  1601.   end;
  1602.   FSessionState := stNone;
  1603.   ErrorCode := 0;
  1604. end;
  1605. // Occurs on timeout
  1606. procedure TSocketTalk.Timer(Sender: TObject);
  1607. begin
  1608.   FTimer.Enabled := False;
  1609.   FTalkError := teTimeout;
  1610.   FDataSize := 0;
  1611.   FExpectedEnd := '';
  1612.   FWaitingServer := False;
  1613.   FServerResult := False;
  1614.   if Assigned(FOnSocketTalkError) then
  1615.   begin
  1616.     FOnSocketTalkError(Self, FSessionState, FTalkError);
  1617.   end;
  1618.   FSessionState := stNone;
  1619. end;
  1620. // Cancel the waiting for server response
  1621. procedure TSocketTalk.Cancel;
  1622. begin
  1623.   FTimer.Enabled := False;
  1624.   FTalkError := teNoError;
  1625.   FSessionState := stNone;
  1626.   FExpectedEnd := '';
  1627.   FDataSize := 0;
  1628.   FWaitingServer := False;
  1629.   FServerResult := False;
  1630. end;
  1631. // Inform that the data comming belongs
  1632. procedure TSocketTalk.ForceState(SessionState: TSessionState);
  1633. begin
  1634.   FExpectedEnd := '';
  1635.   FLastResponse := '';
  1636.   FTimer.Interval := FTimeOut * 1000;
  1637.   FTimer.Enabled := True;
  1638.   FDataSize := 0;
  1639.   FTalkError := teNoError;
  1640.   FSessionState := SessionState;
  1641.   FWaitingServer := True;
  1642.   FServerResult := False;
  1643. end;
  1644. // Send a command to server
  1645. procedure TSocketTalk.Talk(Buffer, EndStr: String; SessionState: TSessionState);
  1646. var
  1647.   nPos: Integer;
  1648.   nLen: Integer;
  1649. begin
  1650.   FExpectedEnd := EndStr;
  1651.   FSessionState := SessionState;
  1652.   FLastResponse := '';
  1653.   FTimer.Interval := FTimeOut * 1000;
  1654.   FTalkError := teNoError;
  1655.   FWaitingServer := True;
  1656.   FServerResult := False;
  1657.   nPos := 1;
  1658.   if (FPacketSize > 0) and (Length(Buffer) > FPacketSize) then
  1659.   begin
  1660.     if Assigned(OnProgress) then
  1661.       OnProgress(Self.Owner, Length(Buffer), 0);
  1662.     while nPos <= Length(Buffer) do
  1663.     begin
  1664.       Application.ProcessMessages;
  1665.       if (nPos+FPacketSize-1) > Length(Buffer) then
  1666.         nLen := Length(Buffer)-nPos+1
  1667.       else
  1668.         nLen := FPacketSize;
  1669.       FTimer.Enabled := True;
  1670.       while (FClientSocket.Socket.SendBuf(Buffer[nPos], nLen) = -1) do
  1671.         Sleep(10);
  1672.       FTimer.Enabled := False;
  1673.       nPos := nPos + nLen;
  1674.       if Assigned(OnProgress) then
  1675.         OnProgress(Self.Owner, Length(Buffer), nPos-1);
  1676.     end;
  1677.     if Assigned(OnProgress) then
  1678.       OnProgress(Self.Owner, Length(Buffer), Length(Buffer));
  1679.   end
  1680.   else
  1681.   begin
  1682.     while (FClientSocket.Socket.SendBuf(Buffer[1], Length(Buffer)) = -1 )
  1683.        do Sleep (10);
  1684.   end;
  1685.   FPacketSize := 0;
  1686. end;
  1687. // Wait for server response
  1688. // by Rene de Jong (rmdejong@ism.nl)
  1689. procedure TSocketTalk.WaitServer;
  1690. begin
  1691.   FTimer.Interval := FTimeOut * 1000;
  1692.   while FWaitingServer and (not FServerResult) do
  1693.   begin
  1694.     FTimer.Enabled := True;
  1695.     Application.ProcessMessages;
  1696.   end;
  1697.   FTimer.Enabled := False;
  1698. end;
  1699. { TPOP2000 ====================================================================== }
  1700. // Initialize TPOP2000
  1701. constructor TPOP2000.Create;
  1702. begin
  1703.   FSocketTalk := TSocketTalk.Create(Self);
  1704.   FSocketTalk.OnEndOfData := EndOfData;
  1705.   FSocketTalk.OnSocketTalkError := SocketTalkError;
  1706.   FSocketTalk.OnReceiveData := ReceiveData;
  1707.   FSocketTalk.OnDisconnect := SocketDisconnect;
  1708.   FHost := '';
  1709.   FPort := 110;
  1710.   FUserName := '';
  1711.   FPassword := '';
  1712.   FSessionMessageCount := -1;
  1713.   FSessionConnected := False;
  1714.   FSessionLogged := False;
  1715.   FMailMessage := nil;
  1716.   FDeleteOnRetrieve := False;
  1717.   SetLength(FSessionMessageSize, 0);
  1718.   inherited Create(AOwner);
  1719. end;
  1720. // Finalize TPOP2000
  1721. destructor TPOP2000.Destroy;
  1722. begin
  1723.   FSocketTalk.Free;
  1724.   SetLength(FSessionMessageSize, 0);
  1725.   inherited Destroy;
  1726. end;
  1727. // Set timeout
  1728. procedure TPOP2000.SetTimeOut(Value: Integer);
  1729. begin
  1730.   FSocketTalk.TimeOut := Value;
  1731. end;
  1732. // Get timeout
  1733. function TPOP2000.GetTimeOut: Integer;
  1734. begin
  1735.   Result := FSocketTalk.TimeOut;
  1736. end;
  1737. // Set OnProgress event
  1738. procedure TPOP2000.SetProgress(Value: TProgressEvent);
  1739. begin
  1740.   FSocketTalk.OnProgress := Value;
  1741. end;
  1742. // Get OnProgress event
  1743. function TPOP2000.GetProgress: TProgressEvent;
  1744. begin
  1745.   Result := FSocketTalk.OnProgress;
  1746. end;
  1747. // Get LastResponse
  1748. function TPOP2000.GetLastResponse: String;
  1749. begin
  1750.   Result := FSocketTalk.LastResponse;
  1751. end;
  1752. // When data from server ends
  1753. procedure TPOP2000.EndOfData(Sender: TObject; SessionState: TSessionState; Data: String; var ServerResult: Boolean);
  1754. begin
  1755.   case SessionState of
  1756.     stConnect, stUser, stPass, stStat, stList, stRetr, stQuit, stDele, stUIDL:
  1757.     if Copy(Data, 1, 3) = '+OK' then
  1758.       ServerResult := True;
  1759.   end;
  1760. end;
  1761. // On socket error
  1762. procedure TPOP2000.SocketTalkError(Sender: TObject; SessionState: TSessionState; TalkError: TTalkError);
  1763. begin
  1764.   FSocketTalk.Cancel;
  1765. end;
  1766. // On data received
  1767. procedure TPOP2000.ReceiveData(Sender: TObject; SessionState: TSessionState; Data: String; var ServerResult: Boolean);
  1768. begin
  1769.   if (Copy(Data, 1, 4) = '-ERR') and (Copy(Data, Length(Data)-1, 2) = #13#10) then
  1770.   begin
  1771.     ServerResult := False;
  1772.     FSocketTalk.Cancel;
  1773.   end;
  1774. end;
  1775. // On socket disconnected
  1776. procedure TPOP2000.SocketDisconnect(Sender: TObject);
  1777. begin
  1778.   FSessionMessageCount := -1;
  1779.   FSessionConnected := False;
  1780.   FSessionLogged := False;
  1781.   SetLength(FSessionMessageSize, 0);
  1782. end;
  1783. // Connect socket
  1784. function TPOP2000.Connect: Boolean;
  1785. begin
  1786.   if FSessionConnected or FSocketTalk.ClientSocket.Active then
  1787.   begin
  1788.     Result := False;
  1789.     Exit;
  1790.   end;
  1791.   if Length(FHost) = 0 then
  1792.   begin
  1793.     Result := False;
  1794.     Exit;
  1795.   end;
  1796.   if not IsIPAddress(FHost) then
  1797.   begin
  1798.     FSocketTalk.ClientSocket.Host := FHost;
  1799.     FSocketTalk.ClientSocket.Address := '';
  1800.   end
  1801.   else
  1802.   begin
  1803.     FSocketTalk.ClientSocket.Host := '';
  1804.     FSocketTalk.ClientSocket.Address := FHost;
  1805.   end;
  1806.   FSocketTalk.ClientSocket.Port := FPort;
  1807.   FSocketTalk.ForceState(stConnect);
  1808.   FSocketTalk.ClientSocket.Open;
  1809.   FSocketTalk.WaitServer;
  1810.   FSessionConnected := FSocketTalk.ServerResult;
  1811.   Result := FSocketTalk.ServerResult;
  1812. end;
  1813. // POP3 Logon
  1814. function TPOP2000.Login: Boolean;
  1815. var
  1816.   MsgList: TStringList;
  1817.   Loop: Integer;
  1818.   cStat: String;
  1819. begin
  1820.   Result := False;
  1821.   if (not FSessionConnected) or (not FSocketTalk.ClientSocket.Active) then
  1822.   begin
  1823.     Exit;
  1824.   end;
  1825.   FSocketTalk.Talk('USER'#32+FUserName+#13#10, #13#10, stUser);
  1826.   FSocketTalk.WaitServer;
  1827.   if FSocketTalk.ServerResult then
  1828.   begin
  1829.     FSocketTalk.Talk('PASS'#32+FPassword+#13#10, #13#10, stPass);
  1830.     FSocketTalk.WaitServer;
  1831.     if FSocketTalk.ServerResult then
  1832.     begin
  1833.       FSessionLogged := True;
  1834.       FSocketTalk.Talk('LIST'#13#10, _DATAEND1, stList);
  1835.       FSocketTalk.WaitServer;
  1836.       if FSocketTalk.ServerResult then
  1837.       begin
  1838.         MsgList := TStringList.Create;
  1839.         MsgList.Text := FSocketTalk.LastResponse;
  1840.         if MsgList.Count > 2 then
  1841.         begin
  1842.           cStat := TrimSpace(MsgList[MsgList.Count-2]);
  1843.           FSessionMessageCount := StrToIntDef(Copy(cStat, 1, Pos(#32, cStat)-1), -1);
  1844.           if FSessionMessageCount > 0 then
  1845.           begin
  1846.             for Loop := 1 to MsgList.Count-2 do
  1847.             begin
  1848.               cStat := TrimSpace(MsgList[Loop]);
  1849.               cStat := Copy(cStat, 1, Pos(#32, cStat)-1);
  1850.               SetLength(FSessionMessageSize, StrToInt(cStat)+1);
  1851.               if StrToIntDef(cStat, 0) > 0 then
  1852.                 FSessionMessageSize[StrToInt(cStat)] := StrToIntDef(Copy(MsgList[Loop], Pos(#32, MsgList[Loop])+1, 99), 0);
  1853.             end;
  1854.             FSessionMessageSize[0] := 0;
  1855.           end;
  1856.         end
  1857.         else
  1858.         begin
  1859.           FSessionMessageCount := 0;
  1860.           SetLength(FSessionMessageSize, 0);
  1861.         end;
  1862.         MsgList.Free;
  1863.       end;
  1864.     end;
  1865.   end;
  1866.   Result := FSessionLogged;
  1867. end;
  1868. // POP3 Quit
  1869. function TPOP2000.Quit: Boolean;
  1870. begin
  1871.   Result := False;
  1872.   if (not FSessionConnected) or (not FSocketTalk.ClientSocket.Active) then
  1873.   begin
  1874.     Exit;
  1875.   end;
  1876.   FSocketTalk.Talk('QUIT'#13#10, #13#10, stQuit);
  1877.   FSocketTalk.WaitServer;
  1878.   if FSocketTalk.ServerResult then
  1879.   begin
  1880.     FSocketTalk.ClientSocket.Close;
  1881.     FSessionConnected := False;
  1882.     FSessionLogged := False;
  1883.     FSessionMessageCount := -1;
  1884.     Result := True;
  1885.   end;
  1886. end;
  1887. // Force disconnection
  1888. procedure TPOP2000.Abort;
  1889. begin
  1890.   FSocketTalk.ClientSocket.Close;
  1891.   FSessionConnected := False;
  1892.   FSessionLogged := False;
  1893.   FSessionMessageCount := -1;
  1894. end;
  1895. // Retrieve message#
  1896. function TPOP2000.RetrieveMessage(Number: Integer): Boolean;
  1897. var
  1898.   MailTxt: TStringList;
  1899. begin
  1900.   Result := False;
  1901.   FLastMessage := '';
  1902.   if (not FSessionConnected) or (not FSessionLogged) or (not FSocketTalk.ClientSocket.Active) then
  1903.   begin
  1904.     Exit;
  1905.   end;
  1906.   FSocketTalk.DataSize := FSessionMessageSize[Number-1];
  1907.   FSocketTalk.Talk('RETR'#32+IntToStr(Number)+#13#10, _DATAEND1, stRetr);
  1908.   FSocketTalk.WaitServer;
  1909.   if FSocketTalk.ServerResult then
  1910.   begin
  1911.     MailTxt := TStringList.Create;
  1912.     MailTxt.Text := FSocketTalk.LastResponse;
  1913.     MailTxt.Delete(MailTxt.Count-1);
  1914.     MailTxt.Delete(0);
  1915.     FLastMessage := MailTxt.Text;
  1916.     MailTxt.Free;
  1917.     if Assigned(FMailMessage) then
  1918.     begin
  1919.       FMailMessage.Reset;
  1920.       FMailMessage.Fill(PChar(FLastMessage), True);
  1921.     end;
  1922.     Result := True;
  1923.     if FDeleteOnRetrieve then
  1924.       DeleteMessage(Number);
  1925.   end;
  1926. end;
  1927. // Retrieve message# (only header)
  1928. function TPOP2000.RetrieveHeader(Number: Integer; Lines: Integer = 0): Boolean;
  1929. var
  1930.   MailTxt: TStringList;
  1931. begin
  1932.   Result := False;
  1933.   FLastMessage := '';
  1934.   if (not FSessionConnected) or (not FSessionLogged) or (not FSocketTalk.ClientSocket.Active) then
  1935.   begin
  1936.     Exit;
  1937.   end;
  1938.   FSocketTalk.DataSize := FSessionMessageSize[Number-1];
  1939.   FSocketTalk.Talk('TOP'#32+IntToStr(Number)+#32+IntToStr(Lines)+#13#10, _DATAEND1, stRetr);
  1940.   FSocketTalk.WaitServer;
  1941.   if FSocketTalk.ServerResult then
  1942.   begin
  1943.     MailTxt := TStringList.Create;
  1944.     MailTxt.Text := FSocketTalk.LastResponse;
  1945.     MailTxt.Delete(MailTxt.Count-1);
  1946.     MailTxt.Delete(0);
  1947.     FLastMessage := MailTxt.Text;
  1948.     MailTxt.Free;
  1949.     if Assigned(FMailMessage) then
  1950.     begin
  1951.       FMailMessage.Reset;
  1952.       FMailMessage.FHeader.Text := PChar(FLastMessage);
  1953.     end;
  1954.     Result := True;
  1955.   end;
  1956. end;
  1957. // Delete message#
  1958. function TPOP2000.DeleteMessage(Number: Integer): Boolean;
  1959. begin
  1960.   Result := False;
  1961.   if (not FSessionConnected) or (not FSessionLogged) or (not FSocketTalk.ClientSocket.Active) then
  1962.   begin
  1963.     Exit;
  1964.   end;
  1965.   FSocketTalk.Talk('DELE'#32+IntToStr(Number)+#13#10, #13#10, stDele);
  1966.   FSocketTalk.WaitServer;
  1967.   if FSocketTalk.ServerResult then
  1968.   begin
  1969.     Result := True;
  1970.   end;
  1971. end;
  1972. // Get UIDL from message#
  1973. function TPOP2000.GetUIDL(Number: Integer): String;
  1974. var
  1975.   MsgNum: String;
  1976. begin
  1977.   Result := '';
  1978.   MsgNum := IntToStr(Number);
  1979.   if (not FSessionConnected) or (not FSessionLogged) or (not FSocketTalk.ClientSocket.Active) then
  1980.   begin
  1981.     Exit;
  1982.   end;
  1983.   FSocketTalk.Talk('UIDL'#32+MsgNum+#13#10, #13#10, stUIDL);
  1984.   FSocketTalk.WaitServer;
  1985.   if FSocketTalk.ServerResult then
  1986.   begin
  1987.     Result := FSocketTalk.LastResponse;
  1988.     Result := Trim(Copy(Result, Pos(MsgNum+#32, Result)+Length(MsgNum)+1, Length(Result)));
  1989.   end;
  1990. end;
  1991. { TSMTP2000 ====================================================================== }
  1992. // Initialize TSMTP2000
  1993. constructor TSMTP2000.Create;
  1994. begin
  1995.   FSocketTalk := TSocketTalk.Create(Self);
  1996.   FSocketTalk.OnEndOfData := EndOfData;
  1997.   FSocketTalk.OnSocketTalkError := SocketTalkError;
  1998.   FSocketTalk.OnReceiveData := ReceiveData;
  1999.   FSocketTalk.OnDisconnect := SocketDisconnect;
  2000.   FHost := '';
  2001.   FPort := 25;
  2002.   FSessionConnected := False;
  2003.   FPacketSize := 102400;
  2004.   FUserName := '';
  2005.   FPassword := '';
  2006.   FHandshaking := hsAuto;
  2007.   inherited Create(AOwner);
  2008. end;
  2009. // Finalize TSMTP2000
  2010. destructor TSMTP2000.Destroy;
  2011. begin
  2012.   FSocketTalk.Free;
  2013.   inherited Destroy;
  2014. end;
  2015. // Set timeout
  2016. procedure TSMTP2000.SetTimeOut(Value: Integer);
  2017. begin
  2018.   FSocketTalk.TimeOut := Value;
  2019. end;
  2020. // Get timeout
  2021. function TSMTP2000.GetTimeOut: Integer;
  2022. begin
  2023.   Result := FSocketTalk.TimeOut;
  2024. end;
  2025. // Set OnProgress event
  2026. procedure TSMTP2000.SetProgress(Value: TProgressEvent);
  2027. begin
  2028.   FSocketTalk.OnProgress := Value;
  2029. end;
  2030. // Get OnProgress event
  2031. function TSMTP2000.GetProgress: TProgressEvent;
  2032. begin
  2033.   Result := FSocketTalk.OnProgress;
  2034. end;
  2035. // Get LastResponse
  2036. function TSMTP2000.GetLastResponse: String;
  2037. begin
  2038.   Result := FSocketTalk.LastResponse;
  2039. end;
  2040. // When data from server ends
  2041. procedure TSMTP2000.EndOfData(Sender: TObject; SessionState: TSessionState; Data: String; var ServerResult: Boolean);
  2042. begin
  2043.   case SessionState of
  2044.     stConnect:
  2045.     if Copy(Data, 1, 3) = '220' then
  2046.       ServerResult := True;
  2047.     stHelo, stEhlo, stMail, stRcpt, stSendData:
  2048.     if Copy(Data, 1, 3) = '250' then
  2049.       ServerResult := True;
  2050.     stData:
  2051.     if Copy(Data, 1, 3) = '354' then
  2052.       ServerResult := True;
  2053.     stQuit:
  2054.     if Copy(Data, 1, 3) = '221' then
  2055.       ServerResult := True;
  2056.     stAuthLogin, stSMTPUser:
  2057.     if Copy(Data, 1, 3) = '334' then
  2058.       ServerResult := True;
  2059.     stSMTPPass:
  2060.     if Copy(Data, 1, 3) = '235' then
  2061.       ServerResult := True;
  2062.     stNoop: ServerResult := True;
  2063.   end;
  2064. end;
  2065. // On socket error
  2066. procedure TSMTP2000.SocketTalkError(Sender: TObject; SessionState: TSessionState; TalkError: TTalkError);
  2067. begin
  2068.   FSocketTalk.Cancel;
  2069. end;
  2070. // On data received
  2071. procedure TSMTP2000.ReceiveData(Sender: TObject; SessionState: TSessionState; Data: String; var ServerResult: Boolean);
  2072. begin
  2073.   if (StrToIntDef(Copy(Data, 1, 3), 0) >= 500) and (Copy(Data, Length(Data)-1, 2) = #13#10) then
  2074.   begin
  2075.     ServerResult := False;
  2076.     FSocketTalk.Cancel;
  2077.   end;
  2078. end;
  2079. // On socket disconnected
  2080. procedure TSMTP2000.SocketDisconnect(Sender: TObject);
  2081. begin
  2082.   FSessionConnected := False;
  2083. end;
  2084. // Connect socket
  2085. function TSMTP2000.Connect: Boolean;
  2086. var
  2087.   Buffer: String;
  2088. begin
  2089.   Result := False;
  2090.   if FSessionConnected or FSocketTalk.ClientSocket.Active then
  2091.   begin
  2092.     Exit;
  2093.   end;
  2094.   if Length(FHost) = 0 then
  2095.   begin
  2096.     Exit;
  2097.   end;
  2098.   if not IsIPAddress(FHost) then
  2099.   begin
  2100.     FSocketTalk.ClientSocket.Host := FHost;
  2101.     FSocketTalk.ClientSocket.Address := '';
  2102.   end
  2103.   else
  2104.   begin
  2105.     FSocketTalk.ClientSocket.Host := '';
  2106.     FSocketTalk.ClientSocket.Address := FHost;
  2107.   end;
  2108.   FNeedAuthentication := False;
  2109.   FSocketTalk.ClientSocket.Port := FPort;
  2110.   FSocketTalk.ForceState(stConnect);
  2111.   FSocketTalk.ClientSocket.Open;
  2112.   FSocketTalk.WaitServer;
  2113.   if FSocketTalk.ServerResult then
  2114.   begin
  2115.     case FHandshaking of
  2116.       hsAuto:
  2117.       begin
  2118.         FSessionConnected := True;
  2119.         Buffer := FSocketTalk.FLastResponse;
  2120.         Result := Ehlo;
  2121.         Buffer := Buffer + FSocketTalk.FLastResponse;
  2122.         if not Result then
  2123.         begin
  2124.           Result := Helo;
  2125.           Buffer := Buffer + FSocketTalk.FLastResponse;
  2126.         end;
  2127.         if Result then
  2128.         begin
  2129.           if AuthLogin then
  2130.           begin
  2131.             Buffer := Buffer + FSocketTalk.FLastResponse;
  2132.             Result := Login;
  2133.             Buffer := Buffer + FSocketTalk.FLastResponse;
  2134.           end;
  2135.         end;
  2136.         FSocketTalk.FLastResponse := Buffer;
  2137.       end;
  2138.       hsManual:
  2139.       begin
  2140.         Result := True;
  2141.       end;
  2142.     end;
  2143.   end;
  2144.   FSessionConnected := Result;
  2145. end;
  2146. // Sends a HELO command
  2147. function TSMTP2000.Helo: Boolean;
  2148. begin
  2149.   Result := False;
  2150.   if (not FSessionConnected) or (not FSocketTalk.ClientSocket.Active) then
  2151.   begin
  2152.     Exit;
  2153.   end;
  2154.   FSocketTalk.Talk('HELO'#32+FSocketTalk.FClientSocket.Socket.LocalHost+#13#10, #13#10, stHelo);
  2155.   FSocketTalk.WaitServer;
  2156.   Result := FSocketTalk.ServerResult;
  2157. end;
  2158. // Sends a EHLO command
  2159. function TSMTP2000.Ehlo: Boolean;
  2160. begin
  2161.   Result := False;
  2162.   if (not FSessionConnected) or (not FSocketTalk.ClientSocket.Active) then
  2163.   begin
  2164.     Exit;
  2165.   end;
  2166.   FSocketTalk.Talk('EHLO'#32+FSocketTalk.FClientSocket.Socket.LocalHost+#13#10, #13#10, stEhlo);
  2167.   FSocketTalk.WaitServer;
  2168.   Result := FSocketTalk.ServerResult;
  2169. end;
  2170. // Sends a AUTH LOGIN command
  2171. function TSMTP2000.AuthLogin: Boolean;
  2172. begin
  2173.   Result := False;
  2174.   if (not FSessionConnected) or (not FSocketTalk.ClientSocket.Active) then
  2175.   begin
  2176.     Exit;
  2177.   end;
  2178.   FSocketTalk.Talk('AUTH LOGIN'#13#10, #13#10, stAuthLogin);
  2179.   FSocketTalk.WaitServer;
  2180.   FNeedAuthentication := FSocketTalk.ServerResult;
  2181.   Result := FSocketTalk.ServerResult;
  2182. end;
  2183. // Login to server
  2184. function TSMTP2000.Login: Boolean;
  2185. var
  2186.   EncUser, EncPass: String;
  2187. begin
  2188.   Result := False;
  2189.   if (not FSessionConnected) or (not FNeedAuthentication) or (not FSocketTalk.ClientSocket.Active) then
  2190.   begin
  2191.     Exit;
  2192.   end;
  2193.   EncUser := EncodeBASE64String(FUserName);
  2194.   EncPass := EncodeBASE64String(FPassword);
  2195.   FSocketTalk.Talk(EncUser+#13#10, #13#10, stSMTPUser);
  2196.   FSocketTalk.WaitServer;
  2197.   if FSocketTalk.ServerResult then
  2198.   begin
  2199.     FSocketTalk.Talk(EncPass+#13#10, #13#10, stSMTPPass);
  2200.     FSocketTalk.WaitServer;
  2201.     Result := FSocketTalk.ServerResult;
  2202.   end;
  2203. end;
  2204. // SMTP Quit
  2205. function TSMTP2000.Quit: Boolean;
  2206. begin
  2207.   Result := False;
  2208.   if (not FSessionConnected) or (not FSocketTalk.ClientSocket.Active) then
  2209.   begin
  2210.     Exit;
  2211.   end;
  2212.   FSocketTalk.Talk('QUIT'#13#10, #13#10, stQuit);
  2213.   FSocketTalk.WaitServer;
  2214.   if FSocketTalk.ServerResult then
  2215.   begin
  2216.     FSocketTalk.ClientSocket.Close;
  2217.     FSessionConnected := False;
  2218.     Result := True;
  2219.   end;
  2220. end;
  2221. // Force disconnection
  2222. procedure TSMTP2000.Abort;
  2223. begin
  2224.   FSocketTalk.ClientSocket.Close;
  2225.   FSessionConnected := False;
  2226. end;
  2227. // Send message
  2228. function TSMTP2000.SendMessage: Boolean;
  2229. var
  2230.   sDests: String;
  2231. begin
  2232.   if not Assigned(FMailMessage) then
  2233.   begin
  2234.     Exception.CreateFmt(_E_MMUN, [Self.Name]);
  2235.     Result := False;
  2236.     Exit;
  2237.   end;
  2238.   if FMailMessage.ToList.Count > 0 then
  2239.     sDests := FMailMessage.ToList.AllAddresses;
  2240.   if FMailMessage.CcList.Count > 0 then
  2241.   begin
  2242.     if sDests <> '' then sDests := sDests + ',';
  2243.     sDests := sDests + FMailMessage.CcList.AllAddresses;
  2244.   end;
  2245.   if FMailMessage.BccList.Count > 0 then
  2246.   begin
  2247.     if sDests <> '' then sDests := sDests + ',';
  2248.     sDests := sDests + FMailMessage.BccList.AllAddresses;
  2249.   end;
  2250.   Result := SendMessageTo(FMailMessage.FromAddress, sDests);
  2251. end;
  2252. // Send message to specified recipients
  2253. function TSMTP2000.SendMessageTo(const From, Dests: String): Boolean;
  2254. var
  2255.   Loop: Integer;
  2256.   AllOk: Boolean;
  2257.   sDests: TStringList;
  2258.   sHeader: String;
  2259. begin
  2260.   Result := False;
  2261.   if (not FSessionConnected) or (not FSocketTalk.ClientSocket.Active) then
  2262.   begin
  2263.     Exit;
  2264.   end;
  2265.   if not Assigned(FMailMessage) then
  2266.   begin
  2267.     Exception.CreateFmt(_E_MMUN, [Self.Name]);
  2268.     Exit;
  2269.   end;
  2270.   if FMailMessage.FNeedRebuild then
  2271.   begin
  2272.     Exception.CreateFmt(_E_MMNR, [Self.Name]);
  2273.     Exit;
  2274.   end;
  2275.   sDests := TStringList.Create;
  2276.   sDests.Sorted := True;
  2277.   sDests.Duplicates := dupIgnore;
  2278.   sDests.CommaText := Dests;
  2279.   if sDests.Count = 0 then
  2280.   begin
  2281.     Exception.CreateFmt(_E_NRTS, [Self.Name]);
  2282.     Exit;
  2283.   end;
  2284.   FSocketTalk.Talk('MAIL FROM: <'+From+'>'#13#10, #13#10, stMail);
  2285.   FSocketTalk.WaitServer;
  2286.   if FSocketTalk.ServerResult then
  2287.   begin
  2288.     AllOk := True;
  2289.     for Loop := 0 to sDests.Count-1 do
  2290.     begin
  2291.       FSocketTalk.Talk('RCPT TO: <'+sDests[Loop]+'>'#13#10, #13#10, stRcpt);
  2292.       FSocketTalk.WaitServer;
  2293.       if not FSocketTalk.ServerResult then
  2294.       begin
  2295.         AllOk := False;
  2296.         Break;
  2297.       end;
  2298.     end;
  2299.     if AllOk then
  2300.     begin
  2301.       FMailMessage.SetMessageId(FSocketTalk.ClientSocket.Socket.LocalAddress);
  2302.       sHeader := FMailMessage.FHeader.Text;
  2303.       FMailMessage.SetLabelValue('Bcc', '');
  2304.       FSocketTalk.Talk('DATA'#13#10, #13#10, stData);
  2305.       FSocketTalk.WaitServer;
  2306.       if FSocketTalk.ServerResult then
  2307.       begin
  2308.         FSocketTalk.PacketSize := FPacketSize;
  2309.         FSocketTalk.Talk(StringReplace(FMailMessage.MessageSource, _DATAEND1, _DATAEND2, [rfReplaceAll])+_DATAEND1, #13#10, stSendData);
  2310.         FSocketTalk.WaitServer;
  2311.         if FSocketTalk.ServerResult then
  2312.         begin
  2313.           Result := True;
  2314.         end;
  2315.       end;
  2316.       FMailMessage.FHeader.Text := sHeader;
  2317.     end;
  2318.   end;
  2319.   sDests.Free;
  2320. end;
  2321. // Send string to specified recipients
  2322. function TSMTP2000.SendStringTo(const Msg, From, Dests: String): Boolean;
  2323. var
  2324.   Loop: Integer;
  2325.   AllOk: Boolean;
  2326.   sDests: TStringList;
  2327. begin
  2328.   Result := False;
  2329.   if (not FSessionConnected) or (not FSocketTalk.ClientSocket.Active) then
  2330.   begin
  2331.     Exit;
  2332.   end;
  2333.   sDests := TStringList.Create;
  2334.   sDests.Sorted := True;
  2335.   sDests.Duplicates := dupIgnore;
  2336.   sDests.CommaText := Dests;
  2337.   if sDests.Count = 0 then
  2338.   begin
  2339.     Exception.CreateFmt(_E_NRTS, [Self.Name]);
  2340.     Exit;
  2341.   end;
  2342.   FSocketTalk.Talk('MAIL FROM: <'+From+'>'#13#10, #13#10, stMail);
  2343.   FSocketTalk.WaitServer;
  2344.   if FSocketTalk.ServerResult then
  2345.   begin
  2346.     AllOk := True;
  2347.     for Loop := 0 to sDests.Count-1 do
  2348.     begin
  2349.       FSocketTalk.Talk('RCPT TO: <'+sDests[Loop]+'>'#13#10, #13#10, stRcpt);
  2350.       FSocketTalk.WaitServer;
  2351.       if not FSocketTalk.ServerResult then
  2352.       begin
  2353.         AllOk := False;
  2354.         Break;
  2355.       end;
  2356.     end;
  2357.     if AllOk then
  2358.     begin
  2359.       FSocketTalk.Talk('DATA'#13#10, #13#10, stData);
  2360.       FSocketTalk.WaitServer;
  2361.       if FSocketTalk.ServerResult then
  2362.       begin
  2363.         FSocketTalk.PacketSize := FPacketSize;
  2364.         FSocketTalk.Talk(StringReplace(Msg, _DATAEND1, _DATAEND2, [rfReplaceAll])+_DATAEND1, #13#10, stSendData);
  2365.         FSocketTalk.WaitServer;
  2366.         if FSocketTalk.ServerResult then
  2367.         begin
  2368.           Result := True;
  2369.         end;
  2370.       end;
  2371.     end;
  2372.   end;
  2373.   sDests.Free;
  2374. end;
  2375. // =============================================================================
  2376. function TPOP2000.GetUIDLS(List: TStrings):Boolean;
  2377. var
  2378.   I,J:integer;
  2379.   S,temp:String;
  2380. begin
  2381.   Result :=False;
  2382.   if (not FSessionConnected) or (not FSessionLogged) or (not FSocketTalk.ClientSocket.Active) then
  2383.   begin
  2384.     Exit;
  2385.   end;
  2386.   S:=SendCMD('UIDL'#13#10,stUIDL);
  2387.   result:=FSocketTalk.ServerResult;
  2388.   
  2389.   if result then
  2390.   begin
  2391.     S:= FSocketTalk.LastResponse;
  2392.    
  2393.     I:=Pos(#13#10,S);
  2394.     delete(S,1,I);
  2395.     S:=trim(S);
  2396.     while Trim(S)<>'' do
  2397.     begin
  2398.       I:=Pos(#13#10,S);
  2399.       temp:=copy(S,1,I);
  2400.       J:=pos(#32,temp);
  2401.       if J=0 then Exit;
  2402.       List.Add(copy(temp,J+1,Length(temp)-J));
  2403.       delete(S,1,I);
  2404.       S:=trim(S);
  2405.     end;
  2406.     //Result := Trim(Copy(Result, Pos(MsgNum+#32, Result)+Length(MsgNum)+1, Length(Result)));
  2407.   end;
  2408. end;
  2409. function TPOP2000.SendCMD(CMD: string;state:TSessionState): string;
  2410. begin
  2411.   Result:='';
  2412.   if (not FSessionConnected) or (not FSessionLogged) or (not FSocketTalk.ClientSocket.Active) then
  2413.   begin
  2414.     Exit;
  2415.   end;
  2416.   FSocketTalk.Talk('UIDL'#13#10, '', state);
  2417.   FSocketTalk.WaitServer;
  2418.   if FSocketTalk.ServerResult then
  2419.     result:= FSocketTalk.LastResponse;
  2420. end;
  2421. function TPOP2000.RetrieveMessageByUIDL(UIDL: String): Boolean;
  2422. var
  2423.   MailTxt: TStringList;
  2424. begin
  2425.   Result := False;
  2426.   FLastMessage := '';
  2427.   if (not FSessionConnected) or (not FSessionLogged) or (not FSocketTalk.ClientSocket.Active) then
  2428.   begin
  2429.     Exit;
  2430.   end;
  2431.   //FSocketTalk.DataSize := FSessionMessageSize[Number-1];
  2432.   FSocketTalk.Talk('UIDL'#32+UIDL+#13#10, _DATAEND1, stRetr);
  2433.   FSocketTalk.WaitServer;
  2434.   if FSocketTalk.ServerResult then
  2435.   begin
  2436.     MailTxt := TStringList.Create;
  2437.     MailTxt.Text := FSocketTalk.LastResponse;
  2438.     MailTxt.Delete(MailTxt.Count-1);
  2439.     MailTxt.Delete(0);
  2440.     FLastMessage := MailTxt.Text;
  2441.     MailTxt.Free;
  2442.     if Assigned(FMailMessage) then
  2443.     begin
  2444.       FMailMessage.Reset;
  2445.       FMailMessage.Fill(PChar(FLastMessage), True);
  2446.     end;
  2447.     Result := True;
  2448.     //if FDeleteOnRetrieve then
  2449.     //  DeleteMessage(Number);
  2450.   end;
  2451. end;
  2452. end.