2
0

IdPOP3.pas 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664
  1. {
  2. $Project$
  3. $Workfile$
  4. $Revision$
  5. $DateUTC$
  6. $Id$
  7. This file is part of the Indy (Internet Direct) project, and is offered
  8. under the dual-licensing agreement described on the Indy website.
  9. (http://www.indyproject.org/)
  10. Copyright:
  11. (c) 1993-2005, Chad Z. Hower and the Indy Pit Crew. All rights reserved.
  12. }
  13. {
  14. $Log$
  15. }
  16. {
  17. Rev 1.39 1/7/05 3:29:12 PM RLebeau
  18. Fix for AV in Notification()
  19. Rev 1.38 12/21/04 1:51:42 AM RLebeau
  20. Bug fix for Capa() method.
  21. Rev 1.37 11/27/04 2:48:22 AM RLebeau
  22. Fixed bug in ownership of SASLMechanisms property
  23. Rev 1.36 10/26/2004 10:35:42 PM JPMugaas
  24. Updated ref.
  25. Rev 1.35 2004.04.18 1:39:26 PM czhower
  26. Bug fix for .NET with attachments, and several other issues found along the
  27. way.
  28. Rev 1.34 2004.04.07 6:02:42 PM czhower
  29. Implemented AutoLogin in a better manner.
  30. Rev 1.33 2004.04.07 5:53:56 PM czhower
  31. .NET overload
  32. Rev 1.32 2004.03.06 1:31:48 PM czhower
  33. To match Disconnect changes to core.
  34. Rev 1.31 2004.02.03 5:44:12 PM czhower
  35. Name changes
  36. Rev 1.30 2004.02.03 2:12:18 PM czhower
  37. $I path change
  38. Rev 1.29 1/25/2004 3:11:36 PM JPMugaas
  39. SASL Interface reworked to make it easier for developers to use.
  40. SSL and SASL reenabled components.
  41. Rev 1.28 1/21/2004 3:27:06 PM JPMugaas
  42. InitComponent
  43. Rev 1.27 1/12/04 12:22:40 PM RLebeau
  44. Updated RetrieveMailboxSize() and RetrieveMsgSize() to support responses that
  45. contain additional data after the octet values.
  46. Rev 1.26 22/12/2003 00:45:12 CCostelloe
  47. .NET fixes
  48. Rev 1.25 10/19/2003 5:42:36 PM DSiders
  49. Added localization comments.
  50. Rev 1.24 10/11/2003 7:14:34 PM BGooijen
  51. Changed IdCompilerDefines.inc path
  52. Rev 1.23 10/10/2003 11:39:40 PM BGooijen
  53. Compiles in DotNet now
  54. Rev 1.22 6/15/2003 01:17:10 PM JPMugaas
  55. Intermediate class no longer used. We use the SASL functionality right from
  56. the TIdSASLList.
  57. Rev 1.21 6/4/2003 04:10:36 PM JPMugaas
  58. Removed hacked GetInternelResponse.
  59. Updated to use Kudzu's new string reply code.
  60. Rev 1.20 5/26/2003 04:28:16 PM JPMugaas
  61. Removed GenerateReply and ParseResponse calls because those functions are
  62. being removed.
  63. Rev 1.19 5/26/2003 12:23:58 PM JPMugaas
  64. Rev 1.18 5/25/2003 03:54:46 AM JPMugaas
  65. Rev 1.17 5/25/2003 03:45:56 AM JPMugaas
  66. Rev 1.16 5/22/2003 05:27:52 PM JPMugaas
  67. Rev 1.16 5/20/2003 02:29:42 PM JPMugaas
  68. Updated with POP3Reply object.
  69. Rev 1.15 5/10/2003 10:10:46 PM JPMugaas
  70. Bug fixes.
  71. Rev 1.14 5/8/2003 08:44:16 PM JPMugaas
  72. Moved some SASL authentication code down to an anscestor for reuse. WIll
  73. clean up soon.
  74. Rev 1.13 5/8/2003 03:18:14 PM JPMugaas
  75. Flattened ou the SASL authentication API, made a custom descendant of SASL
  76. enabled TIdMessageClient classes.
  77. Rev 1.12 5/8/2003 11:28:10 AM JPMugaas
  78. Moved feature negoation properties down to the ExplicitTLSClient level as
  79. feature negotiation goes hand in hand with explicit TLS support.
  80. Rev 1.11 5/8/2003 03:03:00 AM JPMugaas
  81. Fixed a problem with SASL. It turns out that what was being processed with
  82. something from a previous command. It also turned out that some charactors
  83. were being removed from the SASL processing when they shouldn't have been.
  84. Rev 1.10 5/8/2003 02:18:08 AM JPMugaas
  85. Fixed an AV in IdPOP3 with SASL list on forms. Made exceptions for SASL
  86. mechanisms missing more consistant, made IdPOP3 support feature feature
  87. negotiation, and consolidated some duplicate code.
  88. Rev 1.9 5/7/2003 04:58:34 AM JPMugaas
  89. We now use the initial greeting message from the server when calculating the
  90. parameter for the APOP command. Note that we were calling CAPA before APOP
  91. and that could throw things off.
  92. Rev 1.8 4/5/2003 02:06:24 PM JPMugaas
  93. TLS handshake itself can now be handled.
  94. Rev 1.7 3/27/2003 05:46:40 AM JPMugaas
  95. Updated framework with an event if the TLS negotiation command fails.
  96. Cleaned up some duplicate code in the clients.
  97. Rev 1.6 3/19/2003 08:53:40 PM JPMugaas
  98. Now should work with new framework.
  99. Rev 1.5 3/17/2003 02:25:26 PM JPMugaas
  100. Updated to use new TLS framework. Now can require that users use TLS. Note
  101. that this setting create an incompatiability with Norton AntiVirus because
  102. that does act as a "man in the middle" when intercepting E-Mail for virus
  103. scanning.
  104. Rev 1.4 3/13/2003 09:49:26 AM JPMugaas
  105. Now uses an abstract SSL base class instead of OpenSSL so 3rd-party vendors
  106. can plug-in their products.
  107. Rev 1.3 2/24/2003 09:27:58 PM JPMugaas
  108. Rev 1.2 12/15/2002 04:27:10 PM JPMugaas
  109. POP3 now compiles and works in Indy 10.
  110. Rev 1.1 12-15-2002 12:57:40 BGooijen
  111. Added Top-command
  112. Rev 1.0 11/13/2002 07:58:22 AM JPMugaas
  113. 2002-08-18 - J. Berg
  114. - implement SASL, add CAPA and STLS
  115. 02 August 2002 - A. Neillans
  116. - Bug fix:
  117. [ 574171 ] TIdMessage not cleared before a retreive
  118. 11-10-2001 - J. Peter Mugaas
  119. Added suggested code from Andrew P.Rybin that does the following:
  120. -APOP Authentication Support
  121. -unrecognized text header now displayed in exception message
  122. -GetUIDL method
  123. 2001-AUG-31 DSiders
  124. Changed TIdPOP3.Connect to use ATimeout when calling
  125. inherited Connect.
  126. 2000-SEPT-28 SG
  127. Added GetUIDL as from code by
  128. 2000-MAY-10 HH
  129. Added RetrieveMailBoxSize and renamed RetrieveSize to RetrieveMsgSize.
  130. Finished Connect.
  131. 2000-MARCH-03 HH
  132. Converted to Indy
  133. }
  134. unit IdPOP3;
  135. { POP 3 (Post Office Protocol Version 3) }
  136. interface
  137. {$i IdCompilerDefines.inc}
  138. uses
  139. Classes,
  140. IdAssignedNumbers,
  141. IdGlobal,
  142. IdException,
  143. IdExplicitTLSClientServerBase,
  144. IdGlobalProtocols,
  145. IdMessage,
  146. IdMessageClient,
  147. IdReply,
  148. IdSASL,
  149. IdSASLCollection;
  150. type
  151. TIdPOP3AuthenticationType = (patUserPass, patAPOP, patSASL);
  152. const
  153. DEF_POP3USE_IMPLICIT_TLS = False;
  154. DEF_ATYPE = patUserPass;
  155. type
  156. TIdPOP3 = class(TIdMessageClient)
  157. protected
  158. FAuthType : TIdPOP3AuthenticationType;
  159. FAutoLogin: Boolean;
  160. FAPOPToken : String;
  161. FHasAPOP: Boolean;
  162. FHasCAPA: Boolean;
  163. FSASLMechanisms : TIdSASLEntries;
  164. FSASLCanAttemptIR: Boolean;
  165. //
  166. function GetReplyClass:TIdReplyClass; override;
  167. function GetSupportsTLS: Boolean; override;
  168. procedure SetSASLMechanisms(AValue: TIdSASLEntries);
  169. procedure InitComponent; override;
  170. procedure Notification(AComponent: TComponent; Operation: TOperation); override;
  171. public
  172. function CheckMessages: Integer;
  173. procedure Connect; override;
  174. procedure Login; virtual;
  175. destructor Destroy; override;
  176. function Delete(const MsgNum: Integer): Boolean;
  177. procedure DisconnectNotifyPeer; override;
  178. procedure KeepAlive;
  179. function List(const ADest: TStrings; const AMsgNum: Integer = -1): Boolean;
  180. procedure ParseLIST(ALine: String; var VMsgNum: Integer; var VMsgSize: Int64);
  181. procedure ParseUIDL(ALine: String; var VMsgNum: Integer; var VUidl: String);
  182. function Reset: Boolean;
  183. function Retrieve(const MsgNum: Integer; AMsg: TIdMessage): Boolean;
  184. function RetrieveHeader(const MsgNum: Integer; AMsg: TIdMessage): Boolean;
  185. function RetrieveMsgSize(const MsgNum: Integer): Int64;
  186. function RetrieveMailBoxSize: Int64;
  187. function RetrieveRaw(const aMsgNo: Integer; const aDest: TStrings): boolean; overload;
  188. function RetrieveRaw(const aMsgNo: Integer; const aDest: TStream): boolean; overload;
  189. function RetrieveStats(var VMsgCount: Integer; var VMailBoxSize: Int64): Boolean;
  190. function UIDL(const ADest: TStrings; const AMsgNum: Integer = -1): Boolean;
  191. function Top(const AMsgNum: Integer; const ADest: TStrings; const AMaxLines: Integer = 0): boolean;
  192. function CAPA: Boolean;
  193. property HasAPOP: boolean read FHasAPOP;
  194. property HasCAPA: boolean read FHasCAPA;
  195. published
  196. property AuthType : TIdPOP3AuthenticationType read FAuthType write FAuthType default DEF_ATYPE;
  197. property AutoLogin: Boolean read FAutoLogin write FAutoLogin default True;
  198. property Host;
  199. property Username;
  200. property UseTLS;
  201. property Password;
  202. property Port default IdPORT_POP3;
  203. property SASLMechanisms : TIdSASLEntries read FSASLMechanisms write SetSASLMechanisms;
  204. property SASLCanAttemptInitialResponse: Boolean read FSASLCanAttemptIR write FSASLCanAttemptIR default True;
  205. end;
  206. type
  207. EIdPOP3Exception = class(EIdException);
  208. EIdDoesNotSupportAPOP = class(EIdPOP3Exception);
  209. EIdUnrecognizedReply = class(EIdPOP3Exception);
  210. implementation
  211. uses
  212. IdFIPS,
  213. IdHash,
  214. IdHashMessageDigest,
  215. IdTCPConnection,
  216. IdSSL,
  217. IdResourceStringsProtocols,
  218. IdReplyPOP3,
  219. IdCoderMIME,
  220. SysUtils;
  221. { TIdPOP3 }
  222. function TIdPOP3.CheckMessages: Integer;
  223. var
  224. LIgnore: Int64;
  225. begin
  226. // RLebeau: for backwards compatibility, raise an exception if STAT fails
  227. if not RetrieveStats(Result, LIgnore) then begin
  228. RaiseExceptionForLastCmdResult;
  229. end;
  230. // Only gets here if exception is not raised
  231. end;
  232. procedure TIdPOP3.Login;
  233. var
  234. S: String;
  235. LMD5: TIdHashMessageDigest5;
  236. function IsSASLSupported: Boolean;
  237. var
  238. i : Integer;
  239. LBuf : String;
  240. begin
  241. Result := False;
  242. for i := 0 to FCapabilities.Count -1 do begin
  243. LBuf := TrimLeft(FCapabilities[i]);
  244. if TextIsSame(Fetch(LBuf), 'SASL') then begin {do not localize}
  245. Result := True;
  246. Exit;
  247. end;
  248. end;
  249. end;
  250. begin
  251. if UseTLS in ExplicitTLSVals then begin
  252. if SupportsTLS then begin
  253. if SendCmd('STLS','') = ST_OK then begin {Do not translate}
  254. TLSHandshake;
  255. //obtain capabilities again - RFC2595
  256. CAPA;
  257. end else begin
  258. ProcessTLSNegCmdFailed;
  259. end;
  260. end else begin
  261. ProcessTLSNotAvail;
  262. end;
  263. end;
  264. case FAuthType of
  265. patAPOP: //APR
  266. begin
  267. if FHasAPOP then begin
  268. CheckMD5Permitted;
  269. LMD5 := TIdHashMessageDigest5.Create;
  270. try
  271. S := LowerCase(LMD5.HashStringAsHex(FAPOPToken+Password));
  272. finally
  273. LMD5.Free;
  274. end;//try
  275. SendCmd('APOP ' + Username + ' ' + S, ST_OK); {Do not Localize}
  276. end else begin
  277. raise EIdDoesNotSupportAPOP.Create(RSPOP3ServerDoNotSupportAPOP);
  278. end;
  279. end;
  280. patUserPass:
  281. begin //classic method
  282. SendCmd('USER ' + Username, ST_OK); {Do not Localize}
  283. SendCmd('PASS ' + Password, ST_OK); {Do not Localize}
  284. end;//if APOP
  285. patSASL:
  286. begin
  287. // SASL in POP3 did not originally support Initial-Response. It was added
  288. // in RFC 2449 along with the CAPA command. If a server supports the CAPA
  289. // command then it *should* also support Initial-Response as well, however
  290. // many POP3 servers support CAPA but do not support Initial-Response
  291. // (which was formalized in RFC 5034).
  292. //
  293. // RFC 5034 says:
  294. //
  295. // "If a server either does not support the CAPA command or does not
  296. // advertise the SASL capability, clients SHOULD NOT attempt the AUTH
  297. // command. If a client does attempt the AUTH command in such a
  298. // situation, it MUST NOT supply the client initial response
  299. // parameter (for backwards compatibility with [RFC1734])."
  300. //
  301. // So, as most modern POP3 servers do support Initial-Response now, we
  302. // will attempt Initial-Response by default, unless told not to. For
  303. // instance, Microsoft Office 365 does not support Initial-Response
  304. // when using XOAuth2 authentication (why?)...
  305. // TODO: look in the SASLMechanisms if XOAuth2 is enabled, and if so
  306. // then disable Initial-Response...
  307. FSASLMechanisms.LoginSASL('AUTH', FHost, FPort, IdGSKSSN_pop, [ST_OK], [ST_SASLCONTINUE], Self, Capabilities, 'SASL', {do not localize}
  308. FSASLCanAttemptIR and HasCAPA and IsSASLSupported
  309. );
  310. end;
  311. end;
  312. end;
  313. procedure TIdPOP3.InitComponent;
  314. begin
  315. inherited;
  316. FAutoLogin := True;
  317. FSASLMechanisms := TIdSASLEntries.Create(Self);
  318. FSASLCanAttemptIR := True;
  319. FRegularProtPort := IdPORT_POP3;
  320. FImplicitTLSProtPort := IdPORT_POP3S;
  321. FExplicitTLSProtPort := IdPORT_POP3;
  322. Port := IdPORT_POP3;
  323. FAuthType := DEF_ATYPE;
  324. end;
  325. function TIdPOP3.Delete(const MsgNum: Integer): Boolean;
  326. begin
  327. Result := (SendCmd('DELE ' + IntToStr(MsgNum), '') = ST_OK); {do not localize}
  328. end;
  329. procedure TIdPOP3.DisconnectNotifyPeer;
  330. begin
  331. inherited DisconnectNotifyPeer;
  332. SendCmd('QUIT', ST_OK); {do not localize}
  333. end;
  334. function TIdPOP3.GetReplyClass:TIdReplyClass;
  335. begin
  336. Result := TIdReplyPOP3;
  337. end;
  338. procedure TIdPOP3.KeepAlive;
  339. begin
  340. SendCmd('NOOP', ST_OK); {Do not Localize}
  341. end;
  342. function TIdPOP3.Reset: Boolean;
  343. begin
  344. Result := (SendCmd('RSET', '') = ST_OK); {Do not Localize}
  345. end;
  346. function TIdPOP3.RetrieveRaw(const aMsgNo: Integer; const aDest: TStrings): boolean;
  347. var
  348. LEncoding: IIdTextEncoding;
  349. begin
  350. Result := (SendCmd('RETR ' + IntToStr(aMsgNo), '') = ST_OK); {Do not Localize}
  351. if Result then begin
  352. LEncoding := IndyTextEncoding_8Bit;
  353. IOHandler.Capture(aDest, LEncoding{$IFDEF STRING_IS_ANSI}, LEncoding{$ENDIF});
  354. end;
  355. end;
  356. function TIdPOP3.RetrieveRaw(const aMsgNo: Integer; const aDest: TStream): boolean;
  357. var
  358. LEncoding: IIdTextEncoding;
  359. begin
  360. Result := (SendCmd('RETR ' + IntToStr(aMsgNo), '') = ST_OK); {Do not Localize}
  361. if Result then begin
  362. LEncoding := IndyTextEncoding_8Bit;
  363. IOHandler.Capture(aDest, LEncoding{$IFDEF STRING_IS_ANSI}, LEncoding{$ENDIF});
  364. end;
  365. end;
  366. function TIdPOP3.Retrieve(const MsgNum: Integer; AMsg: TIdMessage): Boolean;
  367. begin
  368. Result := (SendCmd('RETR ' + IntToStr(MsgNum), '') = ST_OK); {Do not Localize}
  369. if Result then begin
  370. AMsg.Clear;
  371. // This is because of a bug in Exchange? with empty messages. See comment in ReceiveHeader
  372. if ReceiveHeader(AMsg) = '' then begin
  373. // Only retreive the body if we do not already have a full RFC
  374. ReceiveBody(AMsg);
  375. end;
  376. end;
  377. end;
  378. function TIdPOP3.RetrieveHeader(const MsgNum: Integer; AMsg: TIdMessage): Boolean;
  379. begin
  380. // Result := False;
  381. AMsg.Clear;
  382. SendCmd('TOP ' + IntToStr(MsgNum) + ' 0', ST_OK); {Do not Localize}
  383. // Only gets here if no exception is raised
  384. ReceiveHeader(AMsg,'.');
  385. Result := True;
  386. end;
  387. function TIdPOP3.RetrieveMailBoxSize: Int64;
  388. var
  389. LIgnore: Integer;
  390. begin
  391. // RLebeau: for backwards compatibility, return -1 if STAT fails
  392. try
  393. if not RetrieveStats(LIgnore, Result) then begin
  394. RaiseExceptionForLastCmdResult;
  395. end;
  396. except
  397. Result := -1;
  398. end;
  399. end;
  400. function TIdPOP3.RetrieveMsgSize(const MsgNum: Integer): Int64;
  401. var
  402. s: string;
  403. begin
  404. Result := -1;
  405. // Returns the size of the message. if an error ocurrs, returns -1.
  406. SendCmd('LIST ' + IntToStr(MsgNum), ST_OK); {Do not Localize}
  407. s := LastCmdResult.Text[0];
  408. if Length(s) > 0 then begin
  409. // RL - ignore the message number, grab just the octets,
  410. // and ignore everything else that may be present
  411. Fetch(s);
  412. Result := IndyStrToInt64(Fetch(s), -1);
  413. end;
  414. end;
  415. function TIdPOP3.RetrieveStats(var VMsgCount: Integer; var VMailBoxSize: Int64): Boolean;
  416. var
  417. s: string;
  418. begin
  419. VMsgCount := 0;
  420. VMailBoxSize := 0;
  421. Result := (SendCmd('STAT', '') = ST_OK); {Do not Localize}
  422. if Result then begin
  423. s := LastCmdResult.Text[0];
  424. if Length(s) > 0 then begin
  425. VMsgCount := IndyStrToInt(Fetch(s));
  426. VMailBoxSize := IndyStrToInt64(Fetch(s));
  427. end;
  428. end;
  429. end;
  430. function TIdPOP3.List(const ADest: TStrings; const AMsgNum: Integer = -1): Boolean;
  431. var
  432. LEncoding: IIdTextEncoding;
  433. begin
  434. if AMsgNum >= 0 then begin
  435. Result := (SendCmd('LIST ' + IntToStr(AMsgNum), '') = ST_OK); {Do not Localize}
  436. if Result then begin
  437. ADest.Assign(LastCmdResult.Text);
  438. end;
  439. end
  440. else begin
  441. Result := (SendCmd('LIST', '') = ST_OK); {Do not Localize}
  442. if Result then begin
  443. LEncoding := IndyTextEncoding_8Bit;
  444. IOHandler.Capture(ADest, LEncoding{$IFDEF STRING_IS_ANSI}, LEncoding{$ENDIF});
  445. end;
  446. end;
  447. end;
  448. procedure TIdPOP3.ParseLIST(ALine: String; var VMsgNum: Integer; var VMsgSize: Int64);
  449. begin
  450. VMsgNum := IndyStrToInt(Fetch(ALine), -1);
  451. VMsgSize := IndyStrToInt64(Fetch(ALine), -1);
  452. end;
  453. function TIdPOP3.UIDL(const ADest: TStrings; const AMsgNum: Integer = -1): Boolean;
  454. var
  455. LEncoding: IIdTextEncoding;
  456. begin
  457. if AMsgNum >= 0 then begin
  458. Result := (SendCmd('UIDL ' + IntToStr(AMsgNum), '') = ST_OK); {Do not Localize}
  459. if Result then begin
  460. ADest.Assign(LastCmdResult.Text);
  461. end;
  462. end
  463. else begin
  464. Result := (SendCmd('UIDL', '') = ST_OK); {Do not Localize}
  465. if Result then begin
  466. LEncoding := IndyTextEncoding_8Bit;
  467. IOHandler.Capture(ADest, LEncoding{$IFDEF STRING_IS_ANSI}, LEncoding{$ENDIF});
  468. end;
  469. end;
  470. end;
  471. procedure TIdPOP3.ParseUIDL(ALine: String; var VMsgNum: Integer; var VUidl: String);
  472. begin
  473. VMsgNum := IndyStrToInt(Fetch(ALine), -1);
  474. VUidl := Fetch(ALine);
  475. end;
  476. function TIdPOP3.Top(const AMsgNum: Integer; const ADest: TStrings; const AMaxLines: Integer = 0): boolean;
  477. var
  478. Cmd: String;
  479. LEncoding: IIdTextEncoding;
  480. begin
  481. Cmd := 'TOP ' + IntToStr(AMsgNum); {Do not Localize}
  482. if AMaxLines <> 0 then begin
  483. Cmd := Cmd + ' ' + IntToStr(AMaxLines); {Do not Localize}
  484. end;
  485. Result := (SendCmd(Cmd,'') = ST_OK);
  486. if Result then begin
  487. LEncoding := IndyTextEncoding_8Bit;
  488. IOHandler.Capture(ADest, LEncoding{$IFDEF STRING_IS_ANSI}, LEncoding{$ENDIF});
  489. end;
  490. end;
  491. destructor TIdPOP3.Destroy;
  492. begin
  493. FreeAndNil(FSASLMechanisms);
  494. inherited;
  495. end;
  496. function TIdPOP3.CAPA: Boolean;
  497. begin
  498. FCapabilities.Clear;
  499. Result := (SendCmd('CAPA','') = ST_OK); {Do not Localize}
  500. if Result then begin
  501. IOHandler.Capture(FCapabilities);
  502. end;
  503. // RLebeau - do not delete here! The +OK reply line is handled
  504. // by SendCmd() above. Deleting here is removing an actual capability entry.
  505. {
  506. if FCapabilities.Count >0 then
  507. begin
  508. //dete the initial OK reply line
  509. FCapabilities.Delete(0);
  510. end;
  511. FHasCapa := Result;
  512. }
  513. FHasCapa := (FCapabilities.Count > 0);
  514. // ParseCapaReply(FCapabilities,'SASL');
  515. end;
  516. procedure TIdPOP3.Notification(AComponent: TComponent; Operation: TOperation);
  517. begin
  518. if (Operation = opRemove) and (FSASLMechanisms <> nil) then begin
  519. FSASLMechanisms.RemoveByComp(AComponent);
  520. end;
  521. inherited Notification(AComponent,Operation);
  522. end;
  523. function TIdPOP3.GetSupportsTLS: Boolean;
  524. begin
  525. Result := ( FCapabilities.IndexOf('STLS') > -1 ); //do not localize
  526. end;
  527. procedure TIdPOP3.SetSASLMechanisms(AValue: TIdSASLEntries);
  528. begin
  529. FSASLMechanisms.Assign(AValue);
  530. end;
  531. procedure TIdPOP3.Connect;
  532. var
  533. S: String;
  534. I: Integer;
  535. begin
  536. FHasAPOP := False;
  537. FHasCAPA := False;
  538. FAPOPToken := '';
  539. if (IOHandler is TIdSSLIOHandlerSocketBase) then begin
  540. (IOHandler as TIdSSLIOHandlerSocketBase).PassThrough := (FUseTLS <> utUseImplicitTLS);
  541. end;
  542. inherited Connect;
  543. try
  544. GetResponse(ST_OK);
  545. // the initial greeting text is needed to determine APOP availability
  546. S := LastCmdResult.Text.Strings[0]; //read response
  547. I := Pos('<', S); {Do not Localize}
  548. if i > 0 then begin
  549. S := Copy(S, I, MaxInt); //?: System.Delete(S,1,i-1);
  550. I := Pos('>', S); {Do not Localize}
  551. if I > 0 then begin
  552. FAPOPToken := Copy(S, 1, I);
  553. end;
  554. end;
  555. FHasAPOP := (Length(FAPOPToken) > 0);
  556. CAPA;
  557. if FAutoLogin then begin
  558. Login;
  559. end;
  560. except
  561. Disconnect(False);
  562. raise;
  563. end;
  564. end;
  565. end.