lsmtp.pp 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806
  1. { lNet SMTP unit
  2. CopyRight (C) 2005-2006 Ales Katona
  3. This library is Free software; you can rediStribute it and/or modify it
  4. under the terms of the GNU Library General Public License as published by
  5. the Free Software Foundation; either version 2 of the License, or (at your
  6. option) any later version.
  7. This program is diStributed in the hope that it will be useful, but WITHOUT
  8. ANY WARRANTY; withOut even the implied warranty of MERCHANTABILITY or
  9. FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License
  10. for more details.
  11. You should have received a Copy of the GNU Library General Public License
  12. along with This library; if not, Write to the Free Software Foundation,
  13. Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  14. This license has been modified. See File LICENSE.ADDON for more inFormation.
  15. Should you find these sources without a LICENSE File, please contact
  16. me at [email protected]
  17. }
  18. unit lsmtp;
  19. {$mode objfpc}{$H+}
  20. {$inline on}
  21. interface
  22. uses
  23. Classes, Contnrs, lNet, lEvents, lCommon;
  24. type
  25. TLSMTP = class;
  26. TLSMTPClient = class;
  27. TLSMTPStatus = (ssNone, ssCon, ssHelo, ssEhlo, ssMail,
  28. ssRcpt, ssData, ssRset, ssQuit);
  29. TLSMTPStatusSet = set of TLSMTPStatus;
  30. TLSMTPStatusRec = record
  31. Status: TLSMTPStatus;
  32. Args: array[1..2] of string;
  33. end;
  34. { TLSMTPStatusFront }
  35. {$DEFINE __front_type__ := TLSMTPStatusRec}
  36. {$i lcontainersh.inc}
  37. TLSMTPStatusFront = TLFront;
  38. TLSMTPClientStatusEvent = procedure (aSocket: TLSocket;
  39. const aStatus: TLSMTPStatus) of object;
  40. { TAttachment }
  41. TAttachment = class
  42. protected
  43. FData: TStringList;
  44. function GetAsText: string; virtual;
  45. public
  46. constructor Create;
  47. destructor Destroy; override;
  48. function LoadFromFile(const aFileName: string): Boolean;
  49. public
  50. property AsText: string read GetAsText;
  51. end;
  52. { TAttachmentList }
  53. TAttachmentList = class
  54. protected
  55. FItems: TFPObjectList;
  56. function GetCount: Integer;
  57. function GetItem(i: Integer): TAttachment;
  58. procedure SetItem(i: Integer; const AValue: TAttachment);
  59. public
  60. constructor Create;
  61. destructor Destroy; override;
  62. function Add(anAttachment: TAttachment): Integer;
  63. function AddFromFile(const aFileName: string): Integer;
  64. function Remove(anAttachment: TAttachment): Integer;
  65. procedure Delete(const i: Integer);
  66. procedure Clear;
  67. public
  68. property Count: Integer read GetCount;
  69. property Items[i: Integer]: TAttachment read GetItem write SetItem; default;
  70. end;
  71. { TMail }
  72. TMail = class
  73. protected
  74. FMailText: string;
  75. FMailStream: TStream;
  76. FRecipients: string;
  77. FSender: string;
  78. FSubject: string;
  79. FAttachments: TAttachmentList;
  80. public
  81. constructor Create;
  82. destructor Destroy; override;
  83. public
  84. property Attachments: TAttachmentList read FAttachments;
  85. property MailText: string read FMailText write FMailText;
  86. property MailStream: TStream read FMailStream write FMailStream;
  87. property Sender: string read FSender write FSender;
  88. property Recipients: string read FRecipients write FRecipients;
  89. property Subject: string read FSubject write FSubject;
  90. end;
  91. TLSMTP = class(TLComponent)
  92. protected
  93. FConnection: TLTcp;
  94. protected
  95. function GetTimeout: DWord;
  96. procedure SetTimeout(const AValue: DWord);
  97. function GetConnected: Boolean;
  98. function GetSocketClass: TLSocketClass;
  99. procedure SetSocketClass(const AValue: TLSocketClass);
  100. function GetEventer: TLEventer;
  101. procedure SetEventer(Value: TLEventer);
  102. public
  103. constructor Create(aOwner: TComponent); override;
  104. destructor Destroy; override;
  105. public
  106. property Connected: Boolean read GetConnected;
  107. property Connection: TLTcp read FConnection;
  108. property SocketClass: TLSocketClass read GetSocketClass write SetSocketClass;
  109. property Eventer: TLEventer read GetEventer write SetEventer;
  110. property Timeout: DWord read GetTimeout write SetTimeout;
  111. end;
  112. { TLSMTPClient }
  113. TLSMTPClient = class(TLSMTP, ILClient)
  114. protected
  115. FStatus: TLSMTPStatusFront;
  116. FCommandFront: TLSMTPStatusFront;
  117. FPipeLine: Boolean;
  118. FOnConnect: TLSocketEvent;
  119. FOnReceive: TLSocketEvent;
  120. FOnDisconnect: TLSocketEvent;
  121. FOnSuccess: TLSMTPClientStatusEvent;
  122. FOnFailure: TLSMTPClientStatusEvent;
  123. FOnError: TLSocketErrorEvent;
  124. FOnSent: TLSocketProgressEvent;
  125. FSL: TStringList;
  126. FStatusSet: TLSMTPStatusSet;
  127. FBuffer: string;
  128. FStream: TStream;
  129. protected
  130. procedure OnEr(const msg: string; aSocket: TLSocket);
  131. procedure OnRe(aSocket: TLSocket);
  132. procedure OnCo(aSocket: TLSocket);
  133. procedure OnDs(aSocket: TLSocket);
  134. procedure OnCs(aSocket: TLSocket);
  135. protected
  136. function CanContinue(const aStatus: TLSMTPStatus; const Arg1, Arg2: string): Boolean;
  137. function CleanInput(var s: string): Integer;
  138. procedure EvaluateAnswer(const Ans: string);
  139. procedure ExecuteFrontCommand;
  140. procedure InsertCRLFs;
  141. procedure SendData(const FromStream: Boolean = False);
  142. public
  143. constructor Create(aOwner: TComponent); override;
  144. destructor Destroy; override;
  145. function Connect(const aHost: string; const aPort: Word = 25): Boolean; virtual; overload;
  146. function Connect: Boolean; virtual; overload;
  147. function Get(var aData; const aSize: Integer; aSocket: TLSocket = nil): Integer; virtual;
  148. function GetMessage(out msg: string; aSocket: TLSocket = nil): Integer; virtual;
  149. procedure SendMail(From, Recipients, Subject, Msg: string);
  150. procedure SendMail(From, Recipients, Subject: string; aStream: TStream);
  151. procedure SendMail(aMail: TMail);
  152. procedure Helo(aHost: string = '');
  153. procedure Ehlo(aHost: string = '');
  154. procedure Mail(const From: string);
  155. procedure Rcpt(const RcptTo: string);
  156. procedure Data(const Msg: string);
  157. procedure Rset;
  158. procedure Quit;
  159. procedure Disconnect; override;
  160. procedure CallAction; override;
  161. public
  162. property PipeLine: Boolean read FPipeLine write FPipeLine;
  163. property StatusSet: TLSMTPStatusSet read FStatusSet write FStatusSet;
  164. property OnConnect: TLSocketEvent read FOnConnect write FOnConnect;
  165. property OnReceive: TLSocketEvent read FOnReceive write FOnReceive;
  166. property OnDisconnect: TLSocketEvent read FOnDisconnect write FOnDisconnect;
  167. property OnSuccess: TLSMTPClientStatusEvent read FOnSuccess write FOnSuccess;
  168. property OnFailure: TLSMTPClientStatusEvent read FOnFailure write FOnFailure;
  169. property OnError: TLSocketErrorEvent read FOnError write FOnError;
  170. property OnSent: TLSocketProgressEvent read FOnSent write FOnSent;
  171. end;
  172. implementation
  173. uses
  174. SysUtils, lMimeStreams;
  175. const
  176. EMPTY_REC: TLSMTPStatusRec = (Status: ssNone; Args: ('', ''));
  177. {$i lcontainers.inc}
  178. function StatusToStr(const aStatus: TLSMTPStatus): string;
  179. const
  180. STATAR: array[ssNone..ssQuit] of string = ('ssNone', 'ssCon', 'ssHelo', 'ssEhlo', 'ssMail',
  181. 'ssRcpt', 'ssData', 'ssRset', 'ssQuit');
  182. begin
  183. Result := STATAR[aStatus];
  184. end;
  185. function MakeStatusRec(const aStatus: TLSMTPStatus; const Arg1, Arg2: string): TLSMTPStatusRec;
  186. begin
  187. Result.Status := aStatus;
  188. Result.Args[1] := Arg1;
  189. Result.Args[2] := Arg2;
  190. end;
  191. { TLSMTP }
  192. function TLSMTP.GetTimeout: DWord;
  193. begin
  194. Result := FConnection.Timeout;
  195. end;
  196. procedure TLSMTP.SetTimeout(const AValue: DWord);
  197. begin
  198. FConnection.Timeout := aValue;
  199. end;
  200. function TLSMTP.GetConnected: Boolean;
  201. begin
  202. Result := FConnection.Connected;
  203. end;
  204. function TLSMTP.GetSocketClass: TLSocketClass;
  205. begin
  206. Result := FConnection.SocketClass;
  207. end;
  208. procedure TLSMTP.SetSocketClass(const AValue: TLSocketClass);
  209. begin
  210. FConnection.SocketClass := AValue;
  211. end;
  212. function TLSMTP.GetEventer: TLEventer;
  213. begin
  214. Result := FConnection.Eventer;
  215. end;
  216. procedure TLSMTP.SetEventer(Value: TLEventer);
  217. begin
  218. FConnection.Eventer := Value;
  219. end;
  220. constructor TLSMTP.Create(aOwner: TComponent);
  221. begin
  222. inherited Create(aOwner);
  223. FConnection := TLTcp.Create(nil);
  224. end;
  225. destructor TLSMTP.Destroy;
  226. begin
  227. FConnection.Free;
  228. inherited Destroy;
  229. end;
  230. { TLSMTPClient }
  231. constructor TLSMTPClient.Create(aOwner: TComponent);
  232. begin
  233. inherited Create(aOwner);
  234. FPort := 25;
  235. FStatusSet := []; // empty set for "ok/not-ok" Event
  236. FSL := TStringList.Create;
  237. // {$warning TODO: fix pipelining support when server does it}
  238. FPipeLine := False;
  239. FConnection.OnError := @OnEr;
  240. FConnection.OnCanSend := @OnCs;
  241. FConnection.OnReceive := @OnRe;
  242. FConnection.OnConnect := @OnCo;
  243. FConnection.OnDisconnect := @OnDs;
  244. FStatus := TLSMTPStatusFront.Create(EMPTY_REC);
  245. FCommandFront := TLSMTPStatusFront.Create(EMPTY_REC);
  246. end;
  247. destructor TLSMTPClient.Destroy;
  248. begin
  249. Quit;
  250. FSL.Free;
  251. FStatus.Free;
  252. FCommandFront.Free;
  253. inherited Destroy;
  254. end;
  255. procedure TLSMTPClient.OnEr(const msg: string; aSocket: TLSocket);
  256. begin
  257. if Assigned(FOnError) then
  258. FOnError(msg, aSocket);
  259. end;
  260. procedure TLSMTPClient.OnRe(aSocket: TLSocket);
  261. begin
  262. if Assigned(FOnReceive) then
  263. FOnReceive(aSocket);
  264. end;
  265. procedure TLSMTPClient.OnCo(aSocket: TLSocket);
  266. begin
  267. if Assigned(FOnConnect) then
  268. FOnConnect(aSocket);
  269. end;
  270. procedure TLSMTPClient.OnDs(aSocket: TLSocket);
  271. begin
  272. if Assigned(FOnDisconnect) then
  273. FOnDisconnect(aSocket);
  274. end;
  275. procedure TLSMTPClient.OnCs(aSocket: TLSocket);
  276. begin
  277. SendData(FStatus.First.Status = ssData);
  278. end;
  279. function TLSMTPClient.CanContinue(const aStatus: TLSMTPStatus; const Arg1, Arg2: string): Boolean;
  280. begin
  281. Result := FPipeLine or FStatus.Empty;
  282. if not Result then
  283. FCommandFront.Insert(MakeStatusRec(aStatus, Arg1, Arg2));
  284. end;
  285. function TLSMTPClient.CleanInput(var s: string): Integer;
  286. var
  287. i: Integer;
  288. begin
  289. FSL.Text := s;
  290. if FSL.Count > 0 then
  291. for i := 0 to FSL.Count-1 do
  292. if Length(FSL[i]) > 0 then EvaluateAnswer(FSL[i]);
  293. s := StringReplace(s, CRLF, LineEnding, [rfReplaceAll]);
  294. i := Pos('PASS', s);
  295. if i > 0 then
  296. s := Copy(s, 1, i-1) + 'PASS';
  297. Result := Length(s);
  298. end;
  299. procedure TLSMTPClient.EvaluateAnswer(const Ans: string);
  300. function GetNum: Integer;
  301. begin
  302. try
  303. Result := StrToInt(Copy(Ans, 1, 3));
  304. except
  305. Result := -1;
  306. end;
  307. end;
  308. function ValidResponse(const Answer: string): Boolean; inline;
  309. begin
  310. Result := (Length(Ans) >= 3) and
  311. (Ans[1] in ['1'..'5']) and
  312. (Ans[2] in ['0'..'9']) and
  313. (Ans[3] in ['0'..'9']);
  314. if Result then
  315. Result := (Length(Ans) = 3) or ((Length(Ans) > 3) and (Ans[4] = ' '));
  316. end;
  317. procedure Eventize(const aStatus: TLSMTPStatus; const Res: Boolean);
  318. begin
  319. if Res then begin
  320. if Assigned(FOnSuccess) and (aStatus in FStatusSet) then
  321. FOnSuccess(FConnection.Iterator, aStatus);
  322. end else begin
  323. if Assigned(FOnFailure) and (aStatus in FStatusSet) then
  324. FOnFailure(FConnection.Iterator, aStatus);
  325. end;
  326. end;
  327. var
  328. x: Integer;
  329. begin
  330. x := GetNum;
  331. if ValidResponse(Ans) and not FStatus.Empty then
  332. case FStatus.First.Status of
  333. ssCon,
  334. ssHelo,
  335. ssEhlo: case x of
  336. 200..299: begin
  337. Eventize(FStatus.First.Status, True);
  338. FStatus.Remove;
  339. end;
  340. else begin
  341. Eventize(FStatus.First.Status, False);
  342. Disconnect;
  343. end;
  344. end;
  345. ssMail,
  346. ssRcpt: begin
  347. Eventize(FStatus.First.Status, (x >= 200) and (x < 299));
  348. FStatus.Remove;
  349. end;
  350. ssData: case x of
  351. 200..299: begin
  352. Eventize(FStatus.First.Status, True);
  353. FStatus.Remove;
  354. end;
  355. 300..399: SendData(True);
  356. else begin
  357. Eventize(FStatus.First.Status, False);
  358. FStatus.Remove;
  359. end;
  360. end;
  361. ssRset: begin
  362. Eventize(FStatus.First.Status, (x >= 200) and (x < 299));
  363. FStatus.Remove;
  364. end;
  365. ssQuit: begin
  366. Eventize(FStatus.First.Status, (x >= 200) and (x < 299));
  367. FStatus.Remove;
  368. if Assigned(FOnDisconnect) then
  369. FOnDisconnect(FConnection.Iterator);
  370. Disconnect;
  371. end;
  372. end;
  373. if FStatus.Empty and not FCommandFront.Empty then
  374. ExecuteFrontCommand;
  375. end;
  376. procedure TLSMTPClient.ExecuteFrontCommand;
  377. begin
  378. with FCommandFront.First do
  379. case Status of
  380. ssHelo: Helo(Args[1]);
  381. ssEhlo: Ehlo(Args[1]);
  382. ssMail: Mail(Args[1]);
  383. ssRcpt: Rcpt(Args[1]);
  384. ssData: Data(Args[1]);
  385. ssRset: Rset;
  386. ssQuit: Quit;
  387. end;
  388. FCommandFront.Remove;
  389. end;
  390. procedure TLSMTPClient.InsertCRLFs;
  391. var
  392. i, c: Integer;
  393. begin
  394. c := 0;
  395. i := 2;
  396. while i <= Length(FBuffer) do begin
  397. if (FBuffer[i - 1] = #13) and (FBuffer[i] = #10) then begin
  398. c := 0;
  399. Inc(i);
  400. end else
  401. Inc(c);
  402. if c >= 74 then begin
  403. Insert(CRLF, FBuffer, i);
  404. c := 0;
  405. Inc(i, 2);
  406. end;
  407. Inc(i);
  408. end;
  409. end;
  410. procedure TLSMTPClient.SendData(const FromStream: Boolean = False);
  411. const
  412. SBUF_SIZE = 65535;
  413. procedure FillBuffer;
  414. var
  415. s: string;
  416. begin
  417. SetLength(s, SBUF_SIZE - Length(FBuffer));
  418. SetLength(s, FStream.Read(s[1], Length(s)));
  419. FBuffer := FBuffer + s;
  420. if FStream.Position = FStream.Size then begin // we finished the stream
  421. FBuffer := FBuffer + CRLF + '.' + CRLF;
  422. FStream := nil;
  423. end;
  424. end;
  425. var
  426. n: Integer;
  427. Sent: Integer;
  428. begin
  429. if FromStream and Assigned(FStream) then
  430. FillBuffer;
  431. n := 1;
  432. Sent := 0;
  433. while (Length(FBuffer) > 0) and (n > 0) do begin
  434. InsertCRLFs;
  435. n := FConnection.SendMessage(FBuffer);
  436. Sent := Sent + n;
  437. if n > 0 then
  438. Delete(FBuffer, 1, n);
  439. if FromStream and Assigned(FStream) and (Length(FBuffer) < SBUF_SIZE) then
  440. FillBuffer;
  441. end;
  442. if Assigned(FOnSent) and (FStatus.First.Status = ssData) then
  443. FOnSent(FConnection.Iterator, Sent);
  444. end;
  445. function TLSMTPClient.Connect(const aHost: string; const aPort: Word = 25): Boolean;
  446. begin
  447. Result := False;
  448. Disconnect;
  449. if FConnection.Connect(aHost, aPort) then begin
  450. FHost := aHost;
  451. FPort := aPort;
  452. FStatus.Insert(MakeStatusRec(ssCon, '', ''));
  453. Result := True;
  454. end;
  455. end;
  456. function TLSMTPClient.Connect: Boolean;
  457. begin
  458. Result := Connect(FHost, FPort);
  459. end;
  460. function TLSMTPClient.Get(var aData; const aSize: Integer; aSocket: TLSocket): Integer;
  461. var
  462. s: string;
  463. begin
  464. Result := FConnection.Get(aData, aSize, aSocket);
  465. if Result > 0 then begin
  466. SetLength(s, Result);
  467. Move(aData, PChar(s)^, Result);
  468. CleanInput(s);
  469. end;
  470. end;
  471. function TLSMTPClient.GetMessage(out msg: string; aSocket: TLSocket): Integer;
  472. begin
  473. Result := FConnection.GetMessage(msg, aSocket);
  474. if Result > 0 then
  475. Result := CleanInput(msg);
  476. end;
  477. procedure TLSMTPClient.SendMail(From, Recipients, Subject, Msg: string);
  478. var
  479. i: Integer;
  480. begin
  481. FStream := nil;
  482. From := EncodeMimeHeaderText(From);
  483. Recipients := EncodeMimeHeaderText(Recipients);
  484. Subject := EncodeMimeHeaderText(Subject);
  485. if (Length(Recipients) > 0) and (Length(From) > 0) then begin
  486. Mail(From);
  487. FSL.CommaText := StringReplace(Recipients, ' ', ',', [rfReplaceAll]);
  488. for i := 0 to FSL.Count-1 do
  489. Rcpt(FSL[i]);
  490. Data('From: ' + From + CRLF + 'Subject: ' + Subject + CRLF + 'To: ' + FSL.CommaText + CRLF + Msg);
  491. Rset;
  492. end;
  493. end;
  494. procedure TLSMTPClient.SendMail(From, Recipients, Subject: string; aStream: TStream);
  495. var
  496. i: Integer;
  497. begin
  498. From := EncodeMimeHeaderText(From);
  499. Recipients := EncodeMimeHeaderText(Recipients);
  500. Subject := EncodeMimeHeaderText(Subject);
  501. FStream := aStream;
  502. if (Length(Recipients) > 0) and (Length(From) > 0) then begin
  503. Mail(From);
  504. FSL.CommaText := StringReplace(Recipients, ' ', ',', [rfReplaceAll]);
  505. for i := 0 to FSL.Count-1 do
  506. Rcpt(FSL[i]);
  507. Data('From: ' + From + CRLF + 'Subject: ' + Subject + CRLF + 'To: ' + FSL.CommaText + CRLF);
  508. Rset;
  509. end;
  510. end;
  511. procedure TLSMTPClient.SendMail(aMail: TMail);
  512. begin
  513. if Length(aMail.MailText) > 0 then
  514. SendMail(aMail.Sender, aMail.Recipients, aMail.Subject, aMail.MailText)
  515. else if Assigned(aMail.MailStream) then
  516. SendMail(aMail.Sender, aMail.Recipients, aMail.Subject, aMail.MailStream);
  517. end;
  518. procedure TLSMTPClient.Helo(aHost: string = '');
  519. begin
  520. if Length(Host) = 0 then
  521. aHost := FHost;
  522. if CanContinue(ssHelo, aHost, '') then begin
  523. FBuffer := FBuffer + 'HELO ' + aHost + CRLF;
  524. FStatus.Insert(MakeStatusRec(ssHelo, '', ''));
  525. SendData;
  526. end;
  527. end;
  528. procedure TLSMTPClient.Ehlo(aHost: string = '');
  529. begin
  530. if Length(aHost) = 0 then
  531. aHost := FHost;
  532. if CanContinue(ssEhlo, aHost, '') then begin
  533. FBuffer := FBuffer + 'EHLO ' + aHost + CRLF;
  534. FStatus.Insert(MakeStatusRec(ssEhlo, '', ''));
  535. SendData;
  536. end;
  537. end;
  538. procedure TLSMTPClient.Mail(const From: string);
  539. begin
  540. if CanContinue(ssMail, From, '') then begin
  541. FBuffer := FBuffer + 'MAIL FROM:' + '<' + From + '>' + CRLF;
  542. FStatus.Insert(MakeStatusRec(ssMail, '', ''));
  543. SendData;
  544. end;
  545. end;
  546. procedure TLSMTPClient.Rcpt(const RcptTo: string);
  547. begin
  548. if CanContinue(ssRcpt, RcptTo, '') then begin
  549. FBuffer := FBuffer + 'RCPT TO:' + '<' + RcptTo + '>' + CRLF;
  550. FStatus.Insert(MakeStatusRec(ssRcpt, '', ''));
  551. SendData;
  552. end;
  553. end;
  554. procedure TLSMTPClient.Data(const Msg: string);
  555. begin
  556. if CanContinue(ssData, Msg, '') then begin
  557. if Assigned(FStream) then begin
  558. if Length(Msg) > 0 then
  559. FBuffer := 'DATA ' + Msg
  560. else
  561. FBuffer := 'DATA ';
  562. end else
  563. FBuffer := 'DATA ' + Msg + CRLF + '.' + CRLF;
  564. FStatus.Insert(MakeStatusRec(ssData, '', ''));
  565. SendData(True);
  566. end;
  567. end;
  568. procedure TLSMTPClient.Rset;
  569. begin
  570. if CanContinue(ssRset, '', '') then begin
  571. FBuffer := FBuffer + 'RSET' + CRLF;
  572. FStatus.Insert(MakeStatusRec(ssRset, '', ''));
  573. SendData;
  574. end;
  575. end;
  576. procedure TLSMTPClient.Quit;
  577. begin
  578. if CanContinue(ssQuit, '', '') then begin
  579. FBuffer := FBuffer + 'QUIT' + CRLF;
  580. FStatus.Insert(MakeStatusRec(ssQuit, '', ''));
  581. SendData;
  582. end;
  583. end;
  584. procedure TLSMTPClient.Disconnect;
  585. begin
  586. FConnection.Disconnect;
  587. FStatus.Clear;
  588. FCommandFront.Clear;
  589. end;
  590. procedure TLSMTPClient.CallAction;
  591. begin
  592. FConnection.CallAction;
  593. end;
  594. { TMail }
  595. constructor TMail.Create;
  596. begin
  597. end;
  598. destructor TMail.Destroy;
  599. begin
  600. end;
  601. { TAttachment }
  602. function TAttachment.GetAsText: string;
  603. begin
  604. Result := '';
  605. raise Exception.Create('Not yet implemented');
  606. end;
  607. constructor TAttachment.Create;
  608. begin
  609. FData := TStringList.Create;
  610. end;
  611. destructor TAttachment.Destroy;
  612. begin
  613. FData.Free;
  614. inherited Destroy;
  615. end;
  616. function TAttachment.LoadFromFile(const aFileName: string): Boolean;
  617. begin
  618. Result := False;
  619. raise Exception.Create('Not yet implemented');
  620. end;
  621. { TAttachmentList }
  622. function TAttachmentList.GetCount: Integer;
  623. begin
  624. Result := FItems.Count;
  625. end;
  626. function TAttachmentList.GetItem(i: Integer): TAttachment;
  627. begin
  628. Result := TAttachment(FItems[i]);
  629. end;
  630. procedure TAttachmentList.SetItem(i: Integer; const AValue: TAttachment);
  631. begin
  632. FItems[i] := aValue;
  633. end;
  634. constructor TAttachmentList.Create;
  635. begin
  636. FItems := TFPObjectList.Create(True);
  637. end;
  638. destructor TAttachmentList.Destroy;
  639. begin
  640. FItems.Free;
  641. inherited Destroy;
  642. end;
  643. function TAttachmentList.Add(anAttachment: TAttachment): Integer;
  644. begin
  645. Result := FItems.Add(anAttachment);
  646. end;
  647. function TAttachmentList.AddFromFile(const aFileName: string): Integer;
  648. var
  649. Tmp: TAttachment;
  650. begin
  651. Tmp := TAttachment.Create;
  652. if Tmp.LoadFromFile(aFileName) then
  653. Result := FItems.Add(Tmp);
  654. end;
  655. function TAttachmentList.Remove(anAttachment: TAttachment): Integer;
  656. begin
  657. Result := FItems.Remove(anAttachment);
  658. end;
  659. procedure TAttachmentList.Delete(const i: Integer);
  660. begin
  661. FItems.Delete(i);
  662. end;
  663. procedure TAttachmentList.Clear;
  664. begin
  665. FItems.Clear;
  666. end;
  667. end.