ftpsend.pas 54 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969
  1. {==============================================================================|
  2. | Project : Ararat Synapse | 004.000.000 |
  3. |==============================================================================|
  4. | Content: FTP client |
  5. |==============================================================================|
  6. | Copyright (c)1999-2011, Lukas Gebauer |
  7. | All rights reserved. |
  8. | |
  9. | Redistribution and use in source and binary forms, with or without |
  10. | modification, are permitted provided that the following conditions are met: |
  11. | |
  12. | Redistributions of source code must retain the above copyright notice, this |
  13. | list of conditions and the following disclaimer. |
  14. | |
  15. | Redistributions in binary form must reproduce the above copyright notice, |
  16. | this list of conditions and the following disclaimer in the documentation |
  17. | and/or other materials provided with the distribution. |
  18. | |
  19. | Neither the name of Lukas Gebauer nor the names of its contributors may |
  20. | be used to endorse or promote products derived from this software without |
  21. | specific prior written permission. |
  22. | |
  23. | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
  24. | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
  25. | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
  26. | ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR |
  27. | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
  28. | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR |
  29. | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER |
  30. | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
  31. | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
  32. | OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH |
  33. | DAMAGE. |
  34. |==============================================================================|
  35. | The Initial Developer of the Original Code is Lukas Gebauer (Czech Republic).|
  36. | Portions created by Lukas Gebauer are Copyright (c) 1999-2010. |
  37. | All Rights Reserved. |
  38. |==============================================================================|
  39. | Contributor(s): |
  40. | Petr Esner <[email protected]> |
  41. |==============================================================================|
  42. | History: see HISTORY.HTM from distribution package |
  43. | (Found at URL: http://www.ararat.cz/synapse/) |
  44. |==============================================================================}
  45. {: @abstract(FTP client protocol)
  46. Used RFC: RFC-959, RFC-2228, RFC-2428
  47. }
  48. {$IFDEF FPC}
  49. {$MODE DELPHI}
  50. {$ENDIF}
  51. {$H+}
  52. {$TYPEINFO ON}// Borland changed defualt Visibility from Public to Published
  53. // and it requires RTTI to be generated $M+
  54. {$M+}
  55. {$IFDEF UNICODE}
  56. {$WARN IMPLICIT_STRING_CAST OFF}
  57. {$WARN IMPLICIT_STRING_CAST_LOSS OFF}
  58. {$ENDIF}
  59. unit ftpsend;
  60. interface
  61. uses
  62. SysUtils, Classes,
  63. blcksock, synautil, synaip, synsock;
  64. const
  65. cFtpProtocol = '21';
  66. cFtpDataProtocol = '20';
  67. {:Terminating value for TLogonActions}
  68. FTP_OK = 255;
  69. {:Terminating value for TLogonActions}
  70. FTP_ERR = 254;
  71. type
  72. {:Array for holding definition of logon sequence.}
  73. TLogonActions = array [0..17] of byte;
  74. {:Procedural type for OnStatus event. Sender is calling @link(TFTPSend) object.
  75. Value is FTP command or reply to this comand. (if it is reply, Response
  76. is @True).}
  77. TFTPStatus = procedure(Sender: TObject; Response: Boolean;
  78. const Value: string) of object;
  79. {: @abstract(Object for holding file information) parsed from directory
  80. listing of FTP server.}
  81. TFTPListRec = class(TObject)
  82. private
  83. FFileName: String;
  84. FDirectory: Boolean;
  85. FReadable: Boolean;
  86. FFileSize: int64;
  87. FFileTime: TDateTime;
  88. FOriginalLine: string;
  89. FMask: string;
  90. FPermission: String;
  91. public
  92. {: You can assign another TFTPListRec to this object.}
  93. procedure Assign(Value: TFTPListRec); virtual;
  94. {:name of file}
  95. property FileName: string read FFileName write FFileName;
  96. {:if name is subdirectory not file.}
  97. property Directory: Boolean read FDirectory write FDirectory;
  98. {:if you have rights to read}
  99. property Readable: Boolean read FReadable write FReadable;
  100. {:size of file in bytes}
  101. property FileSize: int64 read FFileSize write FFileSize;
  102. {:date and time of file. Local server timezone is used. Any timezone
  103. conversions was not done!}
  104. property FileTime: TDateTime read FFileTime write FFileTime;
  105. {:original unparsed line}
  106. property OriginalLine: string read FOriginalLine write FOriginalLine;
  107. {:mask what was used for parsing}
  108. property Mask: string read FMask write FMask;
  109. {:permission string (depending on used mask!)}
  110. property Permission: string read FPermission write FPermission;
  111. end;
  112. {:@abstract(This is TList of TFTPListRec objects.)
  113. This object is used for holding lististing of all files information in listed
  114. directory on FTP server.}
  115. TFTPList = class(TObject)
  116. protected
  117. FList: TList;
  118. FLines: TStringList;
  119. FMasks: TStringList;
  120. FUnparsedLines: TStringList;
  121. Monthnames: string;
  122. BlockSize: string;
  123. DirFlagValue: string;
  124. FileName: string;
  125. VMSFileName: string;
  126. Day: string;
  127. Month: string;
  128. ThreeMonth: string;
  129. YearTime: string;
  130. Year: string;
  131. Hours: string;
  132. HoursModif: Ansistring;
  133. Minutes: string;
  134. Seconds: string;
  135. Size: Ansistring;
  136. Permissions: Ansistring;
  137. DirFlag: string;
  138. function GetListItem(Index: integer): TFTPListRec; virtual;
  139. function ParseEPLF(Value: string): Boolean; virtual;
  140. procedure ClearStore; virtual;
  141. function ParseByMask(Value, NextValue, Mask: ansistring): Integer; virtual;
  142. function CheckValues: Boolean; virtual;
  143. procedure FillRecord(const Value: TFTPListRec); virtual;
  144. public
  145. {:Constructor. You not need create this object, it is created by TFTPSend
  146. class as their property.}
  147. constructor Create;
  148. destructor Destroy; override;
  149. {:Clear list.}
  150. procedure Clear; virtual;
  151. {:count of holded @link(TFTPListRec) objects}
  152. function Count: integer; virtual;
  153. {:Assigns one list to another}
  154. procedure Assign(Value: TFTPList); virtual;
  155. {:try to parse raw directory listing in @link(lines) to list of
  156. @link(TFTPListRec).}
  157. procedure ParseLines; virtual;
  158. {:By this property you have access to list of @link(TFTPListRec).
  159. This is for compatibility only. Please, use @link(Items) instead.}
  160. property List: TList read FList;
  161. {:By this property you have access to list of @link(TFTPListRec).}
  162. property Items[Index: Integer]: TFTPListRec read GetListItem; default;
  163. {:Set of lines with RAW directory listing for @link(parseLines)}
  164. property Lines: TStringList read FLines;
  165. {:Set of masks for directory listing parser. It is predefined by default,
  166. however you can modify it as you need. (for example, you can add your own
  167. definition mask.) Mask is same as mask used in TotalCommander.}
  168. property Masks: TStringList read FMasks;
  169. {:After @link(ParseLines) it holding lines what was not sucessfully parsed.}
  170. property UnparsedLines: TStringList read FUnparsedLines;
  171. end;
  172. {:@abstract(Implementation of FTP protocol.)
  173. Note: Are you missing properties for setting Username and Password? Look to
  174. parent @link(TSynaClient) object! (Username and Password have default values
  175. for "anonymous" FTP login)
  176. Are you missing properties for specify server address and port? Look to
  177. parent @link(TSynaClient) too!}
  178. TFTPSend = class(TSynaClient)
  179. protected
  180. FOnStatus: TFTPStatus;
  181. FSock: TTCPBlockSocket;
  182. FDSock: TTCPBlockSocket;
  183. FResultCode: Integer;
  184. FResultString: string;
  185. FFullResult: TStringList;
  186. FAccount: string;
  187. FFWHost: string;
  188. FFWPort: string;
  189. FFWUsername: string;
  190. FFWPassword: string;
  191. FFWMode: integer;
  192. FDataStream: TMemoryStream;
  193. FDataIP: string;
  194. FDataPort: string;
  195. FDirectFile: Boolean;
  196. FDirectFileName: string;
  197. FCanResume: Boolean;
  198. FPassiveMode: Boolean;
  199. FForceDefaultPort: Boolean;
  200. FForceOldPort: Boolean;
  201. FFtpList: TFTPList;
  202. FBinaryMode: Boolean;
  203. FAutoTLS: Boolean;
  204. FIsTLS: Boolean;
  205. FIsDataTLS: Boolean;
  206. FTLSonData: Boolean;
  207. FFullSSL: Boolean;
  208. function Auth(Mode: integer): Boolean; virtual;
  209. function Connect: Boolean; virtual;
  210. function InternalStor(const Command: string; RestoreAt: int64): Boolean; virtual;
  211. function DataSocket: Boolean; virtual;
  212. function AcceptDataSocket: Boolean; virtual;
  213. procedure DoStatus(Response: Boolean; const Value: string); virtual;
  214. public
  215. {:Custom definition of login sequence. You can use this when you set
  216. @link(FWMode) to value -1.}
  217. CustomLogon: TLogonActions;
  218. constructor Create;
  219. destructor Destroy; override;
  220. {:Waits and read FTP server response. You need this only in special cases!}
  221. function ReadResult: Integer; virtual;
  222. {:Parse remote side information of data channel from value string (returned
  223. by PASV command). This function you need only in special cases!}
  224. procedure ParseRemote(Value: string); virtual;
  225. {:Parse remote side information of data channel from value string (returned
  226. by EPSV command). This function you need only in special cases!}
  227. procedure ParseRemoteEPSV(Value: string); virtual;
  228. {:Send Value as FTP command to FTP server. Returned result code is result of
  229. this function.
  230. This command is good for sending site specific command, or non-standard
  231. commands.}
  232. function FTPCommand(const Value: string): integer; virtual;
  233. {:Connect and logon to FTP server. If you specify any FireWall, connect to
  234. firewall and throw them connect to FTP server. Login sequence depending on
  235. @link(FWMode).}
  236. function Login: Boolean; virtual;
  237. {:Logoff and disconnect from FTP server.}
  238. function Logout: Boolean; virtual;
  239. {:Break current transmission of data. (You can call this method from
  240. Sock.OnStatus event, or from another thread.)}
  241. procedure Abort; virtual;
  242. {:Break current transmission of data. It is same as Abort, but it send abort
  243. telnet commands prior ABOR FTP command. Some servers need it. (You can call
  244. this method from Sock.OnStatus event, or from another thread.)}
  245. procedure TelnetAbort; virtual;
  246. {:Download directory listing of Directory on FTP server. If Directory is
  247. empty string, download listing of current working directory.
  248. If NameList is @true, download only names of files in directory.
  249. (internally use NLST command instead LIST command)
  250. If NameList is @false, returned list is also parsed to @link(FTPList)
  251. property.}
  252. function List(Directory: string; NameList: Boolean): Boolean; virtual;
  253. {:Read data from FileName on FTP server. If Restore is @true and server
  254. supports resume dowloads, download is resumed. (received is only rest
  255. of file)}
  256. function RetrieveFile(const FileName: string; Restore: Boolean): Boolean; virtual;
  257. {:Send data to FileName on FTP server. If Restore is @true and server
  258. supports resume upload, upload is resumed. (send only rest of file)
  259. In this case if remote file is same length as local file, nothing will be
  260. done. If remote file is larger then local, resume is disabled and file is
  261. transfered from begin!}
  262. function StoreFile(const FileName: string; Restore: Boolean): Boolean; virtual;
  263. {:Send data to FTP server and assing unique name for this file.}
  264. function StoreUniqueFile: Boolean; virtual;
  265. {:Append data to FileName on FTP server.}
  266. function AppendFile(const FileName: string): Boolean; virtual;
  267. {:Rename on FTP server file with OldName to NewName.}
  268. function RenameFile(const OldName, NewName: string): Boolean; virtual;
  269. {:Delete file FileName on FTP server.}
  270. function DeleteFile(const FileName: string): Boolean; virtual;
  271. {:Return size of Filename file on FTP server. If command failed (i.e. not
  272. implemented), return -1.}
  273. function FileSize(const FileName: string): int64; virtual;
  274. {:Send NOOP command to FTP server for preserve of disconnect by inactivity
  275. timeout.}
  276. function NoOp: Boolean; virtual;
  277. {:Change currect working directory to Directory on FTP server.}
  278. function ChangeWorkingDir(const Directory: string): Boolean; virtual;
  279. {:walk to upper directory on FTP server.}
  280. function ChangeToParentDir: Boolean; virtual;
  281. {:walk to root directory on FTP server. (May not work with all servers properly!)}
  282. function ChangeToRootDir: Boolean; virtual;
  283. {:Delete Directory on FTP server.}
  284. function DeleteDir(const Directory: string): Boolean; virtual;
  285. {:Create Directory on FTP server.}
  286. function CreateDir(const Directory: string): Boolean; virtual;
  287. {:Return current working directory on FTP server.}
  288. function GetCurrentDir: String; virtual;
  289. {:Establish data channel to FTP server and retrieve data.
  290. This function you need only in special cases, i.e. when you need to implement
  291. some special unsupported FTP command!}
  292. function DataRead(const DestStream: TStream): Boolean; virtual;
  293. {:Establish data channel to FTP server and send data.
  294. This function you need only in special cases, i.e. when you need to implement
  295. some special unsupported FTP command.}
  296. function DataWrite(const SourceStream: TStream): Boolean; virtual;
  297. published
  298. {:After FTP command contains result number of this operation.}
  299. property ResultCode: Integer read FResultCode;
  300. {:After FTP command contains main line of result.}
  301. property ResultString: string read FResultString;
  302. {:After any FTP command it contains all lines of FTP server reply.}
  303. property FullResult: TStringList read FFullResult;
  304. {:Account information used in some cases inside login sequence.}
  305. property Account: string read FAccount Write FAccount;
  306. {:Address of firewall. If empty string (default), firewall not used.}
  307. property FWHost: string read FFWHost Write FFWHost;
  308. {:port of firewall. standard value is same port as ftp server used. (21)}
  309. property FWPort: string read FFWPort Write FFWPort;
  310. {:Username for login to firewall. (if needed)}
  311. property FWUsername: string read FFWUsername Write FFWUsername;
  312. {:password for login to firewall. (if needed)}
  313. property FWPassword: string read FFWPassword Write FFWPassword;
  314. {:Type of Firewall. Used only if you set some firewall address. Supported
  315. predefined firewall login sequences are described by comments in source
  316. file where you can see pseudocode decribing each sequence.}
  317. property FWMode: integer read FFWMode Write FFWMode;
  318. {:Socket object used for TCP/IP operation on control channel. Good for
  319. seting OnStatus hook, etc.}
  320. property Sock: TTCPBlockSocket read FSock;
  321. {:Socket object used for TCP/IP operation on data channel. Good for seting
  322. OnStatus hook, etc.}
  323. property DSock: TTCPBlockSocket read FDSock;
  324. {:If you not use @link(DirectFile) mode, all data transfers is made to or
  325. from this stream.}
  326. property DataStream: TMemoryStream read FDataStream;
  327. {:After data connection is established, contains remote side IP of this
  328. connection.}
  329. property DataIP: string read FDataIP;
  330. {:After data connection is established, contains remote side port of this
  331. connection.}
  332. property DataPort: string read FDataPort;
  333. {:Mode of data handling by data connection. If @False, all data operations
  334. are made to or from @link(DataStream) TMemoryStream.
  335. If @true, data operations is made directly to file in your disk. (filename
  336. is specified by @link(DirectFileName) property.) Dafault is @False!}
  337. property DirectFile: Boolean read FDirectFile Write FDirectFile;
  338. {:Filename for direct disk data operations.}
  339. property DirectFileName: string read FDirectFileName Write FDirectFileName;
  340. {:Indicate after @link(Login) if remote server support resume downloads and
  341. uploads.}
  342. property CanResume: Boolean read FCanResume;
  343. {:If true (default value), all transfers is made by passive method.
  344. It is safer method for various firewalls.}
  345. property PassiveMode: Boolean read FPassiveMode Write FPassiveMode;
  346. {:Force to listen for dataconnection on standard port (20). Default is @false,
  347. dataconnections will be made to any non-standard port reported by PORT FTP
  348. command. This setting is not used, if you use passive mode.}
  349. property ForceDefaultPort: Boolean read FForceDefaultPort Write FForceDefaultPort;
  350. {:When is @true, then is disabled EPSV and EPRT support. However without this
  351. commands you cannot use IPv6! (Disabling of this commands is needed only
  352. when you are behind some crap firewall/NAT.}
  353. property ForceOldPort: Boolean read FForceOldPort Write FForceOldPort;
  354. {:You may set this hook for monitoring FTP commands and replies.}
  355. property OnStatus: TFTPStatus read FOnStatus write FOnStatus;
  356. {:After LIST command is here parsed list of files in given directory.}
  357. property FtpList: TFTPList read FFtpList;
  358. {:if @true (default), then data transfers is in binary mode. If this is set
  359. to @false, then ASCII mode is used.}
  360. property BinaryMode: Boolean read FBinaryMode Write FBinaryMode;
  361. {:if is true, then if server support upgrade to SSL/TLS mode, then use them.}
  362. property AutoTLS: Boolean read FAutoTLS Write FAutoTLS;
  363. {:if server listen on SSL/TLS port, then you set this to true.}
  364. property FullSSL: Boolean read FFullSSL Write FFullSSL;
  365. {:Signalise, if control channel is in SSL/TLS mode.}
  366. property IsTLS: Boolean read FIsTLS;
  367. {:Signalise, if data transfers is in SSL/TLS mode.}
  368. property IsDataTLS: Boolean read FIsDataTLS;
  369. {:If @true (default), then try to use SSL/TLS on data transfers too.
  370. If @false, then SSL/TLS is used only for control connection.}
  371. property TLSonData: Boolean read FTLSonData write FTLSonData;
  372. end;
  373. {:A very useful function, and example of use can be found in the TFtpSend object.
  374. Dowload specified file from FTP server to LocalFile.}
  375. function FtpGetFile(const IP, Port, FileName, LocalFile,
  376. User, Pass: string): Boolean;
  377. {:A very useful function, and example of use can be found in the TFtpSend object.
  378. Upload specified LocalFile to FTP server.}
  379. function FtpPutFile(const IP, Port, FileName, LocalFile,
  380. User, Pass: string): Boolean;
  381. {:A very useful function, and example of use can be found in the TFtpSend object.
  382. Initiate transfer of file between two FTP servers.}
  383. function FtpInterServerTransfer(
  384. const FromIP, FromPort, FromFile, FromUser, FromPass: string;
  385. const ToIP, ToPort, ToFile, ToUser, ToPass: string): Boolean;
  386. implementation
  387. constructor TFTPSend.Create;
  388. begin
  389. inherited Create;
  390. FFullResult := TStringList.Create;
  391. FDataStream := TMemoryStream.Create;
  392. FSock := TTCPBlockSocket.Create;
  393. FSock.Owner := self;
  394. FSock.ConvertLineEnd := True;
  395. FDSock := TTCPBlockSocket.Create;
  396. FDSock.Owner := self;
  397. FFtpList := TFTPList.Create;
  398. FTimeout := 300000;
  399. FTargetPort := cFtpProtocol;
  400. FUsername := 'anonymous';
  401. FPassword := 'anonymous@' + FSock.LocalName;
  402. FDirectFile := False;
  403. FPassiveMode := True;
  404. FForceDefaultPort := False;
  405. FForceOldPort := false;
  406. FAccount := '';
  407. FFWHost := '';
  408. FFWPort := cFtpProtocol;
  409. FFWUsername := '';
  410. FFWPassword := '';
  411. FFWMode := 0;
  412. FBinaryMode := True;
  413. FAutoTLS := False;
  414. FFullSSL := False;
  415. FIsTLS := False;
  416. FIsDataTLS := False;
  417. FTLSonData := True;
  418. end;
  419. destructor TFTPSend.Destroy;
  420. begin
  421. FDSock.Free;
  422. FSock.Free;
  423. FFTPList.Free;
  424. FDataStream.Free;
  425. FFullResult.Free;
  426. inherited Destroy;
  427. end;
  428. procedure TFTPSend.DoStatus(Response: Boolean; const Value: string);
  429. begin
  430. if assigned(OnStatus) then
  431. OnStatus(Self, Response, Value);
  432. end;
  433. function TFTPSend.ReadResult: Integer;
  434. var
  435. s, c: AnsiString;
  436. begin
  437. FFullResult.Clear;
  438. c := '';
  439. repeat
  440. s := FSock.RecvString(FTimeout);
  441. if c = '' then
  442. if length(s) > 3 then
  443. if s[4] in [' ', '-'] then
  444. c :=Copy(s, 1, 3);
  445. FResultString := s;
  446. FFullResult.Add(s);
  447. DoStatus(True, s);
  448. if FSock.LastError <> 0 then
  449. Break;
  450. until (c <> '') and (Pos(c + ' ', s) = 1);
  451. Result := StrToIntDef(c, 0);
  452. FResultCode := Result;
  453. end;
  454. function TFTPSend.FTPCommand(const Value: string): integer;
  455. begin
  456. FSock.Purge;
  457. FSock.SendString(Value + CRLF);
  458. DoStatus(False, Value);
  459. Result := ReadResult;
  460. end;
  461. // based on idea by Petr Esner <[email protected]>
  462. function TFTPSend.Auth(Mode: integer): Boolean;
  463. const
  464. //if not USER <username> then
  465. // if not PASS <password> then
  466. // if not ACCT <account> then ERROR!
  467. //OK!
  468. Action0: TLogonActions =
  469. (0, FTP_OK, 3,
  470. 1, FTP_OK, 6,
  471. 2, FTP_OK, FTP_ERR,
  472. 0, 0, 0, 0, 0, 0, 0, 0, 0);
  473. //if not USER <FWusername> then
  474. // if not PASS <FWPassword> then ERROR!
  475. //if SITE <FTPServer> then ERROR!
  476. //if not USER <username> then
  477. // if not PASS <password> then
  478. // if not ACCT <account> then ERROR!
  479. //OK!
  480. Action1: TLogonActions =
  481. (3, 6, 3,
  482. 4, 6, FTP_ERR,
  483. 5, FTP_ERR, 9,
  484. 0, FTP_OK, 12,
  485. 1, FTP_OK, 15,
  486. 2, FTP_OK, FTP_ERR);
  487. //if not USER <FWusername> then
  488. // if not PASS <FWPassword> then ERROR!
  489. //if USER <UserName>'@'<FTPServer> then OK!
  490. //if not PASS <password> then
  491. // if not ACCT <account> then ERROR!
  492. //OK!
  493. Action2: TLogonActions =
  494. (3, 6, 3,
  495. 4, 6, FTP_ERR,
  496. 6, FTP_OK, 9,
  497. 1, FTP_OK, 12,
  498. 2, FTP_OK, FTP_ERR,
  499. 0, 0, 0);
  500. //if not USER <FWusername> then
  501. // if not PASS <FWPassword> then ERROR!
  502. //if not USER <username> then
  503. // if not PASS <password> then
  504. // if not ACCT <account> then ERROR!
  505. //OK!
  506. Action3: TLogonActions =
  507. (3, 6, 3,
  508. 4, 6, FTP_ERR,
  509. 0, FTP_OK, 9,
  510. 1, FTP_OK, 12,
  511. 2, FTP_OK, FTP_ERR,
  512. 0, 0, 0);
  513. //OPEN <FTPserver>
  514. //if not USER <username> then
  515. // if not PASS <password> then
  516. // if not ACCT <account> then ERROR!
  517. //OK!
  518. Action4: TLogonActions =
  519. (7, 3, 3,
  520. 0, FTP_OK, 6,
  521. 1, FTP_OK, 9,
  522. 2, FTP_OK, FTP_ERR,
  523. 0, 0, 0, 0, 0, 0);
  524. //if USER <UserName>'@'<FTPServer> then OK!
  525. //if not PASS <password> then
  526. // if not ACCT <account> then ERROR!
  527. //OK!
  528. Action5: TLogonActions =
  529. (6, FTP_OK, 3,
  530. 1, FTP_OK, 6,
  531. 2, FTP_OK, FTP_ERR,
  532. 0, 0, 0, 0, 0, 0, 0, 0, 0);
  533. //if not USER <FWUserName>@<FTPServer> then
  534. // if not PASS <FWPassword> then ERROR!
  535. //if not USER <username> then
  536. // if not PASS <password> then
  537. // if not ACCT <account> then ERROR!
  538. //OK!
  539. Action6: TLogonActions =
  540. (8, 6, 3,
  541. 4, 6, FTP_ERR,
  542. 0, FTP_OK, 9,
  543. 1, FTP_OK, 12,
  544. 2, FTP_OK, FTP_ERR,
  545. 0, 0, 0);
  546. //if USER <UserName>@<FTPServer> <FWUserName> then ERROR!
  547. //if not PASS <password> then
  548. // if not ACCT <account> then ERROR!
  549. //OK!
  550. Action7: TLogonActions =
  551. (9, FTP_ERR, 3,
  552. 1, FTP_OK, 6,
  553. 2, FTP_OK, FTP_ERR,
  554. 0, 0, 0, 0, 0, 0, 0, 0, 0);
  555. //if not USER <UserName>@<FWUserName>@<FTPServer> then
  556. // if not PASS <Password>@<FWPassword> then
  557. // if not ACCT <account> then ERROR!
  558. //OK!
  559. Action8: TLogonActions =
  560. (10, FTP_OK, 3,
  561. 11, FTP_OK, 6,
  562. 2, FTP_OK, FTP_ERR,
  563. 0, 0, 0, 0, 0, 0, 0, 0, 0);
  564. var
  565. FTPServer: string;
  566. LogonActions: TLogonActions;
  567. i: integer;
  568. s: string;
  569. x: integer;
  570. begin
  571. Result := False;
  572. if FFWHost = '' then
  573. Mode := 0;
  574. if (FTargetPort = cFtpProtocol) or (FTargetPort = '21') then
  575. FTPServer := FTargetHost
  576. else
  577. FTPServer := FTargetHost + ':' + FTargetPort;
  578. case Mode of
  579. -1:
  580. LogonActions := CustomLogon;
  581. 1:
  582. LogonActions := Action1;
  583. 2:
  584. LogonActions := Action2;
  585. 3:
  586. LogonActions := Action3;
  587. 4:
  588. LogonActions := Action4;
  589. 5:
  590. LogonActions := Action5;
  591. 6:
  592. LogonActions := Action6;
  593. 7:
  594. LogonActions := Action7;
  595. 8:
  596. LogonActions := Action8;
  597. else
  598. LogonActions := Action0;
  599. end;
  600. i := 0;
  601. repeat
  602. case LogonActions[i] of
  603. 0: s := 'USER ' + FUserName;
  604. 1: s := 'PASS ' + FPassword;
  605. 2: s := 'ACCT ' + FAccount;
  606. 3: s := 'USER ' + FFWUserName;
  607. 4: s := 'PASS ' + FFWPassword;
  608. 5: s := 'SITE ' + FTPServer;
  609. 6: s := 'USER ' + FUserName + '@' + FTPServer;
  610. 7: s := 'OPEN ' + FTPServer;
  611. 8: s := 'USER ' + FFWUserName + '@' + FTPServer;
  612. 9: s := 'USER ' + FUserName + '@' + FTPServer + ' ' + FFWUserName;
  613. 10: s := 'USER ' + FUserName + '@' + FFWUserName + '@' + FTPServer;
  614. 11: s := 'PASS ' + FPassword + '@' + FFWPassword;
  615. end;
  616. x := FTPCommand(s);
  617. x := x div 100;
  618. if (x <> 2) and (x <> 3) then
  619. Exit;
  620. i := LogonActions[i + x - 1];
  621. case i of
  622. FTP_ERR:
  623. Exit;
  624. FTP_OK:
  625. begin
  626. Result := True;
  627. Exit;
  628. end;
  629. end;
  630. until False;
  631. end;
  632. function TFTPSend.Connect: Boolean;
  633. begin
  634. FSock.CloseSocket;
  635. FSock.Bind(FIPInterface, cAnyPort);
  636. if FSock.LastError = 0 then
  637. if FFWHost = '' then
  638. FSock.Connect(FTargetHost, FTargetPort)
  639. else
  640. FSock.Connect(FFWHost, FFWPort);
  641. if FSock.LastError = 0 then
  642. if FFullSSL then
  643. FSock.SSLDoConnect;
  644. Result := FSock.LastError = 0;
  645. end;
  646. function TFTPSend.Login: Boolean;
  647. var
  648. x: integer;
  649. begin
  650. Result := False;
  651. FCanResume := False;
  652. if not Connect then
  653. Exit;
  654. FIsTLS := FFullSSL;
  655. FIsDataTLS := False;
  656. repeat
  657. x := ReadResult div 100;
  658. until x <> 1;
  659. if x <> 2 then
  660. Exit;
  661. if FAutoTLS and not(FIsTLS) then
  662. if (FTPCommand('AUTH TLS') div 100) = 2 then
  663. begin
  664. FSock.SSLDoConnect;
  665. FIsTLS := FSock.LastError = 0;
  666. if not FIsTLS then
  667. begin
  668. Result := False;
  669. Exit;
  670. end;
  671. end;
  672. if not Auth(FFWMode) then
  673. Exit;
  674. if FIsTLS then
  675. begin
  676. FTPCommand('PBSZ 0');
  677. if FTLSonData then
  678. FIsDataTLS := (FTPCommand('PROT P') div 100) = 2;
  679. if not FIsDataTLS then
  680. FTPCommand('PROT C');
  681. end;
  682. FTPCommand('TYPE I');
  683. FTPCommand('STRU F');
  684. FTPCommand('MODE S');
  685. if FTPCommand('REST 0') = 350 then
  686. if FTPCommand('REST 1') = 350 then
  687. begin
  688. FTPCommand('REST 0');
  689. FCanResume := True;
  690. end;
  691. Result := True;
  692. end;
  693. function TFTPSend.Logout: Boolean;
  694. begin
  695. Result := (FTPCommand('QUIT') div 100) = 2;
  696. FSock.CloseSocket;
  697. end;
  698. procedure TFTPSend.ParseRemote(Value: string);
  699. var
  700. n: integer;
  701. nb, ne: integer;
  702. s: string;
  703. x: integer;
  704. begin
  705. Value := trim(Value);
  706. nb := Pos('(',Value);
  707. ne := Pos(')',Value);
  708. if (nb = 0) or (ne = 0) then
  709. begin
  710. nb:=RPos(' ',Value);
  711. s:=Copy(Value, nb + 1, Length(Value) - nb);
  712. end
  713. else
  714. begin
  715. s:=Copy(Value,nb+1,ne-nb-1);
  716. end;
  717. for n := 1 to 4 do
  718. if n = 1 then
  719. FDataIP := Fetch(s, ',')
  720. else
  721. FDataIP := FDataIP + '.' + Fetch(s, ',');
  722. x := StrToIntDef(Fetch(s, ','), 0) * 256;
  723. x := x + StrToIntDef(Fetch(s, ','), 0);
  724. FDataPort := IntToStr(x);
  725. end;
  726. procedure TFTPSend.ParseRemoteEPSV(Value: string);
  727. var
  728. n: integer;
  729. s, v: AnsiString;
  730. begin
  731. s := SeparateRight(Value, '(');
  732. s := Trim(SeparateLeft(s, ')'));
  733. Delete(s, Length(s), 1);
  734. v := '';
  735. for n := Length(s) downto 1 do
  736. if s[n] in ['0'..'9'] then
  737. v := s[n] + v
  738. else
  739. Break;
  740. FDataPort := v;
  741. FDataIP := FTargetHost;
  742. end;
  743. function TFTPSend.DataSocket: boolean;
  744. var
  745. s: string;
  746. begin
  747. Result := False;
  748. if FIsDataTLS then
  749. FPassiveMode := True;
  750. if FPassiveMode then
  751. begin
  752. if FSock.IP6used then
  753. s := '2'
  754. else
  755. s := '1';
  756. if FSock.IP6used and not(FForceOldPort) and ((FTPCommand('EPSV ' + s) div 100) = 2) then
  757. begin
  758. ParseRemoteEPSV(FResultString);
  759. end
  760. else
  761. if FSock.IP6used then
  762. Exit
  763. else
  764. begin
  765. if (FTPCommand('PASV') div 100) <> 2 then
  766. Exit;
  767. ParseRemote(FResultString);
  768. end;
  769. FDSock.CloseSocket;
  770. FDSock.Bind(FIPInterface, cAnyPort);
  771. if FIsDataTLS then begin
  772. FDSock.SSL.Session := FSock.SSL.Session;
  773. end;
  774. FDSock.Connect(FDataIP, FDataPort);
  775. Result := FDSock.LastError = 0;
  776. end
  777. else
  778. begin
  779. FDSock.CloseSocket;
  780. if FForceDefaultPort then
  781. s := cFtpDataProtocol
  782. else
  783. s := '0';
  784. //data conection from same interface as command connection
  785. FDSock.Bind(FSock.GetLocalSinIP, s);
  786. if FDSock.LastError <> 0 then
  787. Exit;
  788. FDSock.SetLinger(True, 10000);
  789. FDSock.Listen;
  790. FDSock.GetSins;
  791. FDataIP := FDSock.GetLocalSinIP;
  792. FDataIP := FDSock.ResolveName(FDataIP);
  793. FDataPort := IntToStr(FDSock.GetLocalSinPort);
  794. if FSock.IP6used and (not FForceOldPort) then
  795. begin
  796. if IsIp6(FDataIP) then
  797. s := '2'
  798. else
  799. s := '1';
  800. s := 'EPRT |' + s +'|' + FDataIP + '|' + FDataPort + '|';
  801. Result := (FTPCommand(s) div 100) = 2;
  802. end;
  803. if not Result and IsIP(FDataIP) then
  804. begin
  805. s := ReplaceString(FDataIP, '.', ',');
  806. s := 'PORT ' + s + ',' + IntToStr(FDSock.GetLocalSinPort div 256)
  807. + ',' + IntToStr(FDSock.GetLocalSinPort mod 256);
  808. Result := (FTPCommand(s) div 100) = 2;
  809. end;
  810. end;
  811. end;
  812. function TFTPSend.AcceptDataSocket: Boolean;
  813. var
  814. x: TSocket;
  815. begin
  816. if FPassiveMode then
  817. Result := True
  818. else
  819. begin
  820. Result := False;
  821. if FDSock.CanRead(FTimeout) then
  822. begin
  823. x := FDSock.Accept;
  824. if not FDSock.UsingSocks then
  825. FDSock.CloseSocket;
  826. FDSock.Socket := x;
  827. Result := True;
  828. end;
  829. end;
  830. if Result and FIsDataTLS then
  831. begin
  832. FDSock.SSL.Assign(FSock.SSL);
  833. FDSock.SSLDoConnect;
  834. Result := FDSock.LastError = 0;
  835. end;
  836. end;
  837. function TFTPSend.DataRead(const DestStream: TStream): Boolean;
  838. var
  839. x: integer;
  840. begin
  841. Result := False;
  842. try
  843. if not AcceptDataSocket then
  844. Exit;
  845. FDSock.RecvStreamRaw(DestStream, FTimeout);
  846. FDSock.CloseSocket;
  847. x := ReadResult;
  848. Result := (x div 100) = 2;
  849. finally
  850. FDSock.CloseSocket;
  851. end;
  852. end;
  853. function TFTPSend.DataWrite(const SourceStream: TStream): Boolean;
  854. var
  855. x: integer;
  856. b: Boolean;
  857. begin
  858. Result := False;
  859. try
  860. if not AcceptDataSocket then
  861. Exit;
  862. FDSock.SendStreamRaw(SourceStream);
  863. b := FDSock.LastError = 0;
  864. FDSock.CloseSocket;
  865. x := ReadResult;
  866. Result := b and ((x div 100) = 2);
  867. finally
  868. FDSock.CloseSocket;
  869. end;
  870. end;
  871. function TFTPSend.List(Directory: string; NameList: Boolean): Boolean;
  872. var
  873. x: integer;
  874. begin
  875. Result := False;
  876. FDataStream.Clear;
  877. FFTPList.Clear;
  878. if Directory <> '' then
  879. Directory := ' ' + Directory;
  880. FTPCommand('TYPE A');
  881. if not DataSocket then
  882. Exit;
  883. if NameList then
  884. x := FTPCommand('NLST' + Directory)
  885. else
  886. x := FTPCommand('LIST' + Directory);
  887. if (x div 100) <> 1 then
  888. Exit;
  889. Result := DataRead(FDataStream);
  890. if (not NameList) and Result then
  891. begin
  892. FDataStream.Position := 0;
  893. FFTPList.Lines.LoadFromStream(FDataStream);
  894. FFTPList.ParseLines;
  895. end;
  896. FDataStream.Position := 0;
  897. end;
  898. function TFTPSend.RetrieveFile(const FileName: string; Restore: Boolean): Boolean;
  899. var
  900. RetrStream: TStream;
  901. begin
  902. Result := False;
  903. if FileName = '' then
  904. Exit;
  905. if not DataSocket then
  906. Exit;
  907. Restore := Restore and FCanResume;
  908. if FDirectFile then
  909. if Restore and FileExists(FDirectFileName) then
  910. RetrStream := TFileStream.Create(FDirectFileName,
  911. fmOpenReadWrite or fmShareExclusive)
  912. else
  913. RetrStream := TFileStream.Create(FDirectFileName,
  914. fmCreate or fmShareDenyWrite)
  915. else
  916. RetrStream := FDataStream;
  917. try
  918. if FBinaryMode then
  919. FTPCommand('TYPE I')
  920. else
  921. FTPCommand('TYPE A');
  922. if Restore then
  923. begin
  924. RetrStream.Position := RetrStream.Size;
  925. if (FTPCommand('REST ' + IntToStr(RetrStream.Size)) div 100) <> 3 then
  926. Exit;
  927. end
  928. else
  929. if RetrStream is TMemoryStream then
  930. TMemoryStream(RetrStream).Clear;
  931. if (FTPCommand('RETR ' + FileName) div 100) <> 1 then
  932. Exit;
  933. Result := DataRead(RetrStream);
  934. if not FDirectFile then
  935. RetrStream.Position := 0;
  936. finally
  937. if FDirectFile then
  938. RetrStream.Free;
  939. end;
  940. end;
  941. function TFTPSend.InternalStor(const Command: string; RestoreAt: int64): Boolean;
  942. var
  943. SendStream: TStream;
  944. StorSize: int64;
  945. begin
  946. Result := False;
  947. if FDirectFile then
  948. if not FileExists(FDirectFileName) then
  949. Exit
  950. else
  951. SendStream := TFileStream.Create(FDirectFileName,
  952. fmOpenRead or fmShareDenyWrite)
  953. else
  954. SendStream := FDataStream;
  955. try
  956. if not DataSocket then
  957. Exit;
  958. if FBinaryMode then
  959. FTPCommand('TYPE I')
  960. else
  961. FTPCommand('TYPE A');
  962. StorSize := SendStream.Size;
  963. if not FCanResume then
  964. RestoreAt := 0;
  965. if (StorSize > 0) and (RestoreAt = StorSize) then
  966. begin
  967. Result := True;
  968. Exit;
  969. end;
  970. if RestoreAt > StorSize then
  971. RestoreAt := 0;
  972. FTPCommand('ALLO ' + IntToStr(StorSize - RestoreAt));
  973. if FCanResume then
  974. if (FTPCommand('REST ' + IntToStr(RestoreAt)) div 100) <> 3 then
  975. Exit;
  976. SendStream.Position := RestoreAt;
  977. if (FTPCommand(Command) div 100) <> 1 then
  978. Exit;
  979. Result := DataWrite(SendStream);
  980. finally
  981. if FDirectFile then
  982. SendStream.Free;
  983. end;
  984. end;
  985. function TFTPSend.StoreFile(const FileName: string; Restore: Boolean): Boolean;
  986. var
  987. RestoreAt: int64;
  988. begin
  989. Result := False;
  990. if FileName = '' then
  991. Exit;
  992. RestoreAt := 0;
  993. Restore := Restore and FCanResume;
  994. if Restore then
  995. begin
  996. RestoreAt := Self.FileSize(FileName);
  997. if RestoreAt < 0 then
  998. RestoreAt := 0;
  999. end;
  1000. Result := InternalStor('STOR ' + FileName, RestoreAt);
  1001. end;
  1002. function TFTPSend.StoreUniqueFile: Boolean;
  1003. begin
  1004. Result := InternalStor('STOU', 0);
  1005. end;
  1006. function TFTPSend.AppendFile(const FileName: string): Boolean;
  1007. begin
  1008. Result := False;
  1009. if FileName = '' then
  1010. Exit;
  1011. Result := InternalStor('APPE ' + FileName, 0);
  1012. end;
  1013. function TFTPSend.NoOp: Boolean;
  1014. begin
  1015. Result := (FTPCommand('NOOP') div 100) = 2;
  1016. end;
  1017. function TFTPSend.RenameFile(const OldName, NewName: string): Boolean;
  1018. begin
  1019. Result := False;
  1020. if (FTPCommand('RNFR ' + OldName) div 100) <> 3 then
  1021. Exit;
  1022. Result := (FTPCommand('RNTO ' + NewName) div 100) = 2;
  1023. end;
  1024. function TFTPSend.DeleteFile(const FileName: string): Boolean;
  1025. begin
  1026. Result := (FTPCommand('DELE ' + FileName) div 100) = 2;
  1027. end;
  1028. function TFTPSend.FileSize(const FileName: string): int64;
  1029. var
  1030. s: string;
  1031. begin
  1032. Result := -1;
  1033. if (FTPCommand('SIZE ' + FileName) div 100) = 2 then
  1034. begin
  1035. s := Trim(SeparateRight(ResultString, ' '));
  1036. s := Trim(SeparateLeft(s, ' '));
  1037. {$IFDEF VER100}
  1038. Result := StrToIntDef(s, -1);
  1039. {$ELSE}
  1040. Result := StrToInt64Def(s, -1);
  1041. {$ENDIF}
  1042. end;
  1043. end;
  1044. function TFTPSend.ChangeWorkingDir(const Directory: string): Boolean;
  1045. begin
  1046. Result := (FTPCommand('CWD ' + Directory) div 100) = 2;
  1047. end;
  1048. function TFTPSend.ChangeToParentDir: Boolean;
  1049. begin
  1050. Result := (FTPCommand('CDUP') div 100) = 2;
  1051. end;
  1052. function TFTPSend.ChangeToRootDir: Boolean;
  1053. begin
  1054. Result := ChangeWorkingDir('/');
  1055. end;
  1056. function TFTPSend.DeleteDir(const Directory: string): Boolean;
  1057. begin
  1058. Result := (FTPCommand('RMD ' + Directory) div 100) = 2;
  1059. end;
  1060. function TFTPSend.CreateDir(const Directory: string): Boolean;
  1061. begin
  1062. Result := (FTPCommand('MKD ' + Directory) div 100) = 2;
  1063. end;
  1064. function TFTPSend.GetCurrentDir: String;
  1065. begin
  1066. Result := '';
  1067. if (FTPCommand('PWD') div 100) = 2 then
  1068. begin
  1069. Result := SeparateRight(FResultString, '"');
  1070. Result := Trim(Separateleft(Result, '"'));
  1071. end;
  1072. end;
  1073. procedure TFTPSend.Abort;
  1074. begin
  1075. FSock.SendString('ABOR' + CRLF);
  1076. FDSock.StopFlag := True;
  1077. end;
  1078. procedure TFTPSend.TelnetAbort;
  1079. begin
  1080. FSock.SendString(#$FF + #$F4 + #$FF + #$F2);
  1081. Abort;
  1082. end;
  1083. {==============================================================================}
  1084. procedure TFTPListRec.Assign(Value: TFTPListRec);
  1085. begin
  1086. FFileName := Value.FileName;
  1087. FDirectory := Value.Directory;
  1088. FReadable := Value.Readable;
  1089. FFileSize := Value.FileSize;
  1090. FFileTime := Value.FileTime;
  1091. FOriginalLine := Value.OriginalLine;
  1092. FMask := Value.Mask;
  1093. end;
  1094. constructor TFTPList.Create;
  1095. begin
  1096. inherited Create;
  1097. FList := TList.Create;
  1098. FLines := TStringList.Create;
  1099. FMasks := TStringList.Create;
  1100. FUnparsedLines := TStringList.Create;
  1101. //various UNIX
  1102. FMasks.add('pppppppppp $!!!S*$TTT$DD$hh mm ss$YYYY$n*');
  1103. FMasks.add('pppppppppp $!!!S*$DD$TTT$hh mm ss$YYYY$n*');
  1104. FMasks.add('pppppppppp $!!!S*$TTT$DD$UUUUU$n*'); //mostly used UNIX format
  1105. FMasks.add('pppppppppp $!!!S*$DD$TTT$UUUUU$n*');
  1106. //MacOS
  1107. FMasks.add('pppppppppp $!!S*$TTT$DD$UUUUU$n*');
  1108. FMasks.add('pppppppppp $!S*$TTT$DD$UUUUU$n*');
  1109. //Novell
  1110. FMasks.add('d $!S*$TTT$DD$UUUUU$n*');
  1111. //Windows
  1112. FMasks.add('MM DD YY hh mmH !S* n*');
  1113. FMasks.add('MM DD YY hh mmH $ d!n*');
  1114. FMasks.add('MM DD YYYY hh mmH !S* n*');
  1115. FMasks.add('MM DD YYYY hh mmH $ d!n*');
  1116. FMasks.add('DD MM YYYY hh mmH !S* n*');
  1117. FMasks.add('DD MM YYYY hh mmH $ d!n*');
  1118. //VMS
  1119. FMasks.add('v*$ DD TTT YYYY hh mm');
  1120. FMasks.add('v*$!DD TTT YYYY hh mm');
  1121. FMasks.add('n*$ YYYY MM DD hh mm$S*');
  1122. //AS400
  1123. FMasks.add('!S*$MM DD YY hh mm ss !n*');
  1124. FMasks.add('!S*$DD MM YY hh mm ss !n*');
  1125. FMasks.add('n*!S*$MM DD YY hh mm ss d');
  1126. FMasks.add('n*!S*$DD MM YY hh mm ss d');
  1127. //VxWorks
  1128. FMasks.add('$S* TTT DD YYYY hh mm ss $n* $ d');
  1129. FMasks.add('$S* TTT DD YYYY hh mm ss $n*');
  1130. //Distinct
  1131. FMasks.add('d $S*$TTT DD YYYY hh mm$n*');
  1132. FMasks.add('d $S*$TTT DD$hh mm$n*');
  1133. //PC-NFSD
  1134. FMasks.add('nnnnnnnn.nnn dSSSSSSSSSSS MM DD YY hh mmH');
  1135. //VOS
  1136. FMasks.add('- SSSSS YY MM DD hh mm ss n*');
  1137. FMasks.add('- d= SSSSS YY MM DD hh mm ss n*');
  1138. //Unissys ClearPath
  1139. FMasks.add('nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn SSSSSSSSS MM DD YYYY hh mm');
  1140. FMasks.add('n*\x SSSSSSSSS MM DD YYYY hh mm');
  1141. //IBM
  1142. FMasks.add('- SSSSSSSSSSSS d MM DD YYYY hh mm n*');
  1143. //OS9
  1144. FMasks.add('- YY MM DD hhmm d SSSSSSSSS n*');
  1145. //tandem
  1146. FMasks.add('nnnnnnnn SSSSSSS DD TTT YY hh mm ss');
  1147. //MVS
  1148. FMasks.add('- YYYY MM DD SSSSS d=O n*');
  1149. //BullGCOS8
  1150. FMasks.add(' $S* MM DD YY hh mm ss !n*');
  1151. FMasks.add('d $S* MM DD YY !n*');
  1152. //BullGCOS7
  1153. FMasks.add(' TTT DD YYYY n*');
  1154. FMasks.add(' d n*');
  1155. end;
  1156. destructor TFTPList.Destroy;
  1157. begin
  1158. Clear;
  1159. FList.Free;
  1160. FLines.Free;
  1161. FMasks.Free;
  1162. FUnparsedLines.Free;
  1163. inherited Destroy;
  1164. end;
  1165. procedure TFTPList.Clear;
  1166. var
  1167. n:integer;
  1168. begin
  1169. for n := 0 to FList.Count - 1 do
  1170. if Assigned(FList[n]) then
  1171. TFTPListRec(FList[n]).Free;
  1172. FList.Clear;
  1173. FLines.Clear;
  1174. FUnparsedLines.Clear;
  1175. end;
  1176. function TFTPList.Count: integer;
  1177. begin
  1178. Result := FList.Count;
  1179. end;
  1180. function TFTPList.GetListItem(Index: integer): TFTPListRec;
  1181. begin
  1182. Result := nil;
  1183. if Index < Count then
  1184. Result := TFTPListRec(FList[Index]);
  1185. end;
  1186. procedure TFTPList.Assign(Value: TFTPList);
  1187. var
  1188. flr: TFTPListRec;
  1189. n: integer;
  1190. begin
  1191. Clear;
  1192. for n := 0 to Value.Count - 1 do
  1193. begin
  1194. flr := TFTPListRec.Create;
  1195. flr.Assign(Value[n]);
  1196. Flist.Add(flr);
  1197. end;
  1198. Lines.Assign(Value.Lines);
  1199. Masks.Assign(Value.Masks);
  1200. UnparsedLines.Assign(Value.UnparsedLines);
  1201. end;
  1202. procedure TFTPList.ClearStore;
  1203. begin
  1204. Monthnames := '';
  1205. BlockSize := '';
  1206. DirFlagValue := '';
  1207. FileName := '';
  1208. VMSFileName := '';
  1209. Day := '';
  1210. Month := '';
  1211. ThreeMonth := '';
  1212. YearTime := '';
  1213. Year := '';
  1214. Hours := '';
  1215. HoursModif := '';
  1216. Minutes := '';
  1217. Seconds := '';
  1218. Size := '';
  1219. Permissions := '';
  1220. DirFlag := '';
  1221. end;
  1222. function TFTPList.ParseByMask(Value, NextValue, Mask: AnsiString): Integer;
  1223. var
  1224. Ivalue, IMask: integer;
  1225. MaskC, LastMaskC: AnsiChar;
  1226. c: AnsiChar;
  1227. s: string;
  1228. begin
  1229. ClearStore;
  1230. Result := 0;
  1231. if Value = '' then
  1232. Exit;
  1233. if Mask = '' then
  1234. Exit;
  1235. Ivalue := 1;
  1236. IMask := 1;
  1237. Result := 1;
  1238. LastMaskC := ' ';
  1239. while Imask <= Length(mask) do
  1240. begin
  1241. if (Mask[Imask] <> '*') and (Ivalue > Length(Value)) then
  1242. begin
  1243. Result := 0;
  1244. Exit;
  1245. end;
  1246. MaskC := Mask[Imask];
  1247. if Ivalue > Length(Value) then
  1248. Exit;
  1249. c := Value[Ivalue];
  1250. case MaskC of
  1251. 'n':
  1252. FileName := FileName + c;
  1253. 'v':
  1254. VMSFileName := VMSFileName + c;
  1255. '.':
  1256. begin
  1257. if c in ['.', ' '] then
  1258. FileName := TrimSP(FileName) + '.'
  1259. else
  1260. begin
  1261. Result := 0;
  1262. Exit;
  1263. end;
  1264. end;
  1265. 'D':
  1266. Day := Day + c;
  1267. 'M':
  1268. Month := Month + c;
  1269. 'T':
  1270. ThreeMonth := ThreeMonth + c;
  1271. 'U':
  1272. YearTime := YearTime + c;
  1273. 'Y':
  1274. Year := Year + c;
  1275. 'h':
  1276. Hours := Hours + c;
  1277. 'H':
  1278. HoursModif := HoursModif + c;
  1279. 'm':
  1280. Minutes := Minutes + c;
  1281. 's':
  1282. Seconds := Seconds + c;
  1283. 'S':
  1284. Size := Size + c;
  1285. 'p':
  1286. Permissions := Permissions + c;
  1287. 'd':
  1288. DirFlag := DirFlag + c;
  1289. 'x':
  1290. if c <> ' ' then
  1291. begin
  1292. Result := 0;
  1293. Exit;
  1294. end;
  1295. '*':
  1296. begin
  1297. s := '';
  1298. if LastMaskC in ['n', 'v'] then
  1299. begin
  1300. if Imask = Length(Mask) then
  1301. s := Copy(Value, IValue, Maxint)
  1302. else
  1303. while IValue <= Length(Value) do
  1304. begin
  1305. if Value[Ivalue] = ' ' then
  1306. break;
  1307. s := s + Value[Ivalue];
  1308. Inc(Ivalue);
  1309. end;
  1310. if LastMaskC = 'n' then
  1311. FileName := FileName + s
  1312. else
  1313. VMSFileName := VMSFileName + s;
  1314. end
  1315. else
  1316. begin
  1317. while IValue <= Length(Value) do
  1318. begin
  1319. if not(Value[Ivalue] in ['0'..'9']) then
  1320. break;
  1321. s := s + Value[Ivalue];
  1322. Inc(Ivalue);
  1323. end;
  1324. case LastMaskC of
  1325. 'S':
  1326. Size := Size + s;
  1327. end;
  1328. end;
  1329. Dec(IValue);
  1330. end;
  1331. '!':
  1332. begin
  1333. while IValue <= Length(Value) do
  1334. begin
  1335. if Value[Ivalue] = ' ' then
  1336. break;
  1337. Inc(Ivalue);
  1338. end;
  1339. while IValue <= Length(Value) do
  1340. begin
  1341. if Value[Ivalue] <> ' ' then
  1342. break;
  1343. Inc(Ivalue);
  1344. end;
  1345. Dec(IValue);
  1346. end;
  1347. '$':
  1348. begin
  1349. while IValue <= Length(Value) do
  1350. begin
  1351. if not(Value[Ivalue] in [' ', #9]) then
  1352. break;
  1353. Inc(Ivalue);
  1354. end;
  1355. Dec(IValue);
  1356. end;
  1357. '=':
  1358. begin
  1359. s := '';
  1360. case LastmaskC of
  1361. 'S':
  1362. begin
  1363. while Imask <= Length(Mask) do
  1364. begin
  1365. if not(Mask[Imask] in ['0'..'9']) then
  1366. break;
  1367. s := s + Mask[Imask];
  1368. Inc(Imask);
  1369. end;
  1370. Dec(Imask);
  1371. BlockSize := s;
  1372. end;
  1373. 'T':
  1374. begin
  1375. Monthnames := Copy(Mask, IMask, 12 * 3);
  1376. Inc(IMask, 12 * 3);
  1377. end;
  1378. 'd':
  1379. begin
  1380. Inc(Imask);
  1381. DirFlagValue := Mask[Imask];
  1382. end;
  1383. end;
  1384. end;
  1385. '\':
  1386. begin
  1387. Value := NextValue;
  1388. IValue := 0;
  1389. Result := 2;
  1390. end;
  1391. end;
  1392. Inc(Ivalue);
  1393. Inc(Imask);
  1394. LastMaskC := MaskC;
  1395. end;
  1396. end;
  1397. function TFTPList.CheckValues: Boolean;
  1398. var
  1399. x, n: integer;
  1400. begin
  1401. Result := false;
  1402. if FileName <> '' then
  1403. begin
  1404. if pos('?', VMSFilename) > 0 then
  1405. Exit;
  1406. if pos('*', VMSFilename) > 0 then
  1407. Exit;
  1408. end;
  1409. if VMSFileName <> '' then
  1410. if pos(';', VMSFilename) <= 0 then
  1411. Exit;
  1412. if (FileName = '') and (VMSFileName = '') then
  1413. Exit;
  1414. if Permissions <> '' then
  1415. begin
  1416. if length(Permissions) <> 10 then
  1417. Exit;
  1418. for n := 1 to 10 do
  1419. if not(Permissions[n] in
  1420. ['a', 'b', 'c', 'd', 'h', 'l', 'p', 'r', 's', 't', 'w', 'x', 'y', '-']) then
  1421. Exit;
  1422. end;
  1423. if Day <> '' then
  1424. begin
  1425. Day := TrimSP(Day);
  1426. x := StrToIntDef(day, -1);
  1427. if (x < 1) or (x > 31) then
  1428. Exit;
  1429. end;
  1430. if Month <> '' then
  1431. begin
  1432. Month := TrimSP(Month);
  1433. x := StrToIntDef(Month, -1);
  1434. if (x < 1) or (x > 12) then
  1435. Exit;
  1436. end;
  1437. if Hours <> '' then
  1438. begin
  1439. Hours := TrimSP(Hours);
  1440. x := StrToIntDef(Hours, -1);
  1441. if (x < 0) or (x > 24) then
  1442. Exit;
  1443. end;
  1444. if HoursModif <> '' then
  1445. begin
  1446. if not (HoursModif[1] in ['a', 'A', 'p', 'P']) then
  1447. Exit;
  1448. end;
  1449. if Minutes <> '' then
  1450. begin
  1451. Minutes := TrimSP(Minutes);
  1452. x := StrToIntDef(Minutes, -1);
  1453. if (x < 0) or (x > 59) then
  1454. Exit;
  1455. end;
  1456. if Seconds <> '' then
  1457. begin
  1458. Seconds := TrimSP(Seconds);
  1459. x := StrToIntDef(Seconds, -1);
  1460. if (x < 0) or (x > 59) then
  1461. Exit;
  1462. end;
  1463. if Size <> '' then
  1464. begin
  1465. Size := TrimSP(Size);
  1466. for n := 1 to Length(Size) do
  1467. if not (Size[n] in ['0'..'9']) then
  1468. Exit;
  1469. end;
  1470. if length(Monthnames) = (12 * 3) then
  1471. for n := 1 to 12 do
  1472. CustomMonthNames[n] := Copy(Monthnames, ((n - 1) * 3) + 1, 3);
  1473. if ThreeMonth <> '' then
  1474. begin
  1475. x := GetMonthNumber(ThreeMonth);
  1476. if (x = 0) then
  1477. Exit;
  1478. end;
  1479. if YearTime <> '' then
  1480. begin
  1481. YearTime := ReplaceString(YearTime, '-', ':');
  1482. if pos(':', YearTime) > 0 then
  1483. begin
  1484. if (GetTimeFromstr(YearTime) = -1) then
  1485. Exit;
  1486. end
  1487. else
  1488. begin
  1489. YearTime := TrimSP(YearTime);
  1490. x := StrToIntDef(YearTime, -1);
  1491. if (x = -1) then
  1492. Exit;
  1493. if (x < 1900) or (x > 2100) then
  1494. Exit;
  1495. end;
  1496. end;
  1497. if Year <> '' then
  1498. begin
  1499. Year := TrimSP(Year);
  1500. x := StrToIntDef(Year, -1);
  1501. if (x = -1) then
  1502. Exit;
  1503. if Length(Year) = 4 then
  1504. begin
  1505. if not((x > 1900) and (x < 2100)) then
  1506. Exit;
  1507. end
  1508. else
  1509. if Length(Year) = 2 then
  1510. begin
  1511. if not((x >= 0) and (x <= 99)) then
  1512. Exit;
  1513. end
  1514. else
  1515. if Length(Year) = 3 then
  1516. begin
  1517. if not((x >= 100) and (x <= 110)) then
  1518. Exit;
  1519. end
  1520. else
  1521. Exit;
  1522. end;
  1523. Result := True;
  1524. end;
  1525. procedure TFTPList.FillRecord(const Value: TFTPListRec);
  1526. var
  1527. s: string;
  1528. x: integer;
  1529. myear: Word;
  1530. mmonth: Word;
  1531. mday: Word;
  1532. mhours, mminutes, mseconds: word;
  1533. n: integer;
  1534. begin
  1535. s := DirFlagValue;
  1536. if s = '' then
  1537. s := 'D';
  1538. s := Uppercase(s);
  1539. Value.Directory := s = Uppercase(DirFlag);
  1540. if FileName <> '' then
  1541. Value.FileName := SeparateLeft(Filename, ' -> ');
  1542. if VMSFileName <> '' then
  1543. begin
  1544. Value.FileName := VMSFilename;
  1545. Value.Directory := Pos('.DIR;',VMSFilename) > 0;
  1546. end;
  1547. Value.FileName := TrimSPRight(Value.FileName);
  1548. Value.Readable := not Value.Directory;
  1549. if BlockSize <> '' then
  1550. x := StrToIntDef(BlockSize, 1)
  1551. else
  1552. x := 1;
  1553. {$IFDEF VER100}
  1554. Value.FileSize := x * StrToIntDef(Size, 0);
  1555. {$ELSE}
  1556. Value.FileSize := x * StrToInt64Def(Size, 0);
  1557. {$ENDIF}
  1558. DecodeDate(Date,myear,mmonth,mday);
  1559. mhours := 0;
  1560. mminutes := 0;
  1561. mseconds := 0;
  1562. if Day <> '' then
  1563. mday := StrToIntDef(day, 1);
  1564. if Month <> '' then
  1565. mmonth := StrToIntDef(Month, 1);
  1566. if length(Monthnames) = (12 * 3) then
  1567. for n := 1 to 12 do
  1568. CustomMonthNames[n] := Copy(Monthnames, ((n - 1) * 3) + 1, 3);
  1569. if ThreeMonth <> '' then
  1570. mmonth := GetMonthNumber(ThreeMonth);
  1571. if Year <> '' then
  1572. begin
  1573. myear := StrToIntDef(Year, 0);
  1574. if (myear <= 99) and (myear > 50) then
  1575. myear := myear + 1900;
  1576. if myear <= 50 then
  1577. myear := myear + 2000;
  1578. end;
  1579. if YearTime <> '' then
  1580. begin
  1581. if pos(':', YearTime) > 0 then
  1582. begin
  1583. YearTime := TrimSP(YearTime);
  1584. mhours := StrToIntDef(Separateleft(YearTime, ':'), 0);
  1585. mminutes := StrToIntDef(SeparateRight(YearTime, ':'), 0);
  1586. if (Encodedate(myear, mmonth, mday)
  1587. + EncodeTime(mHours, mminutes, 0, 0)) > now then
  1588. Dec(mYear);
  1589. end
  1590. else
  1591. myear := StrToIntDef(YearTime, 0);
  1592. end;
  1593. if Minutes <> '' then
  1594. mminutes := StrToIntDef(Minutes, 0);
  1595. if Seconds <> '' then
  1596. mseconds := StrToIntDef(Seconds, 0);
  1597. if Hours <> '' then
  1598. begin
  1599. mHours := StrToIntDef(Hours, 0);
  1600. if HoursModif <> '' then
  1601. if Uppercase(HoursModif[1]) = 'P' then
  1602. if mHours <> 12 then
  1603. mHours := MHours + 12;
  1604. end;
  1605. Value.FileTime := Encodedate(myear, mmonth, mday)
  1606. + EncodeTime(mHours, mminutes, mseconds, 0);
  1607. if Permissions <> '' then
  1608. begin
  1609. Value.Permission := Permissions;
  1610. Value.Readable := Uppercase(permissions)[2] = 'R';
  1611. if Uppercase(permissions)[1] = 'D' then
  1612. begin
  1613. Value.Directory := True;
  1614. Value.Readable := false;
  1615. end
  1616. else
  1617. if Uppercase(permissions)[1] = 'L' then
  1618. Value.Directory := True;
  1619. end;
  1620. end;
  1621. function TFTPList.ParseEPLF(Value: string): Boolean;
  1622. var
  1623. s, os: string;
  1624. flr: TFTPListRec;
  1625. begin
  1626. Result := False;
  1627. if Value <> '' then
  1628. if Value[1] = '+' then
  1629. begin
  1630. os := Value;
  1631. Delete(Value, 1, 1);
  1632. flr := TFTPListRec.create;
  1633. flr.FileName := SeparateRight(Value, #9);
  1634. s := Fetch(Value, ',');
  1635. while s <> '' do
  1636. begin
  1637. if s[1] = #9 then
  1638. Break;
  1639. case s[1] of
  1640. '/':
  1641. flr.Directory := true;
  1642. 'r':
  1643. flr.Readable := true;
  1644. 's':
  1645. {$IFDEF VER100}
  1646. flr.FileSize := StrToIntDef(Copy(s, 2, Length(s) - 1), 0);
  1647. {$ELSE}
  1648. flr.FileSize := StrToInt64Def(Copy(s, 2, Length(s) - 1), 0);
  1649. {$ENDIF}
  1650. 'm':
  1651. flr.FileTime := (StrToIntDef(Copy(s, 2, Length(s) - 1), 0) / 86400)
  1652. + 25569;
  1653. end;
  1654. s := Fetch(Value, ',');
  1655. end;
  1656. if flr.FileName <> '' then
  1657. if (flr.Directory and ((flr.FileName = '.') or (flr.FileName = '..')))
  1658. or (flr.FileName = '') then
  1659. flr.free
  1660. else
  1661. begin
  1662. flr.OriginalLine := os;
  1663. flr.Mask := 'EPLF';
  1664. Flist.Add(flr);
  1665. Result := True;
  1666. end;
  1667. end;
  1668. end;
  1669. procedure TFTPList.ParseLines;
  1670. var
  1671. flr: TFTPListRec;
  1672. n, m: Integer;
  1673. S: string;
  1674. x: integer;
  1675. b: Boolean;
  1676. begin
  1677. n := 0;
  1678. while n < Lines.Count do
  1679. begin
  1680. if n = Lines.Count - 1 then
  1681. s := ''
  1682. else
  1683. s := Lines[n + 1];
  1684. b := False;
  1685. x := 0;
  1686. if ParseEPLF(Lines[n]) then
  1687. begin
  1688. b := True;
  1689. x := 1;
  1690. end
  1691. else
  1692. for m := 0 to Masks.Count - 1 do
  1693. begin
  1694. x := ParseByMask(Lines[n], s, Masks[m]);
  1695. if x > 0 then
  1696. if CheckValues then
  1697. begin
  1698. flr := TFTPListRec.create;
  1699. FillRecord(flr);
  1700. flr.OriginalLine := Lines[n];
  1701. flr.Mask := Masks[m];
  1702. if flr.Directory and ((flr.FileName = '.') or (flr.FileName = '..')) then
  1703. flr.free
  1704. else
  1705. Flist.Add(flr);
  1706. b := True;
  1707. Break;
  1708. end;
  1709. end;
  1710. if not b then
  1711. FUnparsedLines.Add(Lines[n]);
  1712. Inc(n);
  1713. if x > 1 then
  1714. Inc(n, x - 1);
  1715. end;
  1716. end;
  1717. {==============================================================================}
  1718. function FtpGetFile(const IP, Port, FileName, LocalFile,
  1719. User, Pass: string): Boolean;
  1720. begin
  1721. Result := False;
  1722. with TFTPSend.Create do
  1723. try
  1724. if User <> '' then
  1725. begin
  1726. Username := User;
  1727. Password := Pass;
  1728. end;
  1729. TargetHost := IP;
  1730. TargetPort := Port;
  1731. if not Login then
  1732. Exit;
  1733. DirectFileName := LocalFile;
  1734. DirectFile:=True;
  1735. Result := RetrieveFile(FileName, False);
  1736. Logout;
  1737. finally
  1738. Free;
  1739. end;
  1740. end;
  1741. function FtpPutFile(const IP, Port, FileName, LocalFile,
  1742. User, Pass: string): Boolean;
  1743. begin
  1744. Result := False;
  1745. with TFTPSend.Create do
  1746. try
  1747. if User <> '' then
  1748. begin
  1749. Username := User;
  1750. Password := Pass;
  1751. end;
  1752. TargetHost := IP;
  1753. TargetPort := Port;
  1754. if not Login then
  1755. Exit;
  1756. DirectFileName := LocalFile;
  1757. DirectFile:=True;
  1758. Result := StoreFile(FileName, False);
  1759. Logout;
  1760. finally
  1761. Free;
  1762. end;
  1763. end;
  1764. function FtpInterServerTransfer(
  1765. const FromIP, FromPort, FromFile, FromUser, FromPass: string;
  1766. const ToIP, ToPort, ToFile, ToUser, ToPass: string): Boolean;
  1767. var
  1768. FromFTP, ToFTP: TFTPSend;
  1769. s: string;
  1770. x: integer;
  1771. begin
  1772. Result := False;
  1773. FromFTP := TFTPSend.Create;
  1774. toFTP := TFTPSend.Create;
  1775. try
  1776. if FromUser <> '' then
  1777. begin
  1778. FromFTP.Username := FromUser;
  1779. FromFTP.Password := FromPass;
  1780. end;
  1781. if ToUser <> '' then
  1782. begin
  1783. ToFTP.Username := ToUser;
  1784. ToFTP.Password := ToPass;
  1785. end;
  1786. FromFTP.TargetHost := FromIP;
  1787. FromFTP.TargetPort := FromPort;
  1788. ToFTP.TargetHost := ToIP;
  1789. ToFTP.TargetPort := ToPort;
  1790. if not FromFTP.Login then
  1791. Exit;
  1792. if not ToFTP.Login then
  1793. Exit;
  1794. if (FromFTP.FTPCommand('PASV') div 100) <> 2 then
  1795. Exit;
  1796. FromFTP.ParseRemote(FromFTP.ResultString);
  1797. s := ReplaceString(FromFTP.DataIP, '.', ',');
  1798. s := 'PORT ' + s + ',' + IntToStr(StrToIntDef(FromFTP.DataPort, 0) div 256)
  1799. + ',' + IntToStr(StrToIntDef(FromFTP.DataPort, 0) mod 256);
  1800. if (ToFTP.FTPCommand(s) div 100) <> 2 then
  1801. Exit;
  1802. x := ToFTP.FTPCommand('RETR ' + FromFile);
  1803. if (x div 100) <> 1 then
  1804. Exit;
  1805. x := FromFTP.FTPCommand('STOR ' + ToFile);
  1806. if (x div 100) <> 1 then
  1807. Exit;
  1808. FromFTP.Timeout := 21600000;
  1809. x := FromFTP.ReadResult;
  1810. if (x div 100) <> 2 then
  1811. Exit;
  1812. ToFTP.Timeout := 21600000;
  1813. x := ToFTP.ReadResult;
  1814. if (x div 100) <> 2 then
  1815. Exit;
  1816. Result := True;
  1817. finally
  1818. ToFTP.Free;
  1819. FromFTP.Free;
  1820. end;
  1821. end;
  1822. end.