PageRenderTime 66ms CodeModel.GetById 20ms RepoModel.GetById 1ms app.codeStats 0ms

/ProSnooperFx_src/indy10.0.52_source/Protocols/IdFTP.pas

http://github.com/lookias/ProSnooper
Pascal | 3570 lines | 2455 code | 217 blank | 898 comment | 270 complexity | 8f38ef32b852a662d62336598357674d MD5 | raw file
  1. { $HDR$}
  2. {**********************************************************************}
  3. { Unit archived using Team Coherence }
  4. { Team Coherence is Copyright 2002 by Quality Software Components }
  5. { }
  6. { For further information / comments, visit our WEB site at }
  7. { http://www.TeamCoherence.com }
  8. {**********************************************************************}
  9. {}
  10. { $Log: 13828: IdFTP.pas
  11. {
  12. { Rev 1.102 11/5/2004 1:54:42 AM JPMugaas
  13. { Minor adjustment - should not detect TitanFTPD better (tested at:
  14. { ftp.southrivertech.com).
  15. {
  16. { If MLSD is being used, SITE ZONE will not be issued. It's not needed because
  17. { the MLSD spec indicates the time is based on GMT.
  18. }
  19. {
  20. { Rev 1.101 10/27/2004 12:58:08 AM JPMugaas
  21. { Improvement from Tobias Giesen http://www.superflexible.com
  22. { His notation is below:
  23. {
  24. { "here's a fix for TIdFTP.IndexOfFeatLine. It does not work the
  25. { way it is used in TIdFTP.SetModTime, because it only
  26. { compares the first word of the FeatLine."
  27. }
  28. {
  29. { Rev 1.100 10/26/2004 9:19:10 PM JPMugaas
  30. { Fixed references.
  31. }
  32. {
  33. { Rev 1.99 9/16/2004 3:24:04 AM JPMugaas
  34. { TIdFTP now compresses to the IOHandler and decompresses from the IOHandler.
  35. {
  36. { Noted some that the ZLib code is based was taken from ZLibEx.
  37. }
  38. {
  39. { Rev 1.98 9/13/2004 12:15:42 AM JPMugaas
  40. { Now should be able to handle some values better as suggested by Michael J.
  41. { Leave.
  42. }
  43. {
  44. { Rev 1.97 9/11/2004 10:58:06 AM JPMugaas
  45. { FTP now decompresses output directly to the IOHandler.
  46. }
  47. {
  48. { Rev 1.96 9/10/2004 7:37:42 PM JPMugaas
  49. { Fixed a bug. We needed to set Passthrough instead of calling StartSSL. This
  50. { was causing a SSL problem with upload.
  51. }
  52. {
  53. { Rev 1.95 8/2/04 5:56:16 PM RLebeau
  54. { Tweaks to TIdFTP.InitDataChannel()
  55. }
  56. {
  57. Rev 1.94 7/30/2004 1:55:04 AM DSiders
  58. Corrected DoOnRetrievedDir naming.
  59. }
  60. {
  61. Rev 1.93 7/30/2004 12:36:32 AM DSiders
  62. Corrected spelling in OnRetrievedDir, DoOnRetrievedDir declarations.
  63. }
  64. {
  65. { Rev 1.92 7/29/2004 2:15:28 AM JPMugaas
  66. { New property for controlling what AUTH command is sent. Fixed some minor
  67. { issues with FTP properties. Some were not set to defaults causing
  68. { unpredictable results -- OOPS!!!
  69. }
  70. {
  71. { Rev 1.91 7/29/2004 12:04:40 AM JPMugaas
  72. { New events for Get and Put as suggested by Don Sides and to complement an
  73. { event done by APR.
  74. }
  75. {
  76. { Rev 1.90 7/28/2004 10:16:14 AM JPMugaas
  77. { New events for determining when a listing is finished and when the dir
  78. { parsing begins and ends. Dir parsing is done sometimes when DirectoryListing
  79. { is referenced.
  80. }
  81. {
  82. { Rev 1.89 7/27/2004 2:03:54 AM JPMugaas
  83. { New property:
  84. {
  85. { ExternalIP - used to specify an IP address for the PORT and EPRT commands.
  86. { This should be blank unless you are behind a NAT and you need to use PORT
  87. { transfers with SSL. You would set ExternalIP to the NAT's IP address on the
  88. { Internet.
  89. {
  90. { The idea is this:
  91. {
  92. { 1) You set up your NAT to forward a range ports ports to your computer behind
  93. { the NAT.
  94. { 2) You specify that a port range with the DataPortMin and DataPortMin
  95. { properties.
  96. { 3) You set ExternalIP to the NAT's Internet IP address.
  97. {
  98. { I have verified this with Indy and WS FTP Pro behind a NAT router.
  99. }
  100. {
  101. { Rev 1.88 7/23/04 7:09:50 PM RLebeau
  102. { Bug fix for TFileStream access rights in Get()
  103. }
  104. {
  105. Rev 1.87 7/18/2004 3:00:12 PM DSiders
  106. Added localization comments.
  107. }
  108. {
  109. { Rev 1.86 7/16/2004 4:28:40 AM JPMugaas
  110. { CCC Support in TIdFTP to complement that capability in TIdFTPServer.
  111. }
  112. {
  113. { Rev 1.85 7/13/04 6:48:14 PM RLebeau
  114. { Added support for new DataPort and DataPortMin/Max properties
  115. }
  116. {
  117. Rev 1.84 7/6/2004 4:51:46 PM DSiders
  118. Corrected spelling of Challenge in properties, methods, types.
  119. }
  120. {
  121. { Rev 1.83 7/3/2004 3:15:50 AM JPMugaas
  122. { Checked in so everyone else can work on stuff while I'm away.
  123. }
  124. {
  125. { Rev 1.82 6/27/2004 1:45:38 AM JPMugaas
  126. { Can now optionally support LastAccessTime like Smartftp's FTP Server could.
  127. { I also made the MLST listing object and parser support this as well.
  128. }
  129. {
  130. { Rev 1.81 6/20/2004 8:31:58 PM JPMugaas
  131. { New events for reporting greeting and after login banners during the login
  132. { sequence.
  133. }
  134. {
  135. { Rev 1.80 6/20/2004 6:56:42 PM JPMugaas
  136. { Start oin attempt to support FXP with Deflate compression. More work will
  137. { need to be done.
  138. }
  139. {
  140. { Rev 1.79 6/17/2004 3:42:32 PM JPMugaas
  141. { Adjusted code for removal of dmBlock and dmCompressed. Made TransferMode a
  142. { property. Note that the Set method is odd because I am trying to keep
  143. { compatibility with older Indy versions.
  144. }
  145. {
  146. { Rev 1.78 6/14/2004 6:19:02 PM JPMugaas
  147. { This now refers to TIdStreamVCL when downloading isntead of directly to a
  148. { memory stream when compressing data.
  149. }
  150. {
  151. { Rev 1.77 6/14/2004 8:34:52 AM JPMugaas
  152. { Fix for AV on Put with Passive := True.
  153. }
  154. {
  155. Rev 1.76 6/11/2004 9:34:12 AM DSiders
  156. Added "Do not Localize" comments.
  157. }
  158. {
  159. { Rev 1.75 2004.05.20 11:37:16 AM czhower
  160. { IdStreamVCL
  161. }
  162. {
  163. { Rev 1.74 5/6/2004 6:54:26 PM JPMugaas
  164. { FTP Port transfers with TransparentProxies is enabled. This only works if
  165. { the TransparentProxy supports a "bind" request.
  166. }
  167. {
  168. { Rev 1.73 5/4/2004 11:16:28 AM JPMugaas
  169. { TransferTimeout property added and enabled (Bug 96).
  170. }
  171. {
  172. { Rev 1.72 5/4/2004 11:07:12 AM JPMugaas
  173. { Timeouts should now be reenabled in TIdFTP.
  174. }
  175. {
  176. { Rev 1.71 4/19/2004 5:05:02 PM JPMugaas
  177. { Class rework Kudzu wanted.
  178. }
  179. {
  180. { Rev 1.70 2004.04.16 9:31:42 PM czhower
  181. { Remove unnecessary duplicate string parsing and replaced with .assign.
  182. }
  183. {
  184. { Rev 1.69 2004.04.15 7:09:04 PM czhower
  185. { .NET overloads
  186. }
  187. {
  188. { Rev 1.68 4/15/2004 9:46:48 AM JPMugaas
  189. { List no longer requires a TStrings. It turns out that it was an optional
  190. { parameter.
  191. }
  192. {
  193. { Rev 1.67 2004.04.15 2:03:28 PM czhower
  194. { Removed login param from connect and made it a prop like POP3.
  195. }
  196. {
  197. { Rev 1.66 3/3/2004 5:57:40 AM JPMugaas
  198. { Some IFDEF excluses were removed because the functionality is now in DotNET.
  199. }
  200. {
  201. { Rev 1.65 2004.03.03 11:54:26 AM czhower
  202. { IdStream change
  203. }
  204. {
  205. { Rev 1.64 2/20/2004 1:01:06 PM JPMugaas
  206. { Preliminary FTP PRET command support for using PASV with a distributed FTP
  207. { server (Distributed PASV -
  208. { http://drftpd.org/wiki/wiki.phtml?title=Distributed_PASV).
  209. }
  210. {
  211. { Rev 1.63 2/17/2004 12:25:52 PM JPMugaas
  212. { The client now supports MODE Z (deflate) uploads and downloads as specified
  213. { by http://www.ietf.org/internet-drafts/draft-preston-ftpext-deflate-00.txt
  214. }
  215. {
  216. { Rev 1.62 2004.02.03 5:45:10 PM czhower
  217. { Name changes
  218. }
  219. {
  220. { Rev 1.61 2004.02.03 2:12:06 PM czhower
  221. { $I path change
  222. }
  223. {
  224. { Rev 1.60 1/27/2004 10:17:10 PM JPMugaas
  225. { Fix from Steve Loft for a server that sends something like this:
  226. { "227 Passive mode OK (195,92,195,164,4,99 )"
  227. }
  228. {
  229. { Rev 1.59 1/27/2004 3:59:28 PM SPerry
  230. { StringStream ->IdStringStream
  231. }
  232. {
  233. { Rev 1.58 24/01/2004 19:13:58 CCostelloe
  234. { Cleaned up warnings
  235. }
  236. {
  237. { Rev 1.57 1/21/2004 2:27:50 PM JPMugaas
  238. { Bullete Proof FTPD and Titan FTP support SITE ZONE. Saw this in a command
  239. { database in StaffFTP.
  240. { InitComponent.
  241. }
  242. {
  243. { Rev 1.56 1/19/2004 9:05:38 PM JPMugaas
  244. { Fixes to FTP Set Date functionality.
  245. { Introduced properties for Time Zone information from the server. The way it
  246. { works is this, if TIdFTP detects you are using "Serv-U" or SITE ZONE is
  247. { listed in the FEAT reply, Indy obtains the time zone information with the
  248. { SITE ZONE command and makes the appropriate calculation. Indy then uses this
  249. { information to calculate a timestamp to send to the server with the MDTM
  250. { command. You can also use the Time Zone information yourself to convert the
  251. { FTP directory listing item timestamps into GMT and than convert that to your
  252. { local time.
  253. { FTP Voyager uses SITE ZONE as I've described.
  254. }
  255. {
  256. { Rev 1.55 1/19/2004 4:39:08 AM JPMugaas
  257. { You can now set the time for a file on the server. Note that these methods
  258. { try to treat the time as relative to GMT.
  259. }
  260. {
  261. { Rev 1.54 1/17/2004 9:09:30 PM JPMugaas
  262. { Should now compile.
  263. }
  264. {
  265. { Rev 1.53 1/17/2004 7:48:02 PM JPMugaas
  266. { FXP site to site transfer code was redone for improvements with FXP with TLS.
  267. { It actually works and I verified with RaidenFTPD
  268. { (http://www.raidenftpd.com/) and the Indy FTP server components. I also
  269. { lowered the requirements for TLS FXP transfers. The requirements now are:
  270. { 1) Only server (either the recipient or the sendor) has to support SSCN
  271. {
  272. { or
  273. {
  274. { 2) The server receiving a PASV must support CPSV and the transfer is done
  275. { with IPv4.
  276. }
  277. {
  278. { Rev 1.52 1/9/2004 2:51:26 PM JPMugaas
  279. { Started IPv6 support.
  280. }
  281. {
  282. { Rev 1.51 11/27/2003 4:55:28 AM JPMugaas
  283. { Made STOU functionality separate from PUT functionality. Put now requires a
  284. { destination filename except where a source-file name is given. In that case,
  285. { the default is the filename from the source string.
  286. }
  287. {
  288. { Rev 1.50 10/26/2003 04:28:50 PM JPMugaas
  289. { Reworked Status.
  290. {
  291. { The old one was problematic because it assumed that STAT was a request to
  292. { send a directory listing through the control channel. This assumption is not
  293. { correct. It provides a way to get a freeform status report from a server.
  294. { With a Path parameter, it should work like a LIST command except that the
  295. { control connection is used. We don't support that feature and you should use
  296. { our LIst method to get the directory listing anyway, IMAO.
  297. }
  298. {
  299. { Rev 1.49 10/26/2003 9:17:46 PM BGooijen
  300. { Compiles in DotNet, and partially works there
  301. }
  302. {
  303. { Rev 1.48 10/24/2003 12:43:48 PM JPMugaas
  304. { Should work again.
  305. }
  306. {
  307. { Rev 1.47 2003.10.24 10:43:04 AM czhower
  308. { TIdSTream to dos
  309. }
  310. {
  311. { Rev 1.46 10/20/2003 03:06:10 PM JPMugaas
  312. { SHould now work.
  313. }
  314. {
  315. { Rev 1.45 10/20/2003 01:00:38 PM JPMugaas
  316. { EIdException no longer raised. Some things were being gutted needlessly.
  317. }
  318. {
  319. Rev 1.44 10/19/2003 12:58:20 PM DSiders
  320. Added localization comments.
  321. }
  322. {
  323. { Rev 1.43 2003.10.14 9:56:50 PM czhower
  324. { Compile todos
  325. }
  326. {
  327. { Rev 1.42 2003.10.12 3:50:40 PM czhower
  328. { Compile todos
  329. }
  330. {
  331. { Rev 1.41 10/10/2003 11:32:26 PM SPerry
  332. { -
  333. }
  334. {
  335. { Rev 1.40 10/9/2003 10:17:02 AM JPMugaas
  336. { Added overload for GetLoginPassword for providing a challanage string which
  337. { doesn't have to the last command reply.
  338. { Added CLNT support.
  339. }
  340. {
  341. { Rev 1.39 10/7/2003 05:46:20 AM JPMugaas
  342. { SSCN Support added.
  343. }
  344. {
  345. { Rev 1.38 10/6/2003 08:56:44 PM JPMugaas
  346. { Reworked the FTP list parsing framework so that the user can obtain the list
  347. { of capabilities from a parser class with TIdFTP. This should permit the user
  348. { to present a directory listing differently for each parser (some FTP list
  349. { parsers do have different capabilities).
  350. }
  351. {
  352. { Rev 1.37 10/1/2003 12:51:18 AM JPMugaas
  353. { SSL with active (PORT) transfers now should work again.
  354. }
  355. {
  356. { Rev 1.36 9/30/2003 09:50:38 PM JPMugaas
  357. { FTP with TLS should work better. It turned out that we were negotiating it
  358. { several times causing a hang. I also made sure that we send PBSZ 0 and PROT
  359. { P for both implicit and explicit TLS. Data ports should work in PASV again.
  360. }
  361. {
  362. { Rev 1.35 9/28/2003 11:41:06 PM JPMugaas
  363. { Reworked Eldos's proposed FTP fix as suggested by Henrick Hellström by moving
  364. { all of the IOHandler creation code to InitDataChannel. This should reduce
  365. { the likelihood of error.
  366. }
  367. {
  368. { Rev 1.33 9/18/2003 11:22:40 AM JPMugaas
  369. { Removed a temporary workaround for an OnWork bug that was in the Indy Core.
  370. { That bug was fixed so there's no sense in keeping a workaround here.
  371. }
  372. {
  373. { Rev 1.32 9/12/2003 08:05:30 PM JPMugaas
  374. { A temporary fix for OnWork events not firing. The bug is that OnWork events
  375. { aren't used in IOHandler where ReadStream really is located.
  376. }
  377. {
  378. { Rev 1.31 9/8/2003 02:33:00 AM JPMugaas
  379. { OnCustomFTPProxy added to allow Indy to support custom FTP proxies. When
  380. { using this event, you are responsible for programming the FTP Proxy and FTP
  381. { Server login sequence.
  382. { GetLoginPassword method function for returning the password used when logging
  383. { into a FTP server which handles OTP calculation. This way, custom firewall
  384. { support can handle One-Time-Password system transparently. You do have to
  385. { send the User ID before calling this function because the OTP challenge is
  386. { part of the reply.
  387. }
  388. {
  389. { Rev 1.30 6/10/2003 11:10:00 PM JPMugaas
  390. { Made comments about our loop that tries several AUTH command variations.
  391. { Some servers may only accept AUTH SSL while other servers only accept AUTH
  392. { TLS.
  393. }
  394. {
  395. { Rev 1.29 5/26/2003 12:21:54 PM JPMugaas
  396. }
  397. {
  398. { Rev 1.28 5/25/2003 03:54:20 AM JPMugaas
  399. }
  400. {
  401. { Rev 1.27 5/19/2003 08:11:32 PM JPMugaas
  402. { Now should compile properly with new code in Core.
  403. }
  404. {
  405. { Rev 1.26 5/8/2003 11:27:42 AM JPMugaas
  406. { Moved feature negoation properties down to the ExplicitTLSClient level as
  407. { feature negotiation goes hand in hand with explicit TLS support.
  408. }
  409. {
  410. { Rev 1.25 4/5/2003 02:06:34 PM JPMugaas
  411. { TLS handshake itself can now be handled.
  412. }
  413. {
  414. Rev 1.24 4/4/2003 8:01:32 PM BGooijen
  415. now creates iohandler for dataconnection
  416. }
  417. {
  418. { Rev 1.23 3/31/2003 08:40:18 AM JPMugaas
  419. { Fixed problem with QUIT command.
  420. }
  421. {
  422. Rev 1.22 3/27/2003 3:41:28 PM BGooijen
  423. Changed because some properties are moved to IOHandler
  424. }
  425. {
  426. { Rev 1.21 3/27/2003 05:46:24 AM JPMugaas
  427. { Updated framework with an event if the TLS negotiation command fails.
  428. { Cleaned up some duplicate code in the clients.
  429. }
  430. {
  431. { Rev 1.20 3/26/2003 04:19:20 PM JPMugaas
  432. { Cleaned-up some code and illiminated some duplicate things.
  433. }
  434. {
  435. { Rev 1.19 3/24/2003 04:56:10 AM JPMugaas
  436. { A typecast was incorrect and could cause a potential source of instability if
  437. { a TIdIOHandlerStack was not used.
  438. }
  439. {
  440. { Rev 1.18 3/16/2003 06:09:58 PM JPMugaas
  441. { Fixed port setting bug.
  442. }
  443. {
  444. { Rev 1.17 3/16/2003 02:40:16 PM JPMugaas
  445. { FTP client with new design.
  446. }
  447. {
  448. Rev 1.16 3/16/2003 1:02:44 AM BGooijen
  449. Added 2 events to give the user more control to the dataconnection, moved
  450. SendTransferType, enabled ssl
  451. }
  452. {
  453. { Rev 1.15 3/13/2003 09:48:58 AM JPMugaas
  454. { Now uses an abstract SSL base class instead of OpenSSL so 3rd-party vendors
  455. { can plug-in their products.
  456. }
  457. {
  458. { Rev 1.14 3/7/2003 11:51:52 AM JPMugaas
  459. { Fixed a writeln bug and an IOError issue.
  460. }
  461. {
  462. { Rev 1.13 3/3/2003 07:06:26 PM JPMugaas
  463. { FFreeIOHandlerOnDisconnect to FreeIOHandlerOnDisconnect at Bas's instruction
  464. }
  465. {
  466. { Rev 1.12 2/21/2003 06:54:36 PM JPMugaas
  467. { The FTP list processing has been restructured so that Directory output is not
  468. { done by IdFTPList. This now also uses the IdFTPListParserBase for parsing so
  469. { that the code is more scalable.
  470. }
  471. {
  472. { Rev 1.11 2/17/2003 04:45:36 PM JPMugaas
  473. { Now temporarily change the transfer mode to ASCII when requesting a DIR.
  474. { TOPS20 does not like transfering dirs in binary mode and it might be a good
  475. { idea to do it anyway.
  476. }
  477. {
  478. { Rev 1.10 2/16/2003 03:22:20 PM JPMugaas
  479. { Removed the Data Connection assurance stuff. We figure things out from the
  480. { draft specificaiton, the only servers we found would not send any data after
  481. { the new commands were sent, and there were only 2 server types that supported
  482. { it anyway.
  483. }
  484. {
  485. { Rev 1.9 2/16/2003 10:51:08 AM JPMugaas
  486. { Attempt to implement:
  487. {
  488. { http://www.ietf.org/internet-drafts/draft-ietf-ftpext-data-connection-assuranc
  489. { e-00.txt
  490. {
  491. { Currently commented out because it does not work.
  492. }
  493. {
  494. { Rev 1.8 2/14/2003 11:40:16 AM JPMugaas
  495. { Fixed compile error.
  496. }
  497. {
  498. { Rev 1.7 2/14/2003 10:38:32 AM JPMugaas
  499. { Removed a problematic override for GetInternelResponse. It was messing up
  500. { processing of the FEAT.
  501. }
  502. {
  503. { Rev 1.6 12-16-2002 20:48:10 BGooijen
  504. { now uses TIdIOHandler.ConstructIOHandler to construct iohandlers
  505. { IPv6 works again
  506. { Independant of TIdIOHandlerStack again
  507. }
  508. {
  509. { Rev 1.5 12-15-2002 23:27:26 BGooijen
  510. { now compiles on Indy 10, but some things like IPVersion still need to be
  511. { changed
  512. }
  513. {
  514. { Rev 1.4 12/15/2002 04:07:02 PM JPMugaas
  515. { Started port to Indy 10. Still can not complete it though.
  516. }
  517. {
  518. { Rev 1.3 12/6/2002 05:29:38 PM JPMugaas
  519. { Now decend from TIdTCPClientCustom instead of TIdTCPClient.
  520. }
  521. {
  522. { Rev 1.2 12/1/2002 04:18:02 PM JPMugaas
  523. { Moved all dir parsing code to one place. Reworked to use more than one line
  524. { for determining dir format type along with flfNextLine dir format type.
  525. }
  526. {
  527. { Rev 1.1 11/14/2002 04:02:58 PM JPMugaas
  528. { Removed cludgy code that was a workaround for the RFC Reply limitation. That
  529. { is no longer limited.
  530. }
  531. {
  532. { Rev 1.0 11/14/2002 02:20:00 PM JPMugaas
  533. }
  534. unit IdFTP;
  535. {
  536. Change Log:
  537. 2002-10-25 - J. Peter Mugaas
  538. - added XCRC support - specified by "GlobalSCAPE Secure FTP Server User’s Guide"
  539. which is available at http://www.globalscape.com
  540. and also explained at http://www.southrivertech.com/support/titanftp/webhelp/titanftp.htm
  541. - added COMB support - specified by "GlobalSCAPE Secure FTP Server User’s Guide"
  542. which is available at http://www.globalscape.com
  543. and also explained at http://www.southrivertech.com/support/titanftp/webhelp/titanftp.htm
  544. 2002-10-24 - J. Peter Mugaas
  545. - now supports RFC 2640 - FTP Internalization
  546. 2002-09-18
  547. _ added AFromBeginning parameter to InternalPut to correctly honor the AAppend parameter of Put
  548. 2002-09-05 - J. Peter Mugaas
  549. - now complies with RFC 2389 - Feature negotiation mechanism for the File Transfer Protocol
  550. - now complies with RFC 2428 - FTP Extensions for IPv6 and NATs
  551. 2002-08-27 - Andrew P.Rybin
  552. - proxy support fix (non-standard ftp port's)
  553. 2002-01-xx - Andrew P.Rybin
  554. - Proxy support, OnAfterGet (ex:decrypt, set srv timestamp)
  555. - J.Peter Mugaas: not readonly ProxySettings
  556. A Neillans - 10/17/2001
  557. Merged changes submitted by Andrew P.Rybin
  558. Correct command case problems - some servers expect commands in Uppercase only.
  559. SP - 06/08/2001
  560. Added a few more functions
  561. Doychin - 02/18/2001
  562. OnAfterLogin event handler and Login method
  563. OnAfterLogin is executed after successfull login but before setting up the
  564. connection properties. This event can be used to provide FTP proxy support
  565. from the user application. Look at the FTP demo program for more information
  566. on how to provide such support.
  567. Doychin - 02/17/2001
  568. New onFTPStatus event
  569. New Quote method for executing commands not implemented by the compoent
  570. -CleanDir contributed by Amedeo Lanza
  571. TODO: Chage the FTP demo to demonstrate the use of the new events and add proxy support
  572. }
  573. interface
  574. uses
  575. Classes,
  576. IdAssignedNumbers, IdGlobal, IdCustomTransparentProxy, IdExceptionCore,
  577. IdExplicitTLSClientServerBase, IdFTPCommon, IdFTPList, IdFTPListParseBase, IdException,
  578. IdIOHandler, IdIOHandlerSocket,
  579. IdReplyFTP,
  580. IdReplyRFC,
  581. IdReply,
  582. IdSocketHandle, IdStreamVCL,
  583. IdTCPConnection, IdTCPClient, IdThread, IdTStrings, IdZLibCompressorBase;
  584. type
  585. //Added by SP
  586. TIdCreateFTPList = procedure(ASender: TObject; Var VFTPList: TIdFTPListItems) of object;
  587. // TIdCheckListFormat = procedure(ASender: TObject; const ALine: String; Var VListFormat: TIdFTPListFormat) of object;
  588. TOnAfterClientLogin = TNotifyEvent;
  589. TIdFtpAfterGet = procedure (ASender: TObject; VStream: TStream) of object; //APR
  590. TIdOnDataChannelCreate = procedure (ASender: TObject; ADataChannel: TIdTCPConnection) of object;
  591. TIdOnDataChannelDestroy = procedure (ASender: TObject; ADataChannel: TIdTCPConnection) of object;
  592. const
  593. Id_TIdFTP_TransferType = ftBinary;
  594. Id_TIdFTP_Passive = False;
  595. Id_TIdFTP_UseNATFastTrack = False;
  596. Id_TIdFTP_HostPortDelimiter = ':';
  597. Id_TIdFTP_DataConAssurance = False;
  598. type
  599. //APR 011216:
  600. TIdFtpProxyType = (fpcmNone,//Connect method:
  601. fpcmUserSite, //Send command USER user@hostname
  602. fpcmSite, //Send command SITE (with logon)
  603. fpcmOpen, //Send command OPEN
  604. fpcmUserPass,//USER user@firewalluser@hostname / PASS pass@firewallpass
  605. fpcmTransparent, //First use the USER and PASS command with the firewall username and password, and then with the target host username and password.
  606. fpcmHttpProxyWithFtp, //HTTP Proxy with FTP support. Will be supported in Indy 10
  607. fpcmCustomProxy // use OnCustomFTPProxy to customize the proxy login
  608. ); //TIdFtpProxyType
  609. //This has to be in the same order as TLS_AUTH_NAMES
  610. TAuthCmd = (tAuto, tAuthTLS, tAuthSSL, tAuthTLSC, tAuthTLSP);
  611. const
  612. Id_TIdFTP_DataPortProtection = ftpdpsClear;
  613. DEF_Id_TIdFTP_Implicit = False;
  614. DEF_Id_FTP_UseExtendedDataPort = False;
  615. DEF_Id_TIdFTP_UseExtendedData = False;
  616. DEF_Id_TIdFTP_UseMIS = False;
  617. DEF_Id_FTP_UseCCC = False;
  618. DEF_Id_FTP_AUTH_CMD = tAuto;
  619. type
  620. TIdFTPBannerEvent = procedure (ASender: TObject; const AMsg : String) of object;
  621. TIdFTPClientIdentifier = class (TPersistent)
  622. protected
  623. FClientName : String;
  624. FClientVersion : String;
  625. FPlatformDescription : String;
  626. procedure SetClientName(const AValue: String);
  627. procedure SetClientVersion(const AValue: String);
  628. procedure SetPlatformDescription(const AValue: String);
  629. function GetClntOutput: String;
  630. public
  631. procedure Assign(Source: TPersistent); override;
  632. property ClntOutput : String read GetClntOutput;
  633. published
  634. property ClientName : String read FClientName write SetClientName;
  635. property ClientVersion : String read FClientVersion write SetClientVersion;
  636. property PlatformDescription : String read FPlatformDescription write SetPlatformDescription;
  637. end;
  638. TIdFtpProxySettings = class (TPersistent)
  639. protected
  640. FHost, FUserName, FPassword: String;
  641. FProxyType: TIdFtpProxyType;
  642. FPort: Integer;
  643. public
  644. procedure Assign(Source: TPersistent); override;
  645. published
  646. property ProxyType: TIdFtpProxyType read FProxyType write FProxyType;
  647. property Host: String read FHost write FHost;
  648. property UserName: String read FUserName write FUserName;
  649. property Password: String read FPassword write FPassword;
  650. property Port: Integer read FPort write FPort;
  651. End;//TIdFtpProxySettings
  652. TIdFTPTZInfo = class(TPersistent)
  653. protected
  654. FGMTOffset : TDateTime;
  655. FGMTOffsetAvailable : Boolean;
  656. public
  657. procedure Assign(Source: TPersistent); override;
  658. published
  659. property GMTOffset : TDateTime read FGMTOffset write FGMTOffset;
  660. property GMTOffsetAvailable : Boolean read FGMTOffsetAvailable write FGMTOffsetAvailable;
  661. end;
  662. TIdFTP = class(TIdExplicitTLSClient)
  663. protected
  664. FAutoLogin: Boolean;
  665. FCurrentTransferMode : TIdFTPTransferMode;
  666. FClientInfo : TIdFTPClientIdentifier;
  667. FUsingSFTP : Boolean; //enable SFTP internel flag
  668. FUsingCCC : Boolean; //are we using FTP with SSL on a clear control channel?
  669. FCanUseMLS : Boolean; //can we use MLISx instead of LIST
  670. FUsedMLS : Boolean; //Did the developer use MLSx commands for the last list command
  671. FUsingExtDataPort : Boolean; //are NAT Extensions (RFC 2428 available) flag
  672. FUsingNATFastTrack : Boolean;//are we using NAT fastrack feature
  673. FCanResume: Boolean;
  674. FListResult: TIdStrings;
  675. FLoginMsg: TIdReplyFTP;
  676. FPassive: boolean;
  677. FDataPortProtection : TIdFTPDataPortSecurity;
  678. FAUTHCmd : TAuthCmd;
  679. FDataPort: Integer;
  680. FDataPortMin: Integer;
  681. FDataPortMax: Integer;
  682. FExternalIP : String;
  683. FResumeTested: Boolean;
  684. FSystemDesc: string;
  685. FTransferType: TIdFTPTransferType;
  686. FTransferTimeout : Integer;
  687. FDataChannel: TIdTCPConnection;
  688. FDirectoryListing: TIdFTPListItems;
  689. FDirFormat : String;
  690. FListParserClass : TIdFTPListParseClass;
  691. FOnAfterClientLogin: TNotifyEvent;
  692. FOnCreateFTPList: TIdCreateFTPList;
  693. FOnBeforeGet: TNotifyEvent;
  694. FOnBeforePut: TIdFtpAfterGet;
  695. //in case someone needs to do something special with the data being uploaded
  696. FOnAfterGet: TIdFtpAfterGet; //APR
  697. FOnAfterPut: TNotifyEvent; //JPM at Don Sider's suggestion
  698. FOnCustomFTPProxy : TNotifyEvent;
  699. FOnDataChannelCreate:TIdOnDataChannelCreate;
  700. FOnDataChannelDestroy:TIdOnDataChannelDestroy;
  701. FProxySettings: TIdFtpProxySettings;
  702. FUseExtensionDataPort : Boolean;
  703. FTryNATFastTrack : Boolean;
  704. FUseMLIS : Boolean;
  705. FLangsSupported : TIdStrings;
  706. FUseCCC: Boolean;
  707. //is the SSCN Client method on for this connection?
  708. FSSCNOn : Boolean;
  709. FOnBannerBeforeLogin : TIdFTPBannerEvent;
  710. FOnBannerAfterLogin : TIdFTPBannerEvent;
  711. FTZInfo : TIdFTPTZInfo;
  712. FCompressor : TIdZLibCompressorBase;
  713. //ZLib settings
  714. FZLibCompressionLevel : Integer; //7
  715. FZLibWindowBits : Integer; //-15
  716. FZLibMemLevel : Integer; //8
  717. FZLibStratagy : Integer; //0 - default
  718. //dir events for some GUI programs.
  719. //The directory was Retrieved from the FTP server.
  720. FOnRetrievedDir : TNotifyEvent;
  721. //parsing is done only when DirectoryListing is referenced
  722. FOnDirParseStart : TNotifyEvent;
  723. FOnDirParseEnd : TNotifyEvent;
  724. procedure DoOnRetrievedDir;
  725. procedure DoOnDirParseStart;
  726. procedure DoOnDirParseEnd;
  727. procedure SetTZInfo(const Value: TIdFTPTZInfo);
  728. function IsSiteZONESupported : Boolean;
  729. function IndexOfFeatLine(const AFeatLine : String):Integer;
  730. procedure ClearSSCN;
  731. function SetSSCNToOn : Boolean;
  732. procedure SendInternalPassive(const ACmd : String; var VIP: string; var VPort: integer);
  733. procedure SendCPassive(var VIP: string; var VPort: integer);
  734. function FindAuthCmd : String;
  735. function GetReplyClass:TIdReplyClass; override;
  736. //
  737. function EPRTParams(const AIP : String; const APort : Integer; const AIPVersion : TIdIPVersion): String;
  738. procedure ParseFTPList(AData : TIdStrings);
  739. procedure SetPassive(const AValue : Boolean);
  740. procedure SetTryNATFastTrack(const AValue: Boolean);
  741. procedure DoTryNATFastTrack;
  742. procedure SetUseExtensionDataPort(const AValue: Boolean);
  743. procedure SetIPVersion(const AValue: TIdIPVersion); override;
  744. procedure SetIOHandler(AValue: TIdIOHandler); override;
  745. function GetSupportsTLS: Boolean; override;
  746. procedure ConstructDirListing;
  747. procedure DoAfterLogin;
  748. procedure DoFTPList;
  749. procedure DoCustomFTPProxy;
  750. procedure DoOnBannerAfterLogin(AText : TIdStrings);
  751. procedure DoOnBannerBeforeLogin(AText : TIdStrings);
  752. procedure SendPBSZ; //protection buffer size
  753. procedure SendPROT; //data port protection
  754. procedure SendDataSettings; //this is for the extensions only;
  755. // procedure DoCheckListFormat(const ALine: String);
  756. function GetDirectoryListing: TIdFTPListItems;
  757. // function GetOnParseCustomListFormat: TIdOnParseCustomListFormat;
  758. procedure InitDataChannel;
  759. //PRET is to help distributed FTP systems by letting them know what you will do
  760. //before issuing a PASV. See: http://drftpd.mog.se/wiki/wiki.phtml?title=Distributed_PASV#PRE_Transfer_Command_for_Distributed_PASV_Transfers
  761. //for a discussion.
  762. procedure SendPret(const ACommand : String);
  763. procedure InternalGet(const ACommand: string; ADest: TIdStreamVCL; AResume: Boolean = false);
  764. procedure InternalPut(const ACommand: string; ASource: TIdStreamVCL; AFromBeginning: Boolean = true);
  765. // procedure SetOnParseCustomListFormat(const AValue: TIdOnParseCustomListFormat);
  766. procedure SendPassive(var VIP: string; var VPort: integer);
  767. procedure SendPort(AHandle: TIdSocketHandle); overload;
  768. procedure SendPort(const AIP : String; const APort : Integer); overload;
  769. procedure ParseEPSV(const AReply : String; var VIP : String; VPort : Integer);
  770. //These two are for RFC 2428.txt
  771. procedure SendEPort(AHandle: TIdSocketHandle); overload;
  772. procedure SendEPort(const AIP : String; const APort : Integer; const AIPVersion : TIdIPVersion); overload;
  773. procedure SendEPassive(var VIP: string; var VPort: integer);
  774. procedure SetProxySettings(const Value: TIdFtpProxySettings);
  775. procedure SetClientInfo(const AValue: TIdFTPClientIdentifier);
  776. procedure SendTransferType;
  777. procedure SetTransferType(AValue: TIdFTPTransferType);
  778. procedure DoBeforeGet; virtual;
  779. procedure DoBeforePut (AStream: TStream); virtual;
  780. procedure DoAfterGet (AStream: TStream); virtual; //APR
  781. procedure DoAfterPut; virtual;
  782. function IsValidOTPString(const AResponse:string):boolean;
  783. function GenerateOTP(const AResponse:string; const APassword:string):string;
  784. procedure FXPSetTransferPorts(AFromSite, AToSite: TIdFTP;
  785. const ATargetUsesPasv : Boolean);
  786. procedure FXPSendFile(AFromSite, AToSite: TIdFTP;
  787. const ASourceFile, ADestFile: String);
  788. function InternalEncryptedTLSFXP(AFromSite, AToSite: TIdFTP; const ASourceFile,
  789. ADestFile: String; const ATargetUsesPasv : Boolean) : Boolean;
  790. function InternalUnencryptedFXP(AFromSite, AToSite: TIdFTP; const ASourceFile,
  791. ADestFile: String; const ATargetUsesPasv : Boolean): Boolean;
  792. function ValidateInternalIsTLSFXP(AFromSite, AToSite: TIdFTP; const ATargetUsesPasv : Boolean): Boolean;
  793. procedure InitComponent; override;
  794. procedure SetUseTLS(AValue : TIdUseTLS); override;
  795. procedure Notification(AComponent: TComponent; Operation: TOperation); override;
  796. procedure SetDataPortProtection(AValue : TIdFTPDataPortSecurity);
  797. procedure SetAUTHCmd(const AValue : TAuthCmd);
  798. procedure SetUseCCC(const AValue: Boolean);
  799. public
  800. function IsExtSupported(const ACmd : String):Boolean;
  801. procedure ExtractFeatFacts(const ACmd : String; AResults : TIdStrings);
  802. //this function transparantly handles OTP based on the Last command response
  803. //so it needs to be called only after the USER command or equivilent.
  804. function GetLoginPassword : String; overload;
  805. function GetLoginPassword(const APrompt : String) : String; overload;
  806. procedure Abort; virtual;
  807. procedure Account(AInfo: String);
  808. procedure Allocate(AAllocateBytes: Integer);
  809. procedure ChangeDir(const ADirName: string);
  810. procedure ChangeDirUp;
  811. procedure Connect; override;
  812. destructor Destroy; override;
  813. procedure Delete(const AFilename: string);
  814. procedure FileStructure(AStructure: TIdFTPDataStructure);
  815. procedure Get(const ASourceFile: string; ADest: TIdStreamVCL; AResume: Boolean = false); overload;
  816. procedure Get(const ASourceFile: string; ADest: TStream; AResume: Boolean = false); overload;
  817. procedure Get(const ASourceFile, ADestFile: string; const ACanOverwrite: boolean = false; AResume: Boolean = false); overload;
  818. procedure Help(var AHelpContents: TIdStringList; ACommand: String = '');
  819. procedure KillDataChannel; virtual;
  820. procedure List; overload; //.NET Overload
  821. procedure List( //.NET Overload
  822. const ASpecifier: string;
  823. ADetails: Boolean = True); overload;
  824. procedure List(
  825. ADest: TIdStrings;
  826. const ASpecifier: string = '';
  827. ADetails: Boolean = True); overload;
  828. procedure ExtListDir(const ADest: TIdStrings=nil; const ADirectory: string = '');
  829. procedure ExtListItem(ADest: TIdStrings; AFList : TIdFTPListItems; const AItem: string=''); overload;
  830. procedure ExtListItem(ADest: TIdStrings; const AItem: string = ''); overload;
  831. procedure ExtListItem(AFList : TIdFTPListItems; const AItem : String= ''); overload;
  832. function FileDate(const AFileName : String; const AsGMT : Boolean = False): TDateTime;
  833. procedure Login;
  834. procedure MakeDir(const ADirName: string);
  835. procedure Noop;
  836. procedure SetCMDOpt(const ACMD, AOptions : String);
  837. procedure Put(const ASource: TIdStreamVCL; const ADestFile: string;
  838. const AAppend: boolean = false); overload;
  839. procedure Put(const ASource: TStream; const ADestFile: string;
  840. const AAppend: boolean = false); overload;
  841. procedure Put(const ASourceFile: string; const ADestFile: string = '';
  842. const AAppend: boolean = false); overload;
  843. procedure StoreUnique(const ASource: TIdStreamVCL); overload;
  844. procedure StoreUnique(const ASource: TStream); overload;
  845. procedure StoreUnique(const ASourceFile: string); overload;
  846. procedure SiteToSiteUpload(const AToSite : TIdFTP; const ASourceFile : String; const ADestFile : String = '');
  847. procedure SiteToSiteDownload(const AFromSite: TIdFTP; const ASourceFile : String; const ADestFile : String = '');
  848. procedure Quit;
  849. function Quote(const ACommand: String): SmallInt;
  850. procedure RemoveDir(const ADirName: string);
  851. procedure Rename(const ASourceFile, ADestFile: string);
  852. function ResumeSupported: Boolean;
  853. function RetrieveCurrentDir: string;
  854. procedure Site(const ACommand: string);
  855. function Size(const AFileName: String): Integer;
  856. procedure Status(AStatusList: TIdStrings);
  857. procedure StructureMount(APath: String);
  858. procedure TransferMode(ATransferMode: TIdFTPTransferMode);
  859. procedure ReInitialize(ADelay: Cardinal = 10);
  860. procedure SetLang(const ALangTag : String);
  861. function CRC(const AFIleName : String; const AStartPoint : Cardinal = 0; const AEndPoint : Cardinal=0) : Int64;
  862. //file parts must be in order in TIdStrings parameter
  863. //GlobalScape FTP Pro uses this for multipart simultanious file uploading
  864. procedure CombineFiles(const ATargetFile : String; AFileParts : TIdStrings);
  865. //Set modified file time.
  866. procedure SetModTime(const AFileName: String; const ALocalTime: TDateTime);
  867. procedure SetModTimeGMT(const AFileName : String; const AGMTTime: TDateTime);
  868. // servers that support MDTM yyyymmddhhmmss[+-xxx] and also support LIST -T
  869. //This is true for servers that are known to support these even if they aren't
  870. //listed in the FEAT reply.
  871. function IsServerMDTZAndListTForm : Boolean;
  872. //
  873. property CanResume: Boolean read ResumeSupported;
  874. property DirectoryListing: TIdFTPListItems read GetDirectoryListing;
  875. property DirFormat : String read FDirFormat;
  876. property LangsSupported : TIdStrings read FLangsSupported;
  877. property ListParserClass : TIdFTPListParseClass read FListParserClass write FListParserClass;
  878. property LoginMsg: TIdReplyFTP read FLoginMsg;
  879. property ListResult: TIdStrings read FListResult;
  880. property SystemDesc: string read FSystemDesc;
  881. property TZInfo : TIdFTPTZInfo read FTZInfo write SetTZInfo;
  882. property UsingExtDataPort : Boolean read FUsingExtDataPort;
  883. property UsingNATFastTrack : Boolean read FUsingNATFastTrack;
  884. property UsingSFTP : Boolean read FUsingSFTP;
  885. property CurrentTransferMode : TIdFTPTransferMode read FCurrentTransferMode write TransferMode;
  886. published
  887. property AutoLogin: Boolean read FAutoLogin write FAutoLogin;
  888. // This is an object that can compress and decompress HTTP Deflate encoding
  889. property Compressor : TIdZLibCompressorBase read FCompressor write FCompressor;
  890. property Host;
  891. property UseCCC : Boolean read FUseCCC write SetUseCCC default DEF_Id_FTP_UseCCC;
  892. property Passive: boolean read FPassive write SetPassive default Id_TIdFTP_Passive;
  893. property DataPortProtection : TIdFTPDataPortSecurity read FDataPortProtection write SetDataPortProtection default Id_TIdFTP_DataPortProtection;
  894. property AUTHCmd : TAuthCmd read FAUTHCmd write SetAUTHCmd default DEF_Id_FTP_AUTH_CMD;
  895. property DataPort: Integer read FDataPort write FDataPort default 0;
  896. property DataPortMin: Integer read FDataPortMin write FDataPortMin default 0;
  897. property DataPortMax: Integer read FDataPortMax write FDataPortMax default 0;
  898. property ExternalIP : String read FExternalIP write FExternalIP;
  899. property Password;
  900. property TransferType: TIdFTPTransferType read FTransferType write SetTransferType default Id_TIdFTP_TransferType;
  901. property TransferTimeout: Integer read FTransferTimeout write FTransferTimeout default IdDefTimeout;
  902. property Username;
  903. property Port default IDPORT_FTP;
  904. property UseExtensionDataPort : Boolean read FUseExtensionDataPort write SetUseExtensionDataPort default DEF_Id_TIdFTP_UseExtendedData;
  905. property UseMLIS : Boolean read FUseMLIS write FUseMLIS default DEF_Id_TIdFTP_UseMIS;
  906. property TryNATFastTrack : Boolean read FTryNATFastTrack write SetTryNATFastTrack default Id_TIdFTP_UseNATFastTrack;
  907. property ProxySettings: TIdFtpProxySettings read FProxySettings write SetProxySettings;
  908. property ClientInfo : TIdFTPClientIdentifier read FClientInfo write SetClientInfo;
  909. property UseTLS;
  910. property OnTLSNotAvailable;
  911. property OnBannerBeforeLogin : TIdFTPBannerEvent read FOnBannerBeforeLogin write FOnBannerBeforeLogin;
  912. property OnBannerAfterLogin : TIdFTPBannerEvent read FOnBannerAfterLogin write FOnBannerAfterLogin;
  913. property OnAfterClientLogin: TOnAfterClientLogin read FOnAfterClientLogin write FOnAfterClientLogin;
  914. property OnCreateFTPList: TIdCreateFTPList read FOnCreateFTPList write FOnCreateFTPList;
  915. property OnAfterGet: TIdFtpAfterGet read FOnAfterGet write FOnAfterGet; //APR
  916. property OnCustomFTPProxy : TNotifyEvent read FOnCustomFTPProxy write FOnCustomFTPProxy;
  917. property OnDataChannelCreate:TIdOnDataChannelCreate read FOnDataChannelCreate write FOnDataChannelCreate;
  918. property OnDataChannelDestroy:TIdOnDataChannelDestroy read FOnDataChannelDestroy write FOnDataChannelDestroy;
  919. //The directory was Retrieved from the FTP server.
  920. property OnRetrievedDir : TNotifyEvent read FOnRetrievedDir write FOnRetrievedDir;
  921. //parsing is done only when DirectoryLiusting is referenced
  922. property OnDirParseStart : TNotifyEvent read FOnDirParseStart write FOnDirParseStart;
  923. property OnDirParseEnd : TNotifyEvent read FOnDirParseEnd write FOnDirParseEnd;
  924. end;
  925. EIdFTPException = class(EIdException);
  926. EIdFTPFileAlreadyExists = class(EIdFTPException);
  927. EIdFTPMustUseExtWithIPv6 = class(EIdFTPException);
  928. EIdFTPMustUseExtWithNATFastTrack = class(EIdFTPException);
  929. EIdFTPPassiveMustBeTrueWithNATFT = class(EIdFTPException);
  930. EIdFTPServerSentInvalidPort = class(EIdFTPException);
  931. EIdFTPSiteToSiteTransfer = class(EIdFTPException);
  932. EIdFTPSToSNATFastTrack = class(EIdFTPSiteToSiteTransfer);
  933. EIdFTPSToSNoDataProtection = class(EIdFTPSiteToSiteTransfer);
  934. EIdFTPSToSIPProtoMustBeSame = class(EIdFTPSiteToSiteTransfer);
  935. EIdFTPSToSBothMostSupportSSCN = class(EIdFTPSiteToSiteTransfer);
  936. EIdFTPSToSTransModesMustBeSame = class(EIdFTPSiteToSiteTransfer);
  937. EIdFTPUnknownOTPMethodException = class(EIdFTPException);
  938. EIdFTPOnCustomFTPProxyRequired = class(EIdFTPException);
  939. EIdFTPConnAssuranceFailure = class(EIdFTPException);
  940. EIdFTPWrongIOHandler = class(EIdFTPException);
  941. EIdFTPUploadFileNameCanNotBeEmpty = class(EIdFTPException);
  942. EIdFTPDataPortProtection = class(EIdFTPException);
  943. EIdFTPNoDataPortProtectionAfterCCC = class(EIdFTPDataPortProtection);
  944. EIdFTPNoDataPortProtectionWOEncryption = class(EIdFTPDataPortProtection);
  945. EIdFTPNoCCCWOEncryption = class(EIdFTPException);
  946. EIdFTPAUTHException = class(EIdFTPException);
  947. EIdFTPNoAUTHWOSSL = class(EIdFTPAUTHException);
  948. EIdFTPCanNotSetAUTHCon = class(EIdFTPAUTHException);
  949. implementation
  950. uses
  951. IdComponent, IdResourceStringsCore, IdIOHandlerStack, IdResourceStringsProtocols,
  952. IdSSL, IdGlobalProtocols,
  953. IdStack, IdSimpleServer,
  954. SysUtils, IdOTPCalculator;
  955. function CleanDirName(const APWDReply: string): string;
  956. begin
  957. Result := APWDReply;
  958. Delete(result, 1, IndyPos('"', result)); // Remove first doublequote {do not localize}
  959. Result := Copy(result, 1, IndyPos('"', result) - 1); // Remove anything from second doublequote {do not localize} // to end of line
  960. end;
  961. function TIdFTP.IsValidOTPString(const AResponse:string):boolean;
  962. var LChallenge:string;
  963. LChallengeStartPos:integer;
  964. LMethod:string;
  965. begin
  966. LChallengeStartPos := pos('otp-',AResponse); {do not localize}
  967. if LChallengeStartPos>0 then begin
  968. inc(LChallengeStartPos,4); // to remove "otp-"
  969. LChallenge:=copy(AResponse,LChallengeStartPos,$FFFF);
  970. LMethod:=Fetch(LChallenge);
  971. result := (LMethod='md4') or (LMethod='md5') or (LMethod='sha1'); // methods are case sensitive {do not localize}
  972. end else result:=false;
  973. end;
  974. function TIdFTP.GenerateOTP(const AResponse:string; const APassword:string):string;
  975. var LChallenge:string;
  976. LChallengeStartPos:integer;
  977. LMethod:string;
  978. LSeed:string;
  979. LCount:integer;
  980. begin
  981. LChallengeStartPos := pos('otp-', AResponse); {do not localize}
  982. if LChallengeStartPos > 0 then begin
  983. inc(LChallengeStartPos, 4); // to remove "otp-"
  984. LChallenge := copy(AResponse,LChallengeStartPos, $FFFF);
  985. LMethod := Fetch(LChallenge);
  986. LCount := StrToInt(Fetch(LChallenge));
  987. LSeed := Fetch(LChallenge);
  988. if LMethod = 'md5' then // methods are case sensitive {do not localize}
  989. begin
  990. Result := TIdOTPCalculator.ToSixWordFormat(TIdOTPCalculator.GenerateKeyMD5(lseed,APassword,LCount))
  991. end
  992. else
  993. begin
  994. if LMethod = 'md4' then {do not localize}
  995. begin
  996. Result := TIdOTPCalculator.ToSixWordFormat(TIdOTPCalculator.GenerateKeyMD4(lseed,APassword,LCount))
  997. end
  998. else
  999. begin
  1000. if LMethod = 'sha1' then {do not localize}
  1001. begin
  1002. Result := TIdOTPCalculator.ToSixWordFormat(TIdOTPCalculator.GenerateKeySHA1(lseed,APassword,LCount))
  1003. end
  1004. else
  1005. begin
  1006. Raise EIdFTPUnknownOTPMethodException.Create(RSFTPOTPMethod);
  1007. end;
  1008. end;
  1009. end;
  1010. end;
  1011. end;
  1012. procedure TIdFTP.InitComponent;
  1013. begin
  1014. inherited;
  1015. //
  1016. FAutoLogin := True;
  1017. FRegularProtPort := IdPORT_FTP;
  1018. FImplicitTLSProtPort := IdPORT_ftps;
  1019. //
  1020. Port := IDPORT_FTP;
  1021. Passive := Id_TIdFTP_Passive;
  1022. FDataPortProtection := Id_TIdFTP_DataPortProtection;
  1023. FUseCCC := DEF_Id_FTP_UseCCC;
  1024. FAUTHCmd := DEF_Id_FTP_AUTH_CMD;
  1025. FDataPort := 0;
  1026. FDataPortMin := 0;
  1027. FDataPortMax := 0;
  1028. FUseExtensionDataPort := DEF_Id_TIdFTP_UseExtendedData;
  1029. FTryNATFastTrack := Id_TIdFTP_UseNATFastTrack;
  1030. FTransferType := Id_TIdFTP_TransferType;
  1031. FTransferTimeout := IdDefTimeout;
  1032. FLoginMsg := TIdReplyFTP.Create(NIL);
  1033. FListResult := TIdStringList.Create;
  1034. FLangsSupported := TIdStringList.Create;
  1035. FCanResume := false;
  1036. FResumeTested := false;
  1037. FProxySettings:= TIdFtpProxySettings.Create; //APR
  1038. FClientInfo := TIdFTPClientIdentifier.Create;
  1039. FTZInfo := TIdFTPTZInfo.Create;
  1040. FTZInfo.FGMTOffsetAvailable := False;
  1041. FUseMLIS := DEF_Id_TIdFTP_UseMIS;
  1042. FUsedMLS := False;
  1043. FCanUseMLS := False; //initialize MLIS flags
  1044. //Settings specified by
  1045. // http://www.ietf.org/internet-drafts/draft-preston-ftpext-deflate-00.txt
  1046. FZLibCompressionLevel := DEF_ZLIB_COMP_LEVEL;
  1047. FZLibWindowBits := DEF_ZLIB_WINDOW_BITS; //-15 - no extra headers
  1048. FZLibMemLevel := DEF_ZLIB_MEM_LEVEL;
  1049. FZLibStratagy := DEF_ZLIB_STRATAGY; // - default
  1050. end;
  1051. procedure TIdFTP.Connect;
  1052. var
  1053. LHost: String;
  1054. LPort: Integer;
  1055. LBuf : String;
  1056. begin
  1057. FCurrentTransferMode := dmStream;
  1058. FTZInfo.FGMTOffsetAvailable := False;
  1059. //FSSCNOn should be set to false to prevent problems.
  1060. FSSCNOn := False;
  1061. FUsingSFTP := False;
  1062. FUsingCCC := False;
  1063. if FUseExtensionDataPort then begin
  1064. FUsingExtDataPort := True;
  1065. end;
  1066. FUsingNATFastTrack := False;
  1067. try
  1068. //APR 011216: proxy support
  1069. LHost := FHost;
  1070. LPort := FPort;
  1071. try
  1072. if (ProxySettings.ProxyType > fpcmNone) and (Length(ProxySettings.Host) > 0) then begin
  1073. FHost := ProxySettings.Host;
  1074. FPort := ProxySettings.Port;
  1075. end;
  1076. if (FUseTLS=utUseImplicitTLS) then
  1077. begin
  1078. //at this point, we treat implicit FTP as if it were explicit FTP with TLS
  1079. FUsingSFTP := True;
  1080. end;
  1081. inherited Connect;
  1082. finally
  1083. FHost := LHost;
  1084. FPort := LPort;
  1085. end;//tryf
  1086. GetResponse([220]);
  1087. FGreeting.Assign(LastCmdResult);
  1088. DoOnBannerBeforeLogin (FGreeting.FormattedReply);
  1089. if AutoLogin then begin
  1090. Login;
  1091. DoAfterLogin;
  1092. //Fast track is set only one time per connection and no more, even
  1093. //with REINIT
  1094. if TryNATFastTrack then begin
  1095. DoTryNATFastTrack;
  1096. end;
  1097. if (FUseTLS=utUseImplicitTLS) then begin
  1098. //at this point, we treat implicit FTP as if it were explicit FTP with TLS
  1099. FUsingSFTP := True;
  1100. end;
  1101. // OpenVMS 7.1 replies with 200 instead of 215 - What does the RFC say about this?
  1102. // if SendCmd('SYST', [200, 215, 500]) = 500 then begin {do not localize}
  1103. //Do not fault if SYST was not understood by the server. Novel Netware FTP
  1104. //may not understand SYST.
  1105. if SendCmd('SYST') = 500 then begin {do not localize}
  1106. FSystemDesc := RSFTPUnknownHost;
  1107. end else begin
  1108. FSystemDesc := LastCmdResult.Text[0];
  1109. end;
  1110. if IsSiteZONESupported then
  1111. begin
  1112. if not FCanUseMLS then
  1113. begin
  1114. if SendCmd('SITE ZONE') = 210 then {do not localize}
  1115. begin
  1116. if LastCmdResult.Text.Count > 0 then
  1117. begin
  1118. LBuf := LastCmdResult.Text[0];
  1119. //remove UTC from reply string "UTC-300"
  1120. IdDelete(LBuf,1,3);
  1121. FTZInfo.GMTOffset := MDTMOffset(LBuf);
  1122. FTZInfo.FGMTOffsetAvailable := True;
  1123. end;
  1124. end;
  1125. end;
  1126. end;
  1127. DoStatus(ftpReady, [RSFTPStatusReady]);
  1128. end;
  1129. except
  1130. Disconnect;
  1131. raise;
  1132. end;
  1133. end;
  1134. procedure TIdFTP.SetTransferType(AValue: TIdFTPTransferType);
  1135. begin
  1136. if AValue <> FTransferType then begin
  1137. if not Assigned(FDataChannel) then begin
  1138. FTransferType := AValue;
  1139. if Connected then begin
  1140. SendTransferType;
  1141. end;
  1142. end
  1143. end;
  1144. end;
  1145. procedure TIdFTP.SendTransferType;
  1146. var
  1147. s: string;
  1148. begin
  1149. case TransferType of
  1150. ftAscii: s := 'A'; {do not localize}
  1151. ftBinary: s := 'I'; {do not localize}
  1152. end;
  1153. SendCmd('TYPE ' + s, 200); {do not localize}
  1154. end;
  1155. function TIdFTP.ResumeSupported: Boolean;
  1156. begin
  1157. if FResumeTested then result := FCanResume
  1158. else begin
  1159. FResumeTested := true;
  1160. FCanResume := Quote('REST 1') = 350; {do not localize}
  1161. result := FCanResume;
  1162. Quote('REST 0'); {do not localize}
  1163. end;
  1164. end;
  1165. procedure TIdFTP.Get(const ASourceFile: string; ADest: TIdStreamVCL; AResume: Boolean = false);
  1166. begin
  1167. //for SSL FXP, we have to do it here because InternalGet is used by the LIST command
  1168. //where SSCN is ignored.
  1169. ClearSSCN;
  1170. AResume := AResume and CanResume;
  1171. DoBeforeGet; //APR
  1172. InternalGet('RETR ' + ASourceFile, ADest, AResume); {do not localize}
  1173. DoAfterGet(ADest.VCLStream ); //APR
  1174. end;
  1175. procedure TIdFTP.Get(const ASourceFile: string; ADest: TStream; AResume: Boolean = false);
  1176. var LStream : TIdStreamVCL;
  1177. begin
  1178. //for SSL FXP, we have to do it here because InternalGet is used by the LIST command
  1179. //where SSCN is ignored.
  1180. ClearSSCN;
  1181. AResume := AResume and CanResume;
  1182. LStream := TIdStreamVCL.Create(ADest);
  1183. try
  1184. Get(ASourceFile,LStream,AResume);
  1185. finally
  1186. FreeAndNil(LStream);
  1187. end;
  1188. end;
  1189. procedure TIdFTP.Get(const ASourceFile, ADestFile: string; const ACanOverwrite: boolean = false;
  1190. AResume: Boolean = false);
  1191. var
  1192. LDestStream: TFileStream;
  1193. begin
  1194. if FileExists(ADestFile) then begin
  1195. AResume := AResume and CanResume;
  1196. if ACanOverwrite and (not AResume) then begin
  1197. DeleteFile(ADestFile);
  1198. LDestStream := TFileStream.Create(ADestFile, fmCreate);
  1199. end
  1200. else begin
  1201. if (not ACanOverwrite) and AResume then begin
  1202. LDestStream := TFileStream.Create(ADestFile, fmOpenReadWrite or fmShareDenyWrite);
  1203. LDestStream.Position := LDestStream.Size;
  1204. end
  1205. else begin
  1206. raise EIdFTPFileAlreadyExists.Create(RSDestinationFileAlreadyExists);
  1207. end;
  1208. end;
  1209. end
  1210. else begin
  1211. LDestStream := TFileStream.Create(ADestFile, fmCreate);
  1212. end;
  1213. try
  1214. Get(ASourceFile, LDestStream, AResume);
  1215. finally
  1216. FreeAndNil(LDestStream);
  1217. end;
  1218. end;
  1219. procedure TIdFTP.DoBeforeGet;
  1220. begin
  1221. if Assigned(FOnBeforeGet) then
  1222. begin
  1223. FOnBeforeGet(Self);
  1224. end;
  1225. end;
  1226. procedure TIdFTP.DoBeforePut (AStream: TStream);
  1227. begin
  1228. if Assigned(FOnBeforePut) then
  1229. begin
  1230. FOnBeforePut(SELF,AStream);
  1231. end;
  1232. end;
  1233. procedure TIdFTP.DoAfterGet (AStream: TStream);//APR
  1234. Begin
  1235. if Assigned(FOnAfterGet) then
  1236. begin
  1237. FOnAfterGet(SELF,AStream);
  1238. end;
  1239. End;//TIdFTP.AtAfterFileGet
  1240. procedure TIdFTP.DoAfterPut;
  1241. begin
  1242. if Assigned(FOnAfterPut) then
  1243. begin
  1244. FOnAfterPut(Self);
  1245. end;
  1246. end;
  1247. procedure TIdFTP.ConstructDirListing;
  1248. begin
  1249. if not Assigned(FDirectoryListing) then begin
  1250. if not (csDesigning in ComponentState) then begin
  1251. DoFTPList;
  1252. end;
  1253. if not Assigned(FDirectoryListing) then begin
  1254. FDirectoryListing := TIdFTPListItems.Create;
  1255. end;
  1256. end else begin
  1257. FDirectoryListing.Clear;
  1258. end;
  1259. end;
  1260. procedure TIdFTP.List(
  1261. ADest: TIdStrings;
  1262. const ASpecifier: string = ''; {do not localize}
  1263. ADetails: Boolean = True);
  1264. var
  1265. LDest: TIdStringStream;
  1266. LTrans : TIdFTPTransferType;
  1267. LStream : TIdStreamVCL;
  1268. begin
  1269. if FCanUseMLS then begin
  1270. ExtListDir(ADest);
  1271. Exit;
  1272. end;
  1273. //Note that for LIST, it might be best to put the connection in ASCII
  1274. //mode because some old servers such as TOPS20 might require this. We restore it
  1275. //if the original mode was not ASCII. It's a good idea to do this anyway
  1276. //because some clients still do this such as WS_FTP Pro and Microsoft's FTP Client.
  1277. LTrans := Self.TransferType;
  1278. if LTrans <> ftASCII then begin
  1279. Self.TransferType := ftASCII;
  1280. end;
  1281. try
  1282. LDest := TIdStringStream.Create(''); try
  1283. LStream := TIdStreamVCL.Create(LDest); try
  1284. InternalGet(Trim(iif(ADetails, 'LIST', 'NLST') + ' ' + ASpecifier), LStream); {do not localize}
  1285. finally FreeAndNil(LStream); end;
  1286. FreeAndNil(FDirectoryListing);
  1287. FListResult.Text := LDest.DataString;
  1288. if ADest <> nil then begin
  1289. ADest.Assign(FListResult);
  1290. end;
  1291. FUsedMLS := False;
  1292. finally FreeAndNil(LDest); end;
  1293. DoOnRetrievedDir;
  1294. finally
  1295. if LTrans <> ftASCII then begin
  1296. Self.TransferType := LTrans;
  1297. end;
  1298. end;
  1299. end;
  1300. procedure TIdFTP.InternalGet(const ACommand: string; ADest: TIdStreamVCL; AResume: Boolean = false);
  1301. var
  1302. LIP: string;
  1303. LPort: Integer;
  1304. LResponse: Integer;
  1305. LPasvCl : TIdTCPClient;
  1306. LPortSv : TIdSimpleServer;
  1307. { procedure ReadCompressedData(ACompressor : TIdZLibCompressorBase; ADest : TIdStreamVCL; AIO : TIdIOHandler;
  1308. const AZLibWindowBits : Integer);
  1309. var LM : TStream;
  1310. LS : TIdStreamVCL;
  1311. begin
  1312. LM := TMemoryStream.Create;
  1313. LS := TIdStreamVCL.Create(LM);
  1314. try
  1315. AIO.ReadStream(LS, -1, True);
  1316. LS.Position := 0;
  1317. if LS.Size<>0 then
  1318. begin
  1319. ACompressor.DecompressFTPDeflate(LM, AZLibWindowBits, ADest.VCLStream);
  1320. end;
  1321. finally
  1322. FreeAndNil(LS);
  1323. FreeAndNil(LM);
  1324. end;
  1325. end; }
  1326. begin
  1327. DoStatus(ftpTransfer, [RSFTPStatusStartTransfer]);
  1328. try
  1329. if FPassive then begin
  1330. SendPret(ACommand);
  1331. //PASV or EPSV
  1332. if FUsingExtDataPort then begin
  1333. SendEPassive(LIP, LPort);
  1334. end else begin
  1335. SendPassive(LIP, LPort);
  1336. end;
  1337. FDataChannel := TIdTCPClient.Create(nil);
  1338. LPasvCl := FDataChannel as TIdTCPClient;
  1339. try
  1340. InitDataChannel;
  1341. LPasvCl.Host := LIP;
  1342. LPasvCl.Port := LPort;
  1343. if Assigned(FOnDataChannelCreate) then begin
  1344. OnDataChannelCreate(Self, FDataChannel);
  1345. end;
  1346. LPasvCl.Connect;
  1347. try
  1348. if AResume then begin
  1349. Self.SendCmd('REST ' + IntToStr(ADest.VCLStream.Position), [350]); {do not localize}
  1350. end;
  1351. Self.IOHandler.WriteLn(ACommand);
  1352. Self.GetResponse([125, 150, 154]); //APR: Ericsson Switch FTP
  1353. if (FDataPortProtection = ftpdpsPrivate) then begin
  1354. TIdSSLIOHandlerSocketBase(FDataChannel.IOHandler).Passthrough := False;
  1355. end;
  1356. if FCurrentTransferMode = dmStream then begin
  1357. LPasvCl.IOHandler.ReadStream(ADest, -1, True);
  1358. end else begin
  1359. FCompressor.DecompressFTPFromIO( LPasvCl.IOHandler, FZLibWindowBits, ADest.VCLStream);
  1360. // ReadCompressedData(FCompressor, ADest, LPasvCl.IOHandler, FZLibWindowBits);
  1361. end;
  1362. finally
  1363. LPasvCl.Disconnect;
  1364. end;
  1365. finally
  1366. if Assigned(FOnDataChannelDestroy) then begin
  1367. OnDataChannelDestroy(Self, FDataChannel);
  1368. end;
  1369. FDataChannel.IOHandler.Free;
  1370. FreeAndNil(FDataChannel);
  1371. end;
  1372. end
  1373. else
  1374. begin
  1375. // PORT or EPRT
  1376. FDataChannel := TIdSimpleServer.Create(nil);
  1377. LPortSv := FDataChannel as TIdSimpleServer;
  1378. try
  1379. InitDataChannel;
  1380. LPortSv.BoundIP := (Self.IOHandler as TIdIOHandlerSocket).Binding.IP;
  1381. LPortSv.BoundPort := FDataPort;
  1382. LPortSv.BoundPortMin := FDataPortMin;
  1383. LPortSv.BoundPortMax := FDataPortMax;
  1384. if Assigned(FOnDataChannelCreate) then begin
  1385. OnDataChannelCreate(Self, FDataChannel);
  1386. end;
  1387. LPortSv.BeginListen;
  1388. if FUsingExtDataPort then begin
  1389. SendEPort(LPortSv.Binding);
  1390. end else begin
  1391. SendPort(LPortSv.Binding);
  1392. end;
  1393. if AResume then begin
  1394. SendCmd('REST ' + IntToStr(ADest.VCLStream.Position), [350]); {do not localize}
  1395. end;
  1396. SendCmd(ACommand, [125, 150, 154]); //APR: Ericsson Switch FTP);
  1397. LPortSv.Listen;
  1398. if FUsingSFTP and (FDataPortProtection = ftpdpsPrivate) then begin
  1399. TIdSSLIOHandlerSocketBase(FDataChannel.IOHandler).PassThrough := False;
  1400. end;
  1401. if FCurrentTransferMode = dmStream then begin
  1402. FDataChannel.IOHandler.ReadStream(ADest, -1, True);
  1403. end else begin
  1404. FCompressor.DecompressFTPFromIO( FDataChannel.IOHandler, FZLibWindowBits, ADest.VCLStream);
  1405. // ReadCompressedData(FCompressor, ADest, FDataChannel.IOHandler, FZLibWindowBits);
  1406. end;
  1407. finally
  1408. if Assigned(FOnDataChannelDestroy) then begin
  1409. OnDataChannelDestroy(Self, FDataChannel);
  1410. end;
  1411. FDataChannel.IOHandler.Free;
  1412. FDataChannel.IOHandler := nil;
  1413. FreeAndNil(FDataChannel);
  1414. end;
  1415. end;
  1416. finally
  1417. DoStatus(ftpReady, [RSFTPStatusDoneTransfer]);
  1418. end;
  1419. // ToDo: Change that to properly handle response code (not just success or except)
  1420. // 226 = download successful, 225 = Abort successful}
  1421. LResponse := GetResponse([225, 226, 250, 426, 450]);
  1422. if (LResponse = 426) or (LResponse = 450) then begin
  1423. GetResponse([226, 225]);
  1424. DoStatus(ftpAborted, [RSFTPStatusAbortTransfer]);
  1425. end;
  1426. end;
  1427. procedure TIdFTP.Quit;
  1428. begin
  1429. if Connected then begin
  1430. IOHandler.WriteLn('QUIT'); {do not localize}
  1431. end;
  1432. Disconnect;
  1433. end;
  1434. procedure TIdFTP.KillDataChannel;
  1435. begin
  1436. // Had kill the data channel ()
  1437. if Assigned(FDataChannel) then begin
  1438. FDataChannel.Disconnect;//FDataChannel.IOHandler.DisconnectSocket; {//BGO}
  1439. end;
  1440. end;
  1441. procedure TIdFTP.Abort;
  1442. begin
  1443. // only send the abort command. The Data channel is supposed to disconnect
  1444. if Connected then begin
  1445. IOHandler.WriteLn('ABOR'); {do not localize}
  1446. end;
  1447. // Kill the data channel: usually, the server doesn't close it by itself
  1448. KillDataChannel;
  1449. end;
  1450. procedure TIdFTP.SendPort(AHandle: TIdSocketHandle);
  1451. begin
  1452. if FExternalIP <> '' then
  1453. begin
  1454. SendPort(FExternalIP,AHandle.Port);
  1455. end
  1456. else
  1457. begin
  1458. SendPort(AHandle.IP, AHandle.Port);
  1459. end;
  1460. end;
  1461. procedure TIdFTP.SendPort(const AIP: String; const APort: Integer);
  1462. begin
  1463. SendDataSettings;
  1464. SendCmd('PORT ' + StringReplace(AIP, '.', ',', [rfReplaceAll]) {do not localize}
  1465. + ',' + IntToStr(APort div 256) + ',' + IntToStr(APort mod 256), [200]); {do not localize}
  1466. end;
  1467. procedure TIdFTP.InternalPut(const ACommand: string; ASource: TIdStreamVCL; AFromBeginning: Boolean = true);
  1468. var
  1469. LIP: string;
  1470. LPort: Integer;
  1471. LResponse: Integer;
  1472. LPasvCl : TIdTCPClient;
  1473. LPortSv : TIdSimpleServer;
  1474. LIO : TIdIOHandler;
  1475. begin
  1476. //for SSL FXP, we have to do it here because there is no command were a client
  1477. //submits data through a data port where the SSCN setting is ignored.
  1478. ClearSSCN;
  1479. DoStatus(ftpTransfer, [RSFTPStatusStartTransfer]);
  1480. try
  1481. if FPassive then begin
  1482. SendPret(ACommand);
  1483. if FUsingExtDataPort then begin
  1484. SendEPassive(LIP, LPort);
  1485. end else begin
  1486. SendPassive(LIP, LPort);
  1487. end;
  1488. IOHandler.WriteLn(ACommand);
  1489. FDataChannel := TIdTCPClient.Create(nil);
  1490. LPasvCl := FDataChannel as TIdTCPClient;
  1491. try
  1492. InitDataChannel;
  1493. LPasvCl.Host := LIP;
  1494. LPasvCl.Port := LPort;
  1495. if Assigned(FOnDataChannelCreate) then begin
  1496. OnDataChannelCreate(self,FDataChannel);
  1497. end;
  1498. LPasvCl.Connect;
  1499. try
  1500. Self.GetResponse([110, 125, 150]);
  1501. try
  1502. if FUsingSFTP and (FDataPortProtection = ftpdpsPrivate) then begin
  1503. TIdSSLIOHandlerSocketBase(FDataChannel.IOHandler).Passthrough := False;
  1504. end;
  1505. if FCurrentTransferMode<>dmDeflate then begin
  1506. if AFromBeginning then begin
  1507. FDataChannel.IOHandler.Write(ASource,0, false); // from beginning
  1508. end else begin
  1509. FDataChannel.IOHandler.Write(ASource,-1, false); // from current position
  1510. end;
  1511. end else begin
  1512. FCompressor.CompressFTPToIO(ASource.VCLStream,FDataChannel.IOHandler,FZLibCompressionLevel,FZLibWindowBits,FZLibMemLevel, FZLibStratagy);
  1513. end;
  1514. except
  1515. on E: EIdSocketError do
  1516. begin
  1517. // If 10038 - abort was called. Server will return 225
  1518. if E.LastError <> 10038 then begin
  1519. raise;
  1520. end;
  1521. end;
  1522. end;
  1523. finally
  1524. LPasvCl.Disconnect;
  1525. end;
  1526. finally
  1527. if Assigned(FOnDataChannelDestroy) then begin
  1528. OnDataChannelDestroy(self,FDataChannel);
  1529. end;
  1530. LIO := FDataChannel.IOHandler;
  1531. FDataChannel.IOHandler := nil;
  1532. FreeAndNil(LIO);
  1533. FreeAndNil(FDataChannel);
  1534. end;
  1535. end else begin
  1536. FDataChannel := TIdSimpleServer.Create(nil);
  1537. LPortSv := FDataChannel as TIdSimpleServer;
  1538. try
  1539. InitDataChannel;
  1540. LPortSv.BoundIP := (Self.IOHandler as TIdIOHandlerSocket).Binding.IP;
  1541. LPortSv.BoundPort := FDataPort;
  1542. LPortSv.BoundPortMin := FDataPortMin;
  1543. LPortSv.BoundPortMax := FDataPortMax;
  1544. if Assigned(FOnDataChannelCreate) then begin
  1545. OnDataChannelCreate(Self, FDataChannel);
  1546. end;
  1547. LPortSv.BeginListen;
  1548. if FUsingExtDataPort then begin
  1549. SendEPort(LPortSv.Binding);
  1550. end else begin
  1551. SendPort(LPortSv.Binding);
  1552. end;
  1553. Self.SendCmd(ACommand, [125, 150]);
  1554. LPortSv.Listen;
  1555. if FUsingSFTP and (FDataPortProtection = ftpdpsPrivate) then begin
  1556. TIdSSLIOHandlerSocketBase(FDataChannel.IOHandler).PassThrough := False;
  1557. end;
  1558. if FCurrentTransferMode<>dmDeflate then begin
  1559. if AFromBeginning then begin
  1560. FDataChannel.IOHandler.Write(ASource,0, false); // from beginning
  1561. end else begin
  1562. FDataChannel.IOHandler.Write(ASource,-1, false); // from current position
  1563. end;
  1564. end else begin
  1565. FCompressor.CompressFTPToIO(ASource.VCLStream,FDataChannel.IOHandler,FZLibCompressionLevel,FZLibWindowBits,FZLibMemLevel, FZLibStratagy);
  1566. end;
  1567. finally
  1568. if Assigned(FOnDataChannelDestroy) then begin
  1569. OnDataChannelDestroy(Self, FDataChannel);
  1570. end;
  1571. FDataChannel.IOHandler.Free;
  1572. FDataChannel.IOHandler := nil;
  1573. FreeAndNil(FDataChannel);
  1574. end;
  1575. end;
  1576. finally
  1577. DoStatus(ftpReady, [RSFTPStatusDoneTransfer]);
  1578. end;
  1579. // 226 = download successful, 225 = Abort successful}
  1580. LResponse := GetResponse([225, 226, 250, 426, 450]);
  1581. if (LResponse = 426) or (LResponse = 450) then
  1582. begin
  1583. // some servers respond with 226 on ABOR
  1584. GetResponse([226, 225]);
  1585. DoStatus(ftpAborted, [RSFTPStatusAbortTransfer]);
  1586. end;
  1587. end;
  1588. procedure TIdFTP.InitDataChannel;
  1589. var LSSL : TIdSSLIOHandlerSocketBase;
  1590. begin
  1591. if (FDataPortProtection = ftpdpsPrivate) then
  1592. begin
  1593. LSSL := TIdSSLIOHandlerSocketBase(Self.IOHandler);
  1594. FDataChannel.IOHandler := LSSL.Clone;
  1595. //we have to delay the actual negotiation until we get the reply and
  1596. //and just before the readString
  1597. TIdSSLIOHandlerSocketBase(FDataChannel.IOHandler).Passthrough := True;
  1598. end else begin
  1599. FDataChannel.IOHandler := TIdIOHandler.MakeDefaultIOHandler(Self);
  1600. end;
  1601. if FDataChannel is TIdTCPClient then
  1602. begin
  1603. //Now SocksInfo are multi-thread safe
  1604. FDataChannel.IOHandler.ConnectTimeout := Self.IOHandler.ConnectTimeout;
  1605. end;
  1606. if (FDataChannel.IOHandler is TIdIOHandlerSocket) and (Self.IOHandler is TIdIOHandlerSocket) then
  1607. begin
  1608. TIdIOHandlerSocket(FDataChannel.IOHandler).TransparentProxy := TIdIOHandlerSocket(Self.IOHandler).TransparentProxy;
  1609. TIdIOHandlerSocket(FDataChannel.IOHandler).IPVersion := TIdIOHandlerSocket(Self.IOHandler).IPVersion;
  1610. end;
  1611. FDataChannel.IOHandler.ReadTimeout := FTransferTimeout;
  1612. FDataChannel.IOHandler.SendBufferSize := IOHandler.SendBufferSize;
  1613. FDataChannel.IOHandler.RecvBufferSize := IOHandler.RecvBufferSize;
  1614. FDataChannel.OnWork := OnWork;
  1615. FDataChannel.OnWorkBegin := OnWorkBegin;
  1616. FDataChannel.OnWorkEnd := OnWorkEnd;
  1617. end;
  1618. procedure TIdFTP.Put(const ASource: TIdStreamVCL; const ADestFile: string;
  1619. const AAppend: boolean = false);
  1620. begin
  1621. if ADestFile = '' then
  1622. begin
  1623. raise EIdFTPUploadFileNameCanNotBeEmpty.Create(RSFTPFileNameCanNotBeEmpty);
  1624. end
  1625. else
  1626. begin
  1627. DoBeforePut(ASource.VCLStream ); //APR);
  1628. if AAppend then
  1629. begin
  1630. InternalPut('APPE ' + ADestFile, ASource, false); {Do not localize}
  1631. end
  1632. else
  1633. begin
  1634. InternalPut('STOR ' + ADestFile, ASource); {Do not localize}
  1635. end;
  1636. DoAfterPut;
  1637. end;
  1638. end;
  1639. procedure TIdFTP.Put(const ASource: TStream; const ADestFile: string;
  1640. const AAppend: boolean = false);
  1641. var LStream : TIdStreamVCL;
  1642. begin
  1643. LStream := TIdStreamVCL.Create(ASource);
  1644. try
  1645. Put(LStream,ADestFile,AAppend);
  1646. finally
  1647. FreeAndNil(LStream);
  1648. end;
  1649. end;
  1650. procedure TIdFTP.Put(const ASourceFile: string; const ADestFile: string='';
  1651. const AAppend: boolean = false);
  1652. var
  1653. LSourceStream: TFileStream;
  1654. LDestFileName : String;
  1655. begin
  1656. LDestFileName := ADestFile;
  1657. if LDestFileName = '' then
  1658. begin
  1659. LDestFileName := ExtractFileName(ASourceFile);
  1660. end;
  1661. LSourceStream := TFileStream.Create(ASourceFile, fmOpenRead or fmShareDenyNone); try
  1662. Put(LSourceStream, LDestFileName, AAppend);
  1663. finally FreeAndNil(LSourceStream); end;
  1664. end;
  1665. procedure TIdFTP.StoreUnique(const ASource: TIdStreamVCL);
  1666. begin
  1667. InternalPut('STOU', ASource); {Do not localize}
  1668. end;
  1669. procedure TIdFTP.StoreUnique(const ASource: TStream);
  1670. var LStream : TIdStreamVCL;
  1671. begin
  1672. LStream := TIdStreamVCL.Create(ASource);
  1673. try
  1674. StoreUnique(LStream);
  1675. finally
  1676. FreeAndNil(LStream);
  1677. end;
  1678. end;
  1679. procedure TIdFTP.StoreUnique(const ASourceFile: string);
  1680. var
  1681. LSourceStream: TFileStream;
  1682. begin
  1683. LSourceStream := TFileStream.Create(ASourceFile, fmOpenRead or fmShareDenyNone); try
  1684. StoreUnique(LSourceStream);
  1685. finally FreeAndNil(LSourceStream); end;
  1686. end;
  1687. procedure TIdFTP.SendInternalPassive(const ACmd: String; var VIP: string;
  1688. var VPort: integer);
  1689. var
  1690. i,bLeft,bRight: integer;
  1691. s: string;
  1692. begin
  1693. SendDataSettings;
  1694. SendCmd(ACmd, 227); {do not localize}
  1695. s := Trim(LastCmdResult.Text[0]);
  1696. // Case 1 (Normal)
  1697. // 227 Entering passive mode(100,1,1,1,23,45)
  1698. bLeft := IndyPos('(', s); {do not localize}
  1699. bRight := IndyPos(')', s); {do not localize}
  1700. if (bLeft = 0) or (bRight = 0) then begin
  1701. // Case 2
  1702. // 227 Entering passive mode on 100,1,1,1,23,45
  1703. bLeft := RPos(#32, s);
  1704. s := Copy(s, bLeft + 1, Length(s) - bLeft);
  1705. end else begin
  1706. s := Copy(s, bLeft + 1, bRight - bLeft - 1);
  1707. end;
  1708. VIP := ''; {do not localize}
  1709. for i := 1 to 4 do begin
  1710. VIP := VIP + '.' + Fetch(s, ','); {do not localize}
  1711. end;
  1712. IdDelete(VIP, 1, 1);
  1713. // Determine port
  1714. VPort := StrToInt(Fetch(s, ',')) shl 8; {do not localize}
  1715. //use trim as one server sends something like this:
  1716. //"227 Passive mode OK (195,92,195,164,4,99 )"
  1717. VPort := VPort + StrToInt(Trim(Fetch(s, ','))); {Do not translate}
  1718. end;
  1719. procedure TIdFTP.SendPassive(var VIP: string; var VPort: integer);
  1720. begin
  1721. SendInternalPassive('PASV', VIP, VPort); {do not localize}
  1722. end;
  1723. procedure TIdFTP.SendCPassive(var VIP: string; var VPort: integer);
  1724. begin
  1725. SendInternalPassive('CPSV', VIP, VPort); {do not localize}
  1726. end;
  1727. procedure TIdFTP.Noop;
  1728. begin
  1729. SendCmd('NOOP', 200); {do not localize}
  1730. end;
  1731. procedure TIdFTP.MakeDir(const ADirName: string);
  1732. begin
  1733. SendCmd('MKD ' + ADirName, 257); {do not localize}
  1734. end;
  1735. function TIdFTP.RetrieveCurrentDir: string;
  1736. begin
  1737. SendCmd('PWD', 257); {do not localize}
  1738. Result := CleanDirName(LastCmdResult.Text[0]);
  1739. end;
  1740. procedure TIdFTP.RemoveDir(const ADirName: string);
  1741. begin
  1742. SendCmd('RMD ' + ADirName, 250); {do not localize}
  1743. end;
  1744. procedure TIdFTP.Delete(const AFilename: string);
  1745. begin
  1746. SendCmd('DELE ' + AFilename, 250); {do not localize}
  1747. end;
  1748. (*
  1749. CHANGE WORKING DIRECTORY (CWD)
  1750. This command allows the user to work with a different
  1751. directory or dataset for file storage or retrieval without
  1752. altering his login or accounting information. Transfer
  1753. parameters are similarly unchanged. The argument is a
  1754. pathname specifying a directory or other system dependent
  1755. file group designator.
  1756. CWD
  1757. 250
  1758. 500, 501, 502, 421, 530, 550
  1759. *)
  1760. procedure TIdFTP.ChangeDir(const ADirName: string);
  1761. begin
  1762. SendCmd('CWD ' + ADirName, [200, 250]); //APR: Ericsson Switch FTP {do not localize}
  1763. end;
  1764. (*
  1765. CHANGE TO PARENT DIRECTORY (CDUP)
  1766. This command is a special case of CWD, and is included to
  1767. simplify the implementation of programs for transferring
  1768. directory trees between operating systems having different
  1769. syntaxes for naming the parent directory. The reply codes
  1770. shall be identical to the reply codes of CWD. See
  1771. Appendix II for further details.
  1772. CDUP
  1773. 200
  1774. 500, 501, 502, 421, 530, 550
  1775. *)
  1776. procedure TIdFTP.ChangeDirUp;
  1777. begin
  1778. // RFC lists 200 as the proper response, but in another section says that it can return the
  1779. // same as CWD, which expects 250. That is it contradicts itself.
  1780. // MS in their infinite wisdom chnaged IIS 5 FTP to return 250.
  1781. SendCmd('CDUP', [200, 250]); {do not localize}
  1782. end;
  1783. procedure TIdFTP.Site(const ACommand: string);
  1784. begin
  1785. SendCmd('SITE ' + ACommand, 200); {do not localize}
  1786. end;
  1787. procedure TIdFTP.Rename(const ASourceFile, ADestFile: string);
  1788. begin
  1789. SendCmd('RNFR ' + ASourceFile, 350); {do not localize}
  1790. SendCmd('RNTO ' + ADestFile, 250); {do not localize}
  1791. end;
  1792. function TIdFTP.Size(const AFileName: String): Integer;
  1793. var
  1794. SizeStr: String;
  1795. begin
  1796. result := -1;
  1797. if SendCmd('SIZE ' + AFileName) = 213 then begin {do not localize}
  1798. SizeStr := Trim(LastCmdResult.Text.Text);
  1799. IdDelete(SizeStr, 1, IndyPos(' ', SizeStr)); // delete the response {do not localize}
  1800. result := StrToIntDef(SizeStr, -1);
  1801. end;
  1802. end;
  1803. //Added by SP
  1804. procedure TIdFTP.ReInitialize(ADelay: Cardinal = 10);
  1805. begin
  1806. Sleep(ADelay); //Added
  1807. if SendCmd('REIN', [120, 220, 500]) <> 500 then begin {do not localize}
  1808. FLoginMsg.Clear;
  1809. FCanResume := False;
  1810. if Assigned(FDirectoryListing) then
  1811. begin
  1812. FDirectoryListing.Clear;
  1813. end;
  1814. FUsername := ''; {do not localize}
  1815. FPassword := ''; {do not localize}
  1816. FPassive := Id_TIdFTP_Passive;
  1817. FCanResume := False;
  1818. FResumeTested := False;
  1819. FSystemDesc := '';
  1820. FTransferType := Id_TIdFTP_TransferType;
  1821. if FUsingSFTP then
  1822. begin
  1823. if FUseTLS <> utUseImplicitTLS then
  1824. begin
  1825. (IOHandler as TIdSSLIOHandlerSocketBase).PassThrough := true;
  1826. FUsingSFTP := False;
  1827. FUseCCC := False;
  1828. end;
  1829. end;
  1830. end;
  1831. end;
  1832. procedure TIdFTP.Allocate(AAllocateBytes: Integer);
  1833. begin
  1834. SendCmd('ALLO ' + IntToStr(AAllocateBytes), [200]); {do not localize}
  1835. end;
  1836. procedure TIdFTP.Status(AStatusList: TIdStrings);
  1837. begin
  1838. if SendCmd('STAT', [211, 212, 213, 500]) <> 500 then {do not localize}
  1839. begin
  1840. AStatusList.Text := LastCmdResult.Text.Text;
  1841. end;
  1842. end;
  1843. procedure TIdFTP.Help(var AHelpContents: TIdStringList; ACommand: String = ''); {do not localize}
  1844. var
  1845. LStrm: TIdStringStream;
  1846. LStream : TIdStreamVCL;
  1847. begin
  1848. LStrm := TIdStringStream.Create(''); {do not localize}
  1849. if SendCmd('HELP ' + ACommand, [211, 214, 500]) <> 500 then {do not localize}
  1850. begin
  1851. LStream := TIdStreamVCL.Create(LStrm);
  1852. try
  1853. IOHandler.ReadStream(LStream, -1, True);
  1854. finally
  1855. FreeAndNil(LStream);
  1856. end;
  1857. AHelpContents.Text := LStrm.DataString;
  1858. end;
  1859. FreeAndNil(LStrm);
  1860. end;
  1861. procedure TIdFTP.Account(AInfo: String);
  1862. begin
  1863. SendCmd('ACCT ' + AInfo, [202, 230, 500]); {do not localize}
  1864. end;
  1865. procedure TIdFTP.StructureMount(APath: String);
  1866. begin
  1867. SendCmd('SMNT ' + APath, [202, 250, 500]); {do not localize}
  1868. end;
  1869. procedure TIdFTP.FileStructure(AStructure: TIdFTPDataStructure);
  1870. var
  1871. s: String;
  1872. begin
  1873. case AStructure of
  1874. dsFile: s := 'F'; {do not localize}
  1875. dsRecord: s := 'R'; {do not localize}
  1876. dsPage: s := 'P'; {do not localize}
  1877. end;
  1878. SendCmd('STRU ' + s, [200, 500]); {do not localize}
  1879. { TODO: Needs to be finished }
  1880. end;
  1881. procedure TIdFTP.TransferMode(ATransferMode: TIdFTPTransferMode);
  1882. var
  1883. s: String;
  1884. i : Integer;
  1885. LBuf : String;
  1886. begin
  1887. if (ATransferMode = dmStream) or (ATransferMode = dmDeflate) then
  1888. begin
  1889. case ATransferMode of
  1890. // dmBlock: begin
  1891. // s := 'B'; {do not localize}
  1892. // end;
  1893. // dmCompressed: begin
  1894. // s := 'C'; {do not localize}
  1895. // end;
  1896. dmStream: begin
  1897. s := 'S'; {do not localize}
  1898. end;
  1899. dmDeflate: begin
  1900. if Assigned(FCompressor) then
  1901. begin
  1902. //we parse this way because IxExtensionSupported can only work
  1903. //with one word.
  1904. for i := 0 to FCapabilities.Count-1 do
  1905. begin
  1906. LBuf := Trim(FCapabilities[i]);
  1907. if LBuf = 'MODE Z' then {do not localize}
  1908. begin
  1909. s := 'Z'; {do not localize}
  1910. break;
  1911. end;
  1912. end;
  1913. if s <> 'Z' then
  1914. begin
  1915. Exit;
  1916. end;
  1917. end
  1918. else
  1919. begin
  1920. Exit;
  1921. end;
  1922. end;
  1923. end;
  1924. if SendCmd('MODE ' + s)=200 then {do not localize}
  1925. begin
  1926. FCurrentTransferMode := ATransferMode;
  1927. end;
  1928. end;
  1929. end;
  1930. destructor TIdFTP.Destroy;
  1931. begin
  1932. FreeAndNil(FClientInfo);
  1933. FreeAndNil(FListResult);
  1934. FreeAndNil(FLoginMsg);
  1935. FreeAndNil(FDirectoryListing);
  1936. FreeAndNil(FLangsSupported);
  1937. FreeAndNIL(FProxySettings); //APR
  1938. FreeAndNil(FTZInfo);
  1939. inherited Destroy;
  1940. end;
  1941. function TIdFTP.Quote(const ACommand: String): SmallInt;
  1942. begin
  1943. result := SendCmd(ACommand);
  1944. end;
  1945. //APR 011216: ftp proxy support
  1946. // TODO: need help - "//?"
  1947. procedure TIdFTP.Login;
  1948. var i : Integer;
  1949. LResp : Word;
  1950. function FtpHost: String;
  1951. Begin
  1952. if FPort = IDPORT_FTP then begin
  1953. Result := FHost;
  1954. end else begin
  1955. Result := FHost + Id_TIdFTP_HostPortDelimiter + IntToStr(FPort);
  1956. end;
  1957. End;//
  1958. begin
  1959. //TLS part
  1960. FUsingSFTP := False;
  1961. if UseTLS in ExplicitTLSVals then begin
  1962. if Self.FAUTHCmd = tAuto then
  1963. begin
  1964. {Note that we can not call SupportsTLS at all. That depends upon the FEAT response
  1965. and unfortunately, some servers such as WS_FTP Server 4.0.0 (78162662)
  1966. will not accept a FEAT command until you login. In other words, you have to do
  1967. this by trial and error.
  1968. }
  1969. //334 has to be accepted because of a broekn implementation
  1970. //see: http://www.ford-hutchinson.com/~fh-1-pfh/ftps-ext.html#bad
  1971. {Note that we have to try several commands because some servers use AUTH TLS while others use
  1972. AUTH SSL. GlobalScape's FTP Server only uses AUTH SSL while IpSwitch's uses AUTH TLS (the correct behavior).
  1973. We try two other commands for historical reasons.
  1974. }
  1975. for i := 0 to 3 do
  1976. begin
  1977. LResp := SendCmd('AUTH ' + TLS_AUTH_NAMES[i]); {do not localize}
  1978. if (LResp = 234) or (LResp = 334) then begin
  1979. //okay. do the handshake
  1980. TLSHandshake;
  1981. FUsingSFTP := True;
  1982. //we are done with the negotiation, let's close this.
  1983. break;
  1984. end
  1985. else
  1986. begin
  1987. //see if the error was not any type of syntax error code
  1988. //if it wasn't, we fail the command.
  1989. if ((LResp div 500)<>1) then
  1990. begin
  1991. ProcessTLSNegCmdFailed;
  1992. Break;
  1993. end;
  1994. end;
  1995. end;
  1996. end
  1997. else
  1998. begin
  1999. LResp := SendCmd('AUTH ' + TLS_AUTH_NAMES[ Ord(Self.FAUTHCmd)-1 ]); {do not localize}
  2000. if (LResp = 234) or (LResp = 334) then begin
  2001. //okay. do the handshake
  2002. TLSHandshake;
  2003. FUsingSFTP := True;
  2004. end
  2005. else
  2006. begin
  2007. ProcessTLSNegCmdFailed;
  2008. end;
  2009. end;
  2010. end;
  2011. if FUsingSFTP = False then
  2012. begin
  2013. ProcessTLSNotAvail;
  2014. end;
  2015. //login
  2016. case ProxySettings.ProxyType of
  2017. fpcmNone:
  2018. begin
  2019. if SendCmd('USER ' + FUserName, [230, 232, 331]) = 331 then begin {do not localize}
  2020. SendCmd('PASS ' +GetLoginPassword, 230); {do not localize}
  2021. end;
  2022. end;//fpcmNone
  2023. fpcmUserSite:
  2024. begin
  2025. if (Length(ProxySettings.UserName)>0) then begin
  2026. if SendCmd('USER ' + ProxySettings.UserName, [230, 331]) = 331 then begin {do not localize}
  2027. SendCmd('PASS ' + ProxySettings.Password, 230); {do not localize}
  2028. end;
  2029. end;//proxy login
  2030. if SendCmd('USER ' + FUserName+'@'+FtpHost, [230, 232, 331]) = 331 then begin {do not localize}
  2031. SendCmd('PASS ' +GetLoginPassword, 230); {do not localize}
  2032. end;
  2033. end;//fpcmUserSite
  2034. fpcmSite:
  2035. begin
  2036. if (Length(ProxySettings.UserName)>0) then begin
  2037. if SendCmd('USER ' + ProxySettings.UserName, [230, 331]) = 331 then begin {do not localize}
  2038. SendCmd('PASS ' + ProxySettings.Password, 230); {do not localize}
  2039. end;
  2040. end;//proxy login
  2041. SendCmd('SITE '+FtpHost); // ? Server Reply? 220? {do not localize}
  2042. if SendCmd('USER ' + FUserName, [230, 232, 331]) = 331 then begin {do not localize}
  2043. SendCmd('PASS ' +GetLoginPassword, 230); {do not localize}
  2044. end;
  2045. end;//fpcmSite
  2046. fpcmOpen:
  2047. begin
  2048. if (Length(ProxySettings.UserName)>0) then begin
  2049. if SendCmd('USER ' + ProxySettings.UserName, [230, 331]) = 331 then begin {do not localize}
  2050. SendCmd('PASS ' +GetLoginPassword, 230); {do not localize}
  2051. end;
  2052. end;//proxy login
  2053. SendCmd('OPEN '+FtpHost);//? Server Reply? 220? {do not localize}
  2054. if SendCmd('USER ' + FUserName, [230, 232, 331]) = 331 then begin {do not localize}
  2055. SendCmd('PASS ' +GetLoginPassword, 230); {do not localize}
  2056. end;
  2057. end;//fpcmSite
  2058. fpcmUserPass: //USER user@firewalluser@hostname / PASS pass@firewallpass
  2059. begin
  2060. if SendCmd(Format('USER %s@%s@%s', [FUserName, ProxySettings.UserName, FtpHost]), [230, 232, 331])=331 then begin {do not localize}
  2061. if Length(ProxySettings.Password)>0 then begin
  2062. SendCmd('PASS ' + GetLoginPassword + '@' + ProxySettings.Password, 230); {do not localize}
  2063. end
  2064. else begin //// needs otp ////
  2065. SendCmd('PASS ' + GetLoginPassword, 230); {do not localize}
  2066. end;//if @
  2067. end;
  2068. end;//fpcmUserPass
  2069. fpcmTransparent: //? +Host
  2070. begin
  2071. if (Length(ProxySettings.UserName)>0) then begin
  2072. if SendCmd('USER ' + ProxySettings.UserName, [230, 331]) = 331 then begin {do not localize}
  2073. SendCmd('PASS ' + ProxySettings.Password, 230); {do not localize}
  2074. end;
  2075. end;//proxy login
  2076. if SendCmd('USER ' + FUserName, [230, 232, 331]) = 331 then begin {do not localize}
  2077. SendCmd('PASS ' + GetLoginPassword, 230); {do not localize}
  2078. end;
  2079. end;//fpcmTransparent
  2080. fpcmHttpProxyWithFtp:
  2081. begin
  2082. {GET ftp://XXX:YYY@indy.nevrona.com/ HTTP/1.0
  2083. Host: indy.nevrona.com
  2084. User-Agent: Mozilla/4.0 (compatible; Wincmd; Windows NT)
  2085. Proxy-Authorization: Basic B64EncodedUserPass==
  2086. Connection: close}
  2087. raise EIdSocksServerCommandError.Create(RSSocksServerCommandError);
  2088. end;//fpcmHttpProxyWithFtp
  2089. fpcmCustomProxy :
  2090. begin
  2091. DoCustomFTPProxy;
  2092. end;
  2093. end;//case
  2094. FLoginMsg.Assign(LastCmdResult);
  2095. DoOnBannerAfterLogin(FLoginMsg.FormattedReply);
  2096. //Feat data
  2097. SendCmd('FEAT'); {do not localize}
  2098. FCapabilities.Clear;
  2099. FCapabilities.AddStrings( LastCmdResult.Text );
  2100. //we remove the first and last lines because we only want the list
  2101. if FCapabilities.Count > 0 then
  2102. begin
  2103. FCapabilities.Delete(0);
  2104. end;
  2105. if FCapabilities.Count > 0 then
  2106. begin
  2107. FCapabilities.Delete( FCapabilities.Count -1 );
  2108. end;
  2109. if FUsingExtDataPort then begin
  2110. FUsingExtDataPort := (IsExtSupported('EPRT')) and {do not localize}
  2111. (IsExtSupported('EPSV')); {do not localize}
  2112. end;
  2113. if FClientInfo.GetClntOutput<>'' then begin
  2114. if Self.IsExtSupported('CLNT') then begin {do not localize}
  2115. SendCmd('CLNT '+ FClientInfo.GetClntOutput); {do not localize}
  2116. end;
  2117. end;
  2118. FCanUseMLS := UseMLIS and
  2119. ((IsExtSupported('MLSD')) or (IsExtSupported('MLST'))); {do not localize}
  2120. ExtractFeatFacts('LANG',FLangsSupported); {do not localize}
  2121. SendTransferType;
  2122. End;//TIdFTP.Login
  2123. procedure TIdFTP.DoAfterLogin;
  2124. begin
  2125. if Assigned(FOnAfterClientLogin) then begin
  2126. OnAfterClientLogin(self);
  2127. end;
  2128. end;
  2129. procedure TIdFTP.DoFTPList;
  2130. begin
  2131. if Assigned(FOnCreateFTPList) then begin
  2132. FOnCreateFTPList(self, FDirectoryListing);
  2133. end;
  2134. end;
  2135. function TIdFTP.GetDirectoryListing: TIdFTPListItems;
  2136. begin
  2137. if FDirectoryListing = nil then begin
  2138. if Assigned(FOnDirParseStart) then
  2139. begin
  2140. FOnDirParseStart(Self);
  2141. end;
  2142. ConstructDirListing;
  2143. ParseFTPList(FListResult);
  2144. end;
  2145. Result := FDirectoryListing;
  2146. end;
  2147. procedure TIdFTP.SetProxySettings(const Value: TIdFtpProxySettings);
  2148. Begin
  2149. FProxySettings.Assign(Value);
  2150. End;//
  2151. { TIdFtpProxySettings }
  2152. procedure TIdFtpProxySettings.Assign(Source: TPersistent);
  2153. Begin
  2154. if Source is TIdFtpProxySettings then begin
  2155. with TIdFtpProxySettings(Source) do begin
  2156. SELF.FProxyType := ProxyType;
  2157. SELF.FHost := Host;
  2158. SELF.FUserName := UserName;
  2159. SELF.FPassword := Password;
  2160. SELF.FPort := Port;
  2161. end;
  2162. end
  2163. else begin
  2164. inherited Assign(Source);
  2165. end;
  2166. End;//
  2167. procedure TIdFTP.SendPBSZ;
  2168. begin
  2169. {NOte that PBSZ - protection buffer size
  2170. must always be zero for FTP TLS
  2171. }
  2172. if FUsingSFTP or (FUseTLS=utUseImplicitTLS)then
  2173. begin
  2174. //protection buffer size
  2175. SendCmd('PBSZ 0'); {do not localize}
  2176. end;
  2177. end;
  2178. procedure TIdFTP.SendPROT;
  2179. begin
  2180. case FDataPortProtection of
  2181. ftpdpsClear : SendCmd('PROT C', 200); //'C' - Clear - neither Integrity nor Privacy {do not localize}
  2182. // NOT USED - 'S' - Safe - Integrity without Privacy
  2183. // NOT USED - 'E' - Confidential - Privacy without Integrity
  2184. // 'P' - Private - Integrity and Privacy
  2185. ftpdpsPrivate : SendCmd('PROT P',200); {do not localize}
  2186. end;
  2187. end;
  2188. procedure TIdFTP.SendDataSettings;
  2189. begin
  2190. if FUsingSFTP then
  2191. begin
  2192. if not FUsingCCC then
  2193. begin
  2194. SendPBSZ;
  2195. SendPROT;
  2196. if FUseCCC then
  2197. begin
  2198. FUsingCCC := (SendCmd('CCC') div 100=2); {do not localize}
  2199. if FUsingCCC then
  2200. begin
  2201. (IOHandler as TIdSSLIOHandlerSocketBase).PassThrough := true;
  2202. end;
  2203. end;
  2204. end;
  2205. end;
  2206. end;
  2207. procedure TIdFTP.SetIOHandler(AValue: TIdIOHandler);
  2208. var LSH : TIdIOHandlerSocket;
  2209. begin
  2210. inherited;
  2211. if (AValue=nil) or (AValue is TIdIOHandlerSocket) then begin
  2212. if AValue is TIdIOHandlerSocket then
  2213. begin
  2214. LSH := TIdIOHandlerSocket(AValue);
  2215. // UseExtensionDataPort must be true for IPv6 connections.
  2216. // PORT and PASV can not communicate IPv6 Addresses
  2217. if LSH.IPVersion = Id_IPv6 then begin
  2218. FUseExtensionDataPort := True;
  2219. end;
  2220. end;
  2221. end else begin
  2222. raise EIdFTPWrongIOHandler.Create(RSFTPIOHandlerWrong); // RS + EXCEPTION {do not localize}
  2223. end;
  2224. end;
  2225. procedure TIdFTP.SetUseExtensionDataPort(const AValue: Boolean);
  2226. begin
  2227. if (AValue = False)
  2228. and (IPVersion = Id_IPv6) then begin
  2229. Raise EIdFTPMustUseExtWithIPv6.Create(RSFTPMustUseExtWithIPv6);
  2230. end else begin
  2231. if TryNATFastTrack then begin
  2232. Raise EIdFTPMustUseExtWithNATFastTrack.Create(RSFTPMustUseExtWithNATFastTrack);
  2233. end;
  2234. FUseExtensionDataPort := AValue;
  2235. end;
  2236. end;
  2237. procedure TIdFTP.ParseEPSV(const AReply : String; var VIP : String; VPort : Integer);
  2238. var
  2239. bLeft,bRight: integer;
  2240. delim : Char;
  2241. s : String;
  2242. begin
  2243. s := Trim(LastCmdResult.Text[0]);
  2244. // "229 Entering Extended Passive Mode (|||59028|)"
  2245. bLeft := IndyPos('(', s); {do not localize}
  2246. bRight := IndyPos(')', s); {do not localize}
  2247. s := Copy(s, bLeft + 1, bRight - bLeft - 1);
  2248. delim := s[1]; // normally is | but the RFC say it may be different
  2249. Fetch(S, delim);
  2250. Fetch(S, delim);
  2251. VIP := Fetch(S, delim);
  2252. s := Trim(Fetch(S, delim));
  2253. VPort := StrToIntDef(s,0);
  2254. if VPort = 0 then begin
  2255. raise EIdFTPServerSentInvalidPort.CreateFmt(RSFTPServerSentInvalidPort, [s]);
  2256. end;
  2257. if VIP = '' then begin
  2258. VIP := Self.Host;
  2259. end;
  2260. end;
  2261. procedure TIdFTP.SendEPassive(var VIP: string; var VPort: integer);
  2262. var
  2263. bLeft,bRight: integer;
  2264. delim: char;
  2265. s: string;
  2266. begin
  2267. SendDataSettings;
  2268. //Note that for FTP Proxies, it is not desirable for the server to choose
  2269. //the EPSV data port IP connection type. We try to if we can.
  2270. if FProxySettings.ProxyType <> fpcmNone then
  2271. begin
  2272. case IPVersion of
  2273. Id_IPv4 : s := '1'; {do not localize}
  2274. Id_IPv6 : s := '2'; {do not localize}
  2275. end;
  2276. SendCMD('EPSV '+s); {do not localize}
  2277. //Raidon and maybe a few others may honor EPSV but not with the proto numbers
  2278. if LastCmdResult.NumericCode <> 229 then
  2279. begin
  2280. SendCMD('EPSV'); {do not localize}
  2281. end;
  2282. end
  2283. else
  2284. begin
  2285. SendCMD('EPSV'); {do not localize}
  2286. end;
  2287. if LastCmdResult.NumericCode<>229 then
  2288. begin
  2289. SendPassive(VIP, VPort);
  2290. FUsingExtDataPort := False;
  2291. Exit;
  2292. end;
  2293. try
  2294. ParseEPSV(Trim(LastCmdResult.Text[0]),VIP,VPort);
  2295. // "229 Entering Extended Passive Mode (|||59028|)"
  2296. bLeft := IndyPos('(', s); {do not localize}
  2297. bRight := IndyPos(')', s); {do not localize}
  2298. s := Copy(s, bLeft + 1, bRight - bLeft - 1);
  2299. delim := s[1]; // normally is | but the RFC say it may be different
  2300. Fetch(S, delim);
  2301. Fetch(S, delim);
  2302. VIP := Fetch(S, delim);
  2303. s := Trim(Fetch(S, delim));
  2304. VPort := StrToIntDef(s,0);
  2305. if VPort = 0 then begin
  2306. raise EIdFTPServerSentInvalidPort.CreateFmt(RSFTPServerSentInvalidPort, [s]);
  2307. end;
  2308. if VIP = '' then begin
  2309. VIP := Self.Host;
  2310. end;
  2311. except
  2312. SendCmd('ABOR'); {do not localize}
  2313. raise;
  2314. end;
  2315. end;
  2316. procedure TIdFTP.SendEPort(AHandle: TIdSocketHandle);
  2317. begin
  2318. SendDataSettings;
  2319. if FExternalIP <> '' then
  2320. begin
  2321. SendEPort(FExternalIP,AHandle.Port, AHandle.IPVersion);
  2322. end
  2323. else
  2324. begin
  2325. SendEPort(AHandle.IP,AHandle.Port, AHandle.IPVersion);
  2326. end;
  2327. end;
  2328. procedure TIdFTP.SendEPort(const AIP: String; const APort: Integer;
  2329. const AIPVersion: TIdIPVersion);
  2330. var s : String;
  2331. begin
  2332. s := '|';
  2333. case AIPVersion of
  2334. Id_IPv4 : s := s + '1'; {do not localize}
  2335. Id_IPv6 : s := s + '2'; {do not localize}
  2336. end;
  2337. s := s + '|';
  2338. SendCmd('EPRT ' + s+ AIP + '|' + IntToStr(APort) + '|'); {do not localize}
  2339. if LastCmdResult.NumericCode<>200 then
  2340. begin
  2341. SendPort(AIP,APort);
  2342. FUsingExtDataPort := False;
  2343. end;
  2344. end;
  2345. procedure TIdFTP.SetPassive(const AValue: Boolean);
  2346. begin
  2347. if (AValue=False) and (FTryNATFastTrack) then
  2348. begin
  2349. Raise EIdFTPPassiveMustBeTrueWithNATFT.Create(RSFTPFTPPassiveMustBeTrueWithNATFT);
  2350. end
  2351. else
  2352. begin
  2353. FPassive := AValue;
  2354. end;
  2355. end;
  2356. procedure TIdFTP.SetTryNATFastTrack(const AValue: Boolean);
  2357. begin
  2358. FTryNATFastTrack := AValue;
  2359. if FTryNATFastTrack then
  2360. begin
  2361. FPassive := True;
  2362. FUseExtensionDataPort := True;
  2363. end;
  2364. end;
  2365. procedure TIdFTP.DoTryNATFastTrack;
  2366. begin
  2367. if (FCapabilities.IndexOf('EPSV')>-1) then {do not localize}
  2368. begin
  2369. SendCMD('EPSV ALL'); {do not localize}
  2370. //Surge FTP treats EPSV ALL as if it were a standard EPSV
  2371. //We send ABOR in that case so it can close the data connection it created
  2372. if LastCmdResult.NumericCode = 229 then
  2373. begin
  2374. SendCMD('ABOR'); {do not localize}
  2375. end;
  2376. FUsingNATFastTrack := True;
  2377. end;
  2378. end;
  2379. procedure TIdFTP.SetCMDOpt(const ACMD, AOptions: String);
  2380. begin
  2381. SendCMD('OPTS '+ACMD+' '+AOptions,200); {do not localize}
  2382. end;
  2383. procedure TIdFTP.ExtListDir(const ADest: TIdStrings=nil; const ADirectory: string='');
  2384. var LDest: TIdStringStream;
  2385. LStream : TIdStreamVCL;
  2386. begin
  2387. LDest := TIdStringStream.Create('');
  2388. LStream := TIdStreamVCL.Create(LDest);
  2389. try
  2390. InternalGet(trim('MLSD ' + ADirectory), LStream); {do not localize}
  2391. finally
  2392. FreeAndNil(LStream);
  2393. end;
  2394. FreeAndNil(FDirectoryListing);
  2395. DoOnRetrievedDir;
  2396. if Assigned(ADest) then begin //APR: User can use ListResult and DirectoryListing
  2397. ADest.Text := LDest.DataString;
  2398. end;
  2399. FListResult.Text := LDest.DataString;
  2400. FUsedMLS := True;
  2401. end;
  2402. procedure TIdFTP.ExtListItem(ADest: TIdStrings; AFList : TIdFTPListItems; const AItem: string);
  2403. var i : Integer;
  2404. begin
  2405. ADest.Clear;
  2406. SendCMD(Trim('MLST '+AItem), 250); {do not localize}
  2407. for i := 0 to LastCmdResult.Text.Count -1 do
  2408. begin
  2409. if Pos(';',LastCmdResult.Text[i]) > 0 then
  2410. begin
  2411. ADest.Add(LastCmdResult.Text[i]);
  2412. end;
  2413. end;
  2414. if Assigned(AFList) then
  2415. begin
  2416. IdFTPListParseBase.ParseListing(ADest, AFList, 'MLST'); {do not localize}
  2417. end;
  2418. end;
  2419. procedure TIdFTP.ExtListItem(ADest: TIdStrings; const AItem: string);
  2420. begin
  2421. ExtListItem(ADest,nil, AItem);
  2422. end;
  2423. procedure TIdFTP.ExtListItem(AFList: TIdFTPListItems; const AItem: String);
  2424. var LBuf : TIdStrings;
  2425. begin
  2426. LBuf := TIdStringList.Create;
  2427. try
  2428. ExtListItem(LBuf,AFList,AItem);
  2429. finally
  2430. FreeAndNil(LBuf);
  2431. end;
  2432. end;
  2433. function TIdFTP.IsExtSupported(const ACmd: String): Boolean;
  2434. var i : Integer;
  2435. LBuf : String;
  2436. begin
  2437. Result := False;
  2438. for i := 0 to FCapabilities.Count -1 do
  2439. begin
  2440. LBuf := TrimLeft(FCapabilities[i]);
  2441. LBuf := UpperCase(Fetch(LBuf));
  2442. if LBuf = ACMD then
  2443. begin
  2444. Result := True;
  2445. Break;
  2446. end;
  2447. end;
  2448. end;
  2449. function TIdFTP.FileDate(const AFileName: String;
  2450. const AsGMT: Boolean): TDateTime;
  2451. var LBuf : String;
  2452. begin
  2453. //Do not use the FEAT list because some servers
  2454. //may support it even if FEAT isn't supported
  2455. if SendCmd('MDTM ' + AFileName) = 213 then {do not localize}
  2456. begin
  2457. LBuf := LastCmdResult.Text[0];
  2458. LBuf := Trim(LBuf);
  2459. if AsGMT then
  2460. begin
  2461. Result := FTPMLSToGMTDateTime(LBuf);
  2462. end
  2463. else
  2464. begin
  2465. Result := FTPMLSToLocalDateTime(LBuf);
  2466. end;
  2467. end
  2468. else
  2469. begin
  2470. Result := 0;
  2471. end;
  2472. end;
  2473. procedure TIdFTP.SiteToSiteUpload(const AToSite: TIdFTP; const ASourceFile,
  2474. ADestFile: String);
  2475. {
  2476. SiteToSiteUpload
  2477. From: PASV To: PORT - ATargetUsesPasv = False
  2478. From: RETR To: STOR
  2479. SiteToSiteDownload
  2480. From: PORT To: PASV - ATargetUsesPasv = True
  2481. From: RETR To: STOR
  2482. }
  2483. begin
  2484. if ValidateInternalIsTLSFXP(Self,AToSite,True) then
  2485. begin
  2486. InternalEncryptedTLSFXP(Self,AToSite,ASourceFile,ADestFile,True);
  2487. end
  2488. else
  2489. begin
  2490. InternalUnencryptedFXP(Self,AToSite,ASourceFile,ADestFile,True);
  2491. end;
  2492. end;
  2493. procedure TIdFTP.SiteToSiteDownload(const AFromSite: TIdFTP; const ASourceFile,
  2494. ADestFile: String);
  2495. {
  2496. The only use of this function is to get the passive mode on the other connection.
  2497. Because not all hosts allow it. This way you get a second chance.
  2498. If uploading from host A doesn't work, try downloading from host B
  2499. }
  2500. begin
  2501. if ValidateInternalIsTLSFXP(AFromSite,Self,True) then
  2502. begin
  2503. InternalEncryptedTLSFXP(AFromSite,Self,ASourceFile,ADestFile,False);
  2504. end
  2505. else
  2506. begin
  2507. InternalUnencryptedFXP(AFromSite,Self,ASourceFile,ADestFile,False);
  2508. end;
  2509. end;
  2510. procedure TIdFTP.ExtractFeatFacts(const ACmd: String; AResults: TIdStrings);
  2511. var i : Integer;
  2512. LBuf : String;
  2513. begin
  2514. for i := 0 to FCapabilities.Count -1 do
  2515. begin
  2516. LBuf := FCapabilities[i];
  2517. LBuf := UpperCase(Fetch(LBuf));
  2518. if LBuf = ACMD then
  2519. begin
  2520. LBuf := FCapabilities[i];
  2521. Fetch(LBuf);
  2522. LBuf := Trim(LBuf);
  2523. Break;
  2524. end;
  2525. //necessary so we don't wind up capturing the last entry in the FEAT list
  2526. //if the command is not supported
  2527. LBuf := '';
  2528. end;
  2529. AResults.Clear;
  2530. repeat
  2531. if LBuf='' then
  2532. begin
  2533. Break;
  2534. end;
  2535. AResults.Add(Trim(Fetch(LBuf,';')));
  2536. until False;
  2537. end;
  2538. procedure TIdFTP.SetLang(const ALangTag: String);
  2539. begin
  2540. if IsExtSupported('LANG') then {do not localize}
  2541. begin
  2542. SendCMD('LANG '+ ALangTag, 200); {do not localize}
  2543. end;
  2544. end;
  2545. function TIdFTP.CRC(const AFIleName: String; const AStartPoint,
  2546. AEndPoint: Cardinal): Int64;
  2547. var LCMD : String;
  2548. LCRC : String;
  2549. begin
  2550. Result := -1;
  2551. if IsExtSupported('XCRC') then {do not localize}
  2552. begin
  2553. LCMD := 'XCRC "' + AFileName + '"'; {do not localize}
  2554. if AStartPoint<>0 then
  2555. begin
  2556. LCMD := LCMD + ' '+IntToStr(AStartPoint);
  2557. if AEndPoint<>0 then
  2558. begin
  2559. LCMD := LCMD + ' '+IntToStr(AEndPoint);
  2560. end;
  2561. end;
  2562. if SendCMD(LCMD) = 250 then
  2563. begin
  2564. LCRC := Trim(LastCmdResult.Text.Text);
  2565. IdDelete(LCRC, 1, IndyPos(' ', LCRC)); // delete the response
  2566. Result := StrToInt64Def('$'+LCRC, -1);
  2567. end;
  2568. end;
  2569. end;
  2570. procedure TIdFTP.CombineFiles(const ATargetFile: String;
  2571. AFileParts: TIdStrings);
  2572. var i : Integer;
  2573. LCMD : String;
  2574. begin
  2575. if IsExtSupported('COMB') and (AFileParts.Count > 0) then {do not localize}
  2576. begin
  2577. LCMD := 'COMB "' + ATargetFile + '"'; {do not localize}
  2578. for i := 0 to AFileParts.Count -1 do
  2579. begin
  2580. LCMD := LCMD + ' ' + AFileParts[i];
  2581. end;
  2582. SendCMD(LCMD, [250]);
  2583. end;
  2584. end;
  2585. procedure TIdFTP.ParseFTPList(AData : TIdStrings);
  2586. begin
  2587. DoOnDirParseStart;
  2588. try
  2589. // Parse directory listing
  2590. if AData.Count > 0 then
  2591. begin
  2592. if FUsedMLS then
  2593. begin
  2594. IdFTPListParseBase.ParseListing(AData, FDirectoryListing, MLST);
  2595. end
  2596. else
  2597. begin
  2598. CheckListParseCapa(AData, FDirectoryListing, FDirFormat, FListParserClass, SystemDesc);
  2599. end;
  2600. end;
  2601. finally
  2602. DoOnDirParseEnd;
  2603. end;
  2604. end;
  2605. function TIdFTP.EPRTParams(const AIP: String; const APort: Integer;
  2606. const AIPVersion: TIdIPVersion): String;
  2607. begin
  2608. Result := '|';
  2609. case AIPVersion of
  2610. Id_IPv4 : Result := Result + '1'; {do not localize}
  2611. Id_IPv6 : Result := Result + '2'; {do not localize}
  2612. end;
  2613. Result := Result + '|';
  2614. Result := Result + AIP + '|' + IntToStr(APort) + '|';
  2615. end;
  2616. function TIdFTP.GetSupportsTLS: Boolean;
  2617. begin
  2618. Result := (FindAuthCmd<>'');
  2619. end;
  2620. function TIdFTP.FindAuthCmd: String;
  2621. var i : Integer;
  2622. LBuf : String;
  2623. LWord : String;
  2624. begin
  2625. Result := '';
  2626. for i := 0 to FCapabilities.Count -1 do
  2627. begin
  2628. LBuf := TrimLeft(FCapabilities[i]);
  2629. LBuf := UpperCase(Fetch(LBuf));
  2630. if LBuf = 'AUTH' then {do not localize}
  2631. begin
  2632. repeat
  2633. LWord := Trim(Fetch(LBuf,';'));
  2634. if (PosInStrArray(LWord,TLS_AUTH_NAMES)>-1) then
  2635. begin
  2636. Result := 'AUTH ' + LWord; {do not localize}
  2637. end;
  2638. until (LBuf='') or (Result ='');
  2639. Break;
  2640. end;
  2641. end;
  2642. end;
  2643. procedure TIdFTP.DoCustomFTPProxy;
  2644. begin
  2645. if Assigned(FOnCustomFTPProxy) then
  2646. begin
  2647. FOnCustomFTPProxy(Self);
  2648. end
  2649. else
  2650. begin
  2651. raise EIdFTPOnCustomFTPProxyRequired.Create(RSFTPOnCustomFTPProxyReq);
  2652. end;
  2653. end;
  2654. function TIdFTP.GetLoginPassword: String;
  2655. begin
  2656. Result := GetLoginPassword(LastCmdResult.Text.Text);
  2657. end;
  2658. function TIdFTP.GetLoginPassword(const APrompt: String): String;
  2659. begin
  2660. if IsValidOTPString(APrompt) then
  2661. begin
  2662. Result := GenerateOTP(APrompt, FPassword);
  2663. end
  2664. else
  2665. begin
  2666. Result := FPassword;
  2667. end;
  2668. end;
  2669. function TIdFTP.SetSSCNToOn : Boolean;
  2670. begin
  2671. Result := FUsingSFTP;
  2672. if not Result then
  2673. begin
  2674. Exit;
  2675. end;
  2676. Result := (DataPortProtection = ftpdpsPrivate);
  2677. if not Result then
  2678. begin
  2679. Exit;
  2680. end;
  2681. Result := (IsExtSupported(SCCN_FEAT)=False);
  2682. if not Result then
  2683. begin
  2684. Exit;
  2685. end;
  2686. if not FSSCNOn then
  2687. begin
  2688. SendCmd(SSCN_ON, SSCN_OK_REPLY);
  2689. FSSCNOn := True;
  2690. end;
  2691. end;
  2692. procedure TIdFTP.ClearSSCN;
  2693. begin
  2694. if FSSCNOn then
  2695. begin
  2696. SendCmd(SSCN_OFF, SSCN_OK_REPLY);
  2697. end;
  2698. end;
  2699. procedure TIdFTP.SetClientInfo(const AValue: TIdFTPClientIdentifier);
  2700. begin
  2701. FClientInfo.Assign( AValue);
  2702. end;
  2703. function TIdFTP.GetReplyClass: TIdReplyClass;
  2704. begin
  2705. Result := TIdReplyFTP;
  2706. end;
  2707. procedure TIdFTP.SetIPVersion(const AValue: TIdIPVersion);
  2708. begin
  2709. if AValue <> FIPVersion then
  2710. begin
  2711. inherited SetIPVersion(AValue);
  2712. if AValue = Id_IPv6 then
  2713. begin
  2714. UseExtensionDataPort := True;
  2715. end;
  2716. end;
  2717. end;
  2718. function TIdFTP.InternalEncryptedTLSFXP(AFromSite, AToSite: TIdFTP;
  2719. const ASourceFile, ADestFile: String; const ATargetUsesPasv : Boolean): Boolean;
  2720. {
  2721. SiteToSiteUpload
  2722. From: PASV To: PORT - ATargetUsesPasv = False
  2723. From: RETR To: STOR
  2724. SiteToSiteDownload
  2725. From: PORT To: PASV - ATargetUsesPasv = True
  2726. From: RETR To: STOR
  2727. To do FXP transfers with TLS FTP, you have to have one computer do the
  2728. TLS handshake as a client (ssl_connect). Thus, one of the following conditions must be meet.
  2729. 1) SSCN must be supported on one of the FTP servers
  2730. or
  2731. 2) If IPv4 is used, the computer receiving a "PASV" command must support
  2732. CPSV. CPSV will NOT work with IPv6.
  2733. IMAO, when doing FXP transfers, you should use SSCN whenever possible as
  2734. SSCN will support IPv6 and SSCN may be in wider use than CPSV. CPSV should
  2735. only be used as a fallback if SSCN isn't supported by both servers and IPv4
  2736. is being used.
  2737. }
  2738. var LIP : String;
  2739. LPort : Integer;
  2740. begin
  2741. Result := True;
  2742. if AFromSite.SetSSCNToOn then
  2743. begin
  2744. AToSite.ClearSSCN;
  2745. end
  2746. else
  2747. begin
  2748. if AToSite.SetSSCNToOn then
  2749. begin
  2750. AFromSite.ClearSSCN;
  2751. end
  2752. else
  2753. begin
  2754. if AToSite.IPVersion = Id_IPv4 then
  2755. begin
  2756. if ATargetUsesPasv then
  2757. begin
  2758. AToSite.SendCPassive(LIP,LPort);
  2759. AFromSite.SendPort(LIP,LPort);
  2760. end
  2761. else
  2762. begin
  2763. AFromSite.SendCPassive(LIP,LPort);
  2764. AToSite.SendPort(LIP,LPort);
  2765. end;
  2766. end;
  2767. end;
  2768. end;
  2769. FXPSendFile(AFromSite, AToSite,ASourceFile,ADestFile);
  2770. end;
  2771. function TIdFTP.InternalUnencryptedFXP(AFromSite, AToSite: TIdFTP;
  2772. const ASourceFile, ADestFile: String; const ATargetUsesPasv : Boolean): Boolean;
  2773. {
  2774. SiteToSiteUpload
  2775. From: PASV To: PORT - ATargetUsesPasv = False
  2776. From: RETR To: STOR
  2777. SiteToSiteDownload
  2778. From: PORT To: PASV - ATargetUsesPasv = True
  2779. From: RETR To: STOR
  2780. }
  2781. begin
  2782. FXPSetTransferPorts(AFromSite, AToSite, ATargetUsesPasv);
  2783. FXPSendFile(AFromSite, AToSite, ASourceFile, ADestFile);
  2784. Result := True;
  2785. end;
  2786. function TIdFTP.ValidateInternalIsTLSFXP(AFromSite, AToSite: TIdFTP; const ATargetUsesPasv : Boolean): Boolean;
  2787. {
  2788. SiteToSiteUpload
  2789. From: PASV To: PORT - ATargetUsesPasv = False
  2790. From: RETR To: STOR
  2791. SiteToSiteDownload
  2792. From: PORT To: PASV - ATargetUsesPasv = True
  2793. From: RETR To: STOR
  2794. This will raise an exception if FXP can not be done. Result = True for encrypted
  2795. or False for unencrypted.
  2796. Note:
  2797. The following is required:
  2798. SiteToSiteUpload
  2799. Source must do P
  2800. }
  2801. begin
  2802. if ATargetUsesPasv then
  2803. begin
  2804. if AToSite.UsingNATFastTrack then
  2805. begin
  2806. raise EIdFTPSToSNATFastTrack.Create(RSFTPNoSToSWithNATFastTrack);
  2807. end;
  2808. end
  2809. else
  2810. begin
  2811. if AFromSite.UsingNATFastTrack then
  2812. begin
  2813. raise EIdFTPSToSNATFastTrack.Create(RSFTPNoSToSWithNATFastTrack);
  2814. end;
  2815. end;
  2816. if AFromSite.IPVersion <> AToSite.IPVersion then
  2817. begin
  2818. raise EIdFTPStoSIPProtoMustBeSame.Create(RSFTPSToSProtosMustBeSame);
  2819. end;
  2820. if AFromSite.CurrentTransferMode <> AToSite.CurrentTransferMode then
  2821. begin
  2822. raise EIdFTPSToSTransModesMustBeSame.Create(RSFTPSToSTransferModesMusbtSame);
  2823. end;
  2824. Result := AFromSite.FUsingSFTP and AToSite.FUsingSFTP;
  2825. if AFromSite.FUsingSFTP <> AToSite.FUsingSFTP then
  2826. begin
  2827. raise EIdFTPSToSNoDataProtection.Create(RSFTPSToSNoDataProtection);
  2828. end;
  2829. if Result then
  2830. begin
  2831. if AFromSite.IsExtSupported('SSCN') or AToSite.IsExtSupported('SSCN') then {do not localize}
  2832. begin
  2833. end
  2834. else
  2835. begin
  2836. //Second chance fallback, is CPSV supported on the server where PASV would
  2837. // be sent
  2838. if AToSite.IPVersion = Id_IPv4 then
  2839. begin
  2840. if ATargetUsesPasv then
  2841. begin
  2842. if not AToSite.IsExtSupported('CPSV') then {do not localize}
  2843. begin
  2844. raise EIdFTPSToSNATFastTrack.Create(RSFTPSToSSSCNNotSupported);
  2845. end;
  2846. end
  2847. else
  2848. begin
  2849. if not AFromSite.IsExtSupported('CPSV') then {do not localize}
  2850. begin
  2851. raise EIdFTPSToSNATFastTrack.Create(RSFTPSToSSSCNNotSupported);
  2852. end;
  2853. end;
  2854. end;
  2855. end;
  2856. end;
  2857. end;
  2858. procedure TIdFTP.FXPSendFile(AFromSite, AToSite: TIdFTP; const ASourceFile,
  2859. ADestFile: String);
  2860. var LDestFile : String;
  2861. begin
  2862. LDestFile := ADestFile;
  2863. if LDestFile = '' then
  2864. begin
  2865. LDestFile := ASourceFile;
  2866. end;
  2867. AToSite.IOHandler.WriteLn('STOR ' + LDestFile); {do not localize}
  2868. AFromSite.IOHandler.WriteLn('RETR ' + ASourceFile); {do not localize}
  2869. AToSite.GetResponse( [110, 125, 150] ) ;
  2870. AFromSite.GetResponse( [110, 125, 150] );
  2871. // AToSite.SendCmd( 'STOR ' + LDestFile,[110, 125, 150] ); {do not localize}
  2872. // AFromSite.SendCmd( 'RETR ' + ASourceFile,[110, 125, 150] ); {do not localize}
  2873. AToSite.GetResponse([225, 226, 250]);
  2874. AFromSite.GetResponse([225, 226, 250]);
  2875. end;
  2876. procedure TIdFTP.FXPSetTransferPorts(AFromSite, AToSite: TIdFTP;
  2877. const ATargetUsesPasv: Boolean);
  2878. var LIP : String;
  2879. LPort : Integer;
  2880. {
  2881. {
  2882. SiteToSiteUpload
  2883. From: PASV To: PORT - ATargetUsesPasv = False
  2884. From: RETR To: STOR
  2885. SiteToSiteDownload
  2886. From: PORT To: PASV - ATargetUsesPasv = True
  2887. From: RETR To: STOR
  2888. }
  2889. begin
  2890. if ATargetUsesPasv then
  2891. begin
  2892. if AToSite.UsingExtDataPort then
  2893. begin
  2894. AToSite.SendEPassive(LIP,LPort);
  2895. end
  2896. else
  2897. begin
  2898. AToSite.SendPassive(LIP,LPort);
  2899. end;
  2900. if AFromSite.UsingExtDataPort then
  2901. begin
  2902. AFromSite.SendEPort(LIP,LPort, IPVersion);
  2903. end
  2904. else
  2905. begin
  2906. AFromSite.SendPort(LIP,LPort);
  2907. end;
  2908. end
  2909. else
  2910. begin
  2911. if AFromSite.UsingExtDataPort then
  2912. begin
  2913. AFromSite.SendEPassive(LIP,LPort);
  2914. end
  2915. else
  2916. begin
  2917. AFromSite.SendPassive(LIP,LPort);
  2918. end;
  2919. if AToSite.UsingExtDataPort then
  2920. begin
  2921. AToSite.SendEPort(LIP,LPort,IPVersion);
  2922. end
  2923. else
  2924. begin
  2925. AToSite.SendPort(LIP,LPort);
  2926. end;
  2927. end;
  2928. end;
  2929. { TIdFTPClientIdentifier }
  2930. procedure TIdFTPClientIdentifier.Assign(Source: TPersistent);
  2931. begin
  2932. if Source is TIdFTPClientIdentifier then begin
  2933. with TIdFTPClientIdentifier(Source) do begin
  2934. SELF.ClientName := ClientName;
  2935. SELF.ClientVersion := ClientVersion;
  2936. SELF.PlatformDescription := PlatformDescription;
  2937. end;
  2938. end
  2939. else begin
  2940. inherited Assign(Source);
  2941. end;
  2942. end;
  2943. function TIdFTPClientIdentifier.GetClntOutput: String;
  2944. //assume syntax such as this:
  2945. //214 Syntax: CLNT <sp> <client-name> <sp> <client-version> [<sp> <optional platform info>] (Set client name)
  2946. begin
  2947. Result := '';
  2948. if FClientName<>'' then
  2949. begin
  2950. Result := Self.FClientName;
  2951. end
  2952. else
  2953. begin
  2954. Exit;
  2955. end;
  2956. if FClientVersion<>'' then
  2957. begin
  2958. Result := Result + ' '+FClientVersion;
  2959. end
  2960. else
  2961. begin
  2962. Exit;
  2963. end;
  2964. if FPlatformDescription <> '' then
  2965. begin
  2966. Result := Result + ' ' + FPlatformDescription;
  2967. end;
  2968. end;
  2969. procedure TIdFTPClientIdentifier.SetClientName(const AValue: String);
  2970. begin
  2971. FClientName := AValue;
  2972. FClientName := Trim(FClientName);
  2973. FClientName := Fetch(FClientName);
  2974. end;
  2975. procedure TIdFTPClientIdentifier.SetClientVersion(const AValue: String);
  2976. begin
  2977. FClientVersion := AValue;
  2978. FClientVersion := Trim(FClientVersion);
  2979. FClientVersion := Fetch(FClientVersion);
  2980. end;
  2981. procedure TIdFTPClientIdentifier.SetPlatformDescription(
  2982. const AValue: String);
  2983. begin
  2984. FPlatformDescription := AValue;
  2985. end;
  2986. procedure TIdFTP.SetModTime(const AFileName: String;
  2987. const ALocalTime: TDateTime);
  2988. begin
  2989. if IsExtSupported('MFMT') then {do not localize}
  2990. begin
  2991. SendCmd('MFMT '+FTPLocalDateTimeToMLS(ALocalTime)+ ' '+AFileName,[213]); {do not localize}
  2992. end
  2993. else
  2994. begin
  2995. {
  2996. Note from:
  2997. http://www.ftpvoyager.com/releasenotes.asp
  2998. ====
  2999. Added support for RFC change and the MDTM. MDTM requires sending the server
  3000. GMT (UTC) instead of a "fixed" date and time. FTP Voyager supports this with
  3001. Serv-U automatically by checking the Serv-U version number and by checking the
  3002. response to the FEAT command for MDTM. Servers returning "MDTM" or
  3003. "MDTM YYYYMMDDHHMMSS[+-TZ] filename" will use the old method. Servers
  3004. returning "MDTM YYYYMMDDHHMMSS" only will use the new method where the date a
  3005. and time is GMT (UTC).
  3006. ===
  3007. }
  3008. if (IndexOfFeatLine('MDTM YYYYMMDDHHMMSS[+-TZ];filename')>0) then {do not localize}
  3009. begin
  3010. //we use the new method
  3011. SendCmd('MDTM '+FTPLocalDateTimeToMLS(ALocalTime)+ ' '+AFileName,[253]); {do not localize}
  3012. end
  3013. else
  3014. begin
  3015. //use old method Serv-U
  3016. //BPFTP Server
  3017. if (IndexOfFeatLine('MDTM YYYYMMDDHHMMSS[+-TZ] filename')>0) or {do not localize}
  3018. IsServerMDTZAndListTForm then
  3019. begin
  3020. SendCmd('MDTM '+ FTPDateTimeToMDTMD(ALocalTime,False,True)+ ' '+AFileName,[253]); {do not localize}
  3021. end
  3022. else
  3023. begin
  3024. if Self.FTZInfo.FGMTOffsetAvailable then
  3025. begin
  3026. //send it relative to the server's time-zone
  3027. SendCmd('MDTM '+ FTPDateTimeToMDTMD(ALocalTime - OffSetFromUTC + FTZInfo.FGMTOffset,False,False)+ ' '+AFileName,[253]); {do not localize}
  3028. end
  3029. else
  3030. begin
  3031. SendCmd('MDTM '+ FTPDateTimeToMDTMD(ALocalTime,False,False)+ ' '+AFileName,[253]); {do not localize}
  3032. end;
  3033. end;
  3034. end;
  3035. end;
  3036. end;
  3037. procedure TIdFTP.SetModTimeGMT(const AFileName: String;
  3038. const AGMTTime: TDateTime);
  3039. begin
  3040. if IsExtSupported('MFMT') then {do not localize}
  3041. begin
  3042. SendCmd('MFMT '+FTPGMTDateTimeToMLS(AGMTTime)+ ' '+AFileName,[213]); {do not localize}
  3043. end
  3044. else
  3045. begin
  3046. {
  3047. Note from:
  3048. http://www.ftpvoyager.com/releasenotes.asp
  3049. ====
  3050. Added support for RFC change and the MDTM. MDTM requires sending the server
  3051. GMT (UTC) instead of a "fixed" date and time. FTP Voyager supports this with
  3052. Serv-U automatically by checking the Serv-U version number and by checking the
  3053. response to the FEAT command for MDTM. Servers returning "MDTM" or
  3054. "MDTM YYYYMMDDHHMMSS[+-TZ] filename" will use the old method. Servers
  3055. returning "MDTM YYYYMMDDHHMMSS" only will use the new method where the date a
  3056. and time is GMT (UTC).
  3057. ===
  3058. }
  3059. if (IndexOfFeatLine('MDTM YYYYMMDDHHMMSS[+-TZ];filename')>0) then {do not localize}
  3060. begin
  3061. //we use the new method
  3062. SendCmd('MDTM '+FTPGMTDateTimeToMLS(AGMTTime)+ ' '+AFileName,[253]); {do not localize}
  3063. end
  3064. else
  3065. begin
  3066. //use old method Serv-U
  3067. if (IndexOfFeatLine('MDTM YYYYMMDDHHMMSS[+-TZ] filename')>0) or {do not localize}
  3068. IsServerMDTZAndListTForm then
  3069. begin
  3070. SendCmd('MDTM '+ FTPDateTimeToMDTMD(AGMTTime + OffSetFromUTC,False,True)+ ' '+AFileName,[253]); {do not localize}
  3071. end
  3072. else
  3073. begin
  3074. if Self.FTZInfo.FGMTOffsetAvailable then
  3075. begin
  3076. //send it relative to the server's time-zone
  3077. SendCmd('MDTM '+ FTPDateTimeToMDTMD(AGMTTime + FTZInfo.FGMTOffset,False,False)+ ' '+AFileName,[253]); {do not localize}
  3078. end
  3079. else
  3080. begin
  3081. SendCmd('MDTM '+ FTPDateTimeToMDTMD(AGMTTime + OffSetFromUTC,False,False)+ ' '+AFileName,[253]); {do not localize}
  3082. end;
  3083. end;
  3084. end;
  3085. end;
  3086. end;
  3087. function TIdFTP.IndexOfFeatLine(const AFeatLine: String): Integer;
  3088. var
  3089. LBuf : String;
  3090. LNoSpaces:Boolean;
  3091. begin
  3092. {Improvement from Tobias Giesen http://www.superflexible.com
  3093. His notation is below:
  3094. "here's a fix for TIdFTP.IndexOfFeatLine. It does not work the
  3095. way it is used in TIdFTP.SetModTime, because it only
  3096. compares the first word of the FeatLine." }
  3097. LNoSpaces := IndyPos(' ',AFeatLine)=0;
  3098. for Result := 0 to FCapabilities.Count -1 do begin
  3099. LBuf := IndyUpperCase(TrimLeft(FCapabilities[Result]));
  3100. if LNoSpaces then begin
  3101. LBuf := Fetch(LBuf);
  3102. end;
  3103. if IndyUpperCase(AFeatLine)=LBuf then begin
  3104. Exit;
  3105. end;
  3106. end;
  3107. Result := -1;
  3108. end;
  3109. { TIdFTPTZInfo }
  3110. procedure TIdFTPTZInfo.Assign(Source: TPersistent);
  3111. begin
  3112. if Source is TIdFTPTZInfo then begin
  3113. with TIdFTPTZInfo(Source) do begin
  3114. Self.FGMTOffset := GMTOffset;
  3115. Self.FGMTOffsetAvailable := GMTOffsetAvailable;
  3116. end;
  3117. end
  3118. else begin
  3119. inherited Assign(Source);
  3120. end;
  3121. end;
  3122. procedure SplitStr(const AData : String; AResults : TIdStrings);
  3123. var LBuf : String;
  3124. begin
  3125. LBuf := AData;
  3126. AResults.Clear;
  3127. repeat
  3128. AResults.Add( Fetch(LBuf,';'));
  3129. if LBuf = '' then
  3130. begin
  3131. Break;
  3132. end;
  3133. until False;
  3134. end;
  3135. function TIdFTP.IsSiteZONESupported: Boolean;
  3136. var LFacts : TIdStrings;
  3137. i, j : Integer;
  3138. LBuf : String;
  3139. begin
  3140. Result := False;
  3141. if IsServerMDTZAndListTForm then
  3142. begin
  3143. Result := True;
  3144. Exit;
  3145. end;
  3146. LFacts := TIdStringList.Create;
  3147. try
  3148. for i := 0 to FCapabilities.Count -1 do
  3149. begin
  3150. LBuf := FCapabilities[i];
  3151. if UpperCase(Fetch(LBuf)) = 'SITE' then {do not localize}
  3152. begin
  3153. SplitStr(LBuf,LFacts);
  3154. for j := 0 to LFacts.Count -1 do
  3155. begin
  3156. if Uppercase(LFacts[j]) = 'ZONE' then {do not localize}
  3157. begin
  3158. Result := True;
  3159. Break;
  3160. end;
  3161. end;
  3162. break;
  3163. end;
  3164. end;
  3165. finally
  3166. FreeAndNil(LFacts);
  3167. end;
  3168. end;
  3169. procedure TIdFTP.SetTZInfo(const Value: TIdFTPTZInfo);
  3170. begin
  3171. FTZInfo.Assign(Value);
  3172. end;
  3173. function TIdFTP.IsServerMDTZAndListTForm: Boolean;
  3174. begin
  3175. Result := (Copy(FGreeting.Text[0],1,7) = 'Serv-U ') or {do not localize}
  3176. (Copy(FGreeting.Text[0],1,13) = 'BPFTP Server ') or {do not localize}
  3177. (Copy(FGreeting.Text[0],1,16) = 'TitanFTP server ') or {do not localize}
  3178. (Copy(FGreeting.Text[0],1,17) = 'Titan FTP Server '); {do not localize}
  3179. end;
  3180. procedure TIdFTP.Notification(AComponent: TComponent;
  3181. Operation: TOperation);
  3182. begin
  3183. inherited;
  3184. if Operation = opRemove then
  3185. begin
  3186. if (AComponent = FCompressor ) then
  3187. begin
  3188. FCompressor := nil;
  3189. if Connected then
  3190. begin
  3191. TransferMode(dmStream);
  3192. end;
  3193. end;
  3194. end;
  3195. end;
  3196. procedure TIdFTP.SendPret(const ACommand: String);
  3197. begin
  3198. if Self.IsExtSupported('PRET') then {do not localize}
  3199. begin
  3200. //note that we don't check for success or failure here
  3201. //as some servers might fail and then succede with the transfer.
  3202. //Pret might not work for some commands.
  3203. SendCmd('PRET ' + ACommand); {do not localize}
  3204. end;
  3205. end;
  3206. procedure TIdFTP.List;
  3207. begin
  3208. List(nil);
  3209. end;
  3210. procedure TIdFTP.List(const ASpecifier: string; ADetails: Boolean);
  3211. begin
  3212. List(nil, ASpecifier, ADetails);
  3213. end;
  3214. procedure TIdFTP.DoOnBannerAfterLogin(AText: TIdStrings);
  3215. begin
  3216. if Assigned( OnBannerAfterLogin ) then
  3217. begin
  3218. OnBannerAfterLogin(Self, AText.Text);
  3219. end;
  3220. end;
  3221. procedure TIdFTP.DoOnBannerBeforeLogin(AText: TIdStrings);
  3222. begin
  3223. if Assigned( OnBannerBeforeLogin ) then
  3224. begin
  3225. OnBannerBeforeLogin(Self, AText.Text);
  3226. end;
  3227. end;
  3228. procedure TIdFTP.SetDataPortProtection(AValue: TIdFTPDataPortSecurity);
  3229. begin
  3230. if csLoading in ComponentState then
  3231. begin
  3232. FDataPortProtection := AValue;
  3233. exit;
  3234. end;
  3235. if FDataPortProtection <> AValue then
  3236. begin
  3237. if FUseTLS=utNoTLSSupport then
  3238. begin
  3239. raise EIdFTPNoDataPortProtectionWOEncryption.Create(RSFTPNoDataPortProtectionWOEncryption);
  3240. end;
  3241. if FUsingCCC then
  3242. begin
  3243. raise EIdFTPNoDataPortProtectionAfterCCC.Create(RSFTPNoDataPortProtectionAfterCCC);
  3244. end;
  3245. FDataPortProtection := AValue;
  3246. end;
  3247. end;
  3248. procedure TIdFTP.SetAUTHCmd(const AValue : TAuthCmd);
  3249. begin
  3250. if csLoading in ComponentState then
  3251. begin
  3252. FAUTHCmd := AValue;
  3253. exit;
  3254. end;
  3255. if FAUTHCmd <> AValue then
  3256. begin
  3257. if FUseTLS=utNoTLSSupport then
  3258. begin
  3259. raise EIdFTPNoAUTHWOSSL.Create(RSFTPNoAUTHWOSSL);
  3260. end;
  3261. if FUsingSFTP then
  3262. begin
  3263. raise EIdFTPCanNotSetAUTHCon.Create(RSFTPNoAUTHCon);
  3264. end;
  3265. FAUTHCmd := AValue;
  3266. end;
  3267. end;
  3268. procedure TIdFTP.SetUseTLS(AValue: TIdUseTLS);
  3269. begin
  3270. inherited;
  3271. if csLoading in ComponentState then
  3272. begin
  3273. exit;
  3274. end;
  3275. if (AValue=utNoTLSSupport) then
  3276. begin
  3277. FDataPortProtection := Id_TIdFTP_DataPortProtection;
  3278. FUseCCC := DEF_Id_FTP_UseCCC;
  3279. FAUTHCmd := DEF_Id_FTP_AUTH_CMD;
  3280. end;
  3281. end;
  3282. procedure TIdFTP.SetUseCCC(const AValue: Boolean);
  3283. begin
  3284. if csLoading in ComponentState then
  3285. begin
  3286. FUseCCC := AValue;
  3287. exit;
  3288. end;
  3289. if FUseTLS=utNoTLSSupport then
  3290. begin
  3291. raise EIdFTPNoCCCWOEncryption.Create(RSFTPNoCCCWOEncryption);
  3292. end
  3293. else
  3294. begin
  3295. FUseCCC := AValue;
  3296. end;
  3297. end;
  3298. procedure TIdFTP.DoOnRetrievedDir;
  3299. begin
  3300. if Assigned(OnRetrievedDir) then
  3301. begin
  3302. OnRetrievedDir(Self);
  3303. end;
  3304. end;
  3305. procedure TIdFTP.DoOnDirParseEnd;
  3306. begin
  3307. if Assigned(FOnDirParseStart) then
  3308. begin
  3309. FOnDirParseStart(Self);
  3310. end;
  3311. end;
  3312. procedure TIdFTP.DoOnDirParseStart;
  3313. begin
  3314. if Assigned(FOnDirParseEnd) then
  3315. begin
  3316. FOnDirParseEnd(Self);
  3317. end;
  3318. end;
  3319. end.