ftpsend.pas 54 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964
  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. FDSock.Connect(FDataIP, FDataPort);
  772. Result := FDSock.LastError = 0;
  773. end
  774. else
  775. begin
  776. FDSock.CloseSocket;
  777. if FForceDefaultPort then
  778. s := cFtpDataProtocol
  779. else
  780. s := '0';
  781. //data conection from same interface as command connection
  782. FDSock.Bind(FSock.GetLocalSinIP, s);
  783. if FDSock.LastError <> 0 then
  784. Exit;
  785. FDSock.SetLinger(True, 10000);
  786. FDSock.Listen;
  787. FDSock.GetSins;
  788. FDataIP := FDSock.GetLocalSinIP;
  789. FDataIP := FDSock.ResolveName(FDataIP);
  790. FDataPort := IntToStr(FDSock.GetLocalSinPort);
  791. if FSock.IP6used and (not FForceOldPort) then
  792. begin
  793. if IsIp6(FDataIP) then
  794. s := '2'
  795. else
  796. s := '1';
  797. s := 'EPRT |' + s +'|' + FDataIP + '|' + FDataPort + '|';
  798. Result := (FTPCommand(s) div 100) = 2;
  799. end;
  800. if not Result and IsIP(FDataIP) then
  801. begin
  802. s := ReplaceString(FDataIP, '.', ',');
  803. s := 'PORT ' + s + ',' + IntToStr(FDSock.GetLocalSinPort div 256)
  804. + ',' + IntToStr(FDSock.GetLocalSinPort mod 256);
  805. Result := (FTPCommand(s) div 100) = 2;
  806. end;
  807. end;
  808. end;
  809. function TFTPSend.AcceptDataSocket: Boolean;
  810. var
  811. x: TSocket;
  812. begin
  813. if FPassiveMode then
  814. Result := True
  815. else
  816. begin
  817. Result := False;
  818. if FDSock.CanRead(FTimeout) then
  819. begin
  820. x := FDSock.Accept;
  821. if not FDSock.UsingSocks then
  822. FDSock.CloseSocket;
  823. FDSock.Socket := x;
  824. Result := True;
  825. end;
  826. end;
  827. if Result and FIsDataTLS then
  828. begin
  829. FDSock.SSL.Assign(FSock.SSL);
  830. FDSock.SSLDoConnect;
  831. Result := FDSock.LastError = 0;
  832. end;
  833. end;
  834. function TFTPSend.DataRead(const DestStream: TStream): Boolean;
  835. var
  836. x: integer;
  837. begin
  838. Result := False;
  839. try
  840. if not AcceptDataSocket then
  841. Exit;
  842. FDSock.RecvStreamRaw(DestStream, FTimeout);
  843. FDSock.CloseSocket;
  844. x := ReadResult;
  845. Result := (x div 100) = 2;
  846. finally
  847. FDSock.CloseSocket;
  848. end;
  849. end;
  850. function TFTPSend.DataWrite(const SourceStream: TStream): Boolean;
  851. var
  852. x: integer;
  853. b: Boolean;
  854. begin
  855. Result := False;
  856. try
  857. if not AcceptDataSocket then
  858. Exit;
  859. FDSock.SendStreamRaw(SourceStream);
  860. b := FDSock.LastError = 0;
  861. FDSock.CloseSocket;
  862. x := ReadResult;
  863. Result := b and ((x div 100) = 2);
  864. finally
  865. FDSock.CloseSocket;
  866. end;
  867. end;
  868. function TFTPSend.List(Directory: string; NameList: Boolean): Boolean;
  869. var
  870. x: integer;
  871. begin
  872. Result := False;
  873. FDataStream.Clear;
  874. FFTPList.Clear;
  875. if Directory <> '' then
  876. Directory := ' ' + Directory;
  877. FTPCommand('TYPE A');
  878. if not DataSocket then
  879. Exit;
  880. if NameList then
  881. x := FTPCommand('NLST' + Directory)
  882. else
  883. x := FTPCommand('LIST' + Directory);
  884. if (x div 100) <> 1 then
  885. Exit;
  886. Result := DataRead(FDataStream);
  887. if (not NameList) and Result then
  888. begin
  889. FDataStream.Position := 0;
  890. FFTPList.Lines.LoadFromStream(FDataStream);
  891. FFTPList.ParseLines;
  892. end;
  893. FDataStream.Position := 0;
  894. end;
  895. function TFTPSend.RetrieveFile(const FileName: string; Restore: Boolean): Boolean;
  896. var
  897. RetrStream: TStream;
  898. begin
  899. Result := False;
  900. if FileName = '' then
  901. Exit;
  902. if not DataSocket then
  903. Exit;
  904. Restore := Restore and FCanResume;
  905. if FDirectFile then
  906. if Restore and FileExists(FDirectFileName) then
  907. RetrStream := TFileStream.Create(FDirectFileName,
  908. fmOpenReadWrite or fmShareExclusive)
  909. else
  910. RetrStream := TFileStream.Create(FDirectFileName,
  911. fmCreate or fmShareDenyWrite)
  912. else
  913. RetrStream := FDataStream;
  914. try
  915. if FBinaryMode then
  916. FTPCommand('TYPE I')
  917. else
  918. FTPCommand('TYPE A');
  919. if Restore then
  920. begin
  921. RetrStream.Position := RetrStream.Size;
  922. if (FTPCommand('REST ' + IntToStr(RetrStream.Size)) div 100) <> 3 then
  923. Exit;
  924. end
  925. else
  926. if RetrStream is TMemoryStream then
  927. TMemoryStream(RetrStream).Clear;
  928. if (FTPCommand('RETR ' + FileName) div 100) <> 1 then
  929. Exit;
  930. Result := DataRead(RetrStream);
  931. if not FDirectFile then
  932. RetrStream.Position := 0;
  933. finally
  934. if FDirectFile then
  935. RetrStream.Free;
  936. end;
  937. end;
  938. function TFTPSend.InternalStor(const Command: string; RestoreAt: int64): Boolean;
  939. var
  940. SendStream: TStream;
  941. StorSize: int64;
  942. begin
  943. Result := False;
  944. if FDirectFile then
  945. if not FileExists(FDirectFileName) then
  946. Exit
  947. else
  948. SendStream := TFileStream.Create(FDirectFileName,
  949. fmOpenRead or fmShareDenyWrite)
  950. else
  951. SendStream := FDataStream;
  952. try
  953. if not DataSocket then
  954. Exit;
  955. if FBinaryMode then
  956. FTPCommand('TYPE I')
  957. else
  958. FTPCommand('TYPE A');
  959. StorSize := SendStream.Size;
  960. if not FCanResume then
  961. RestoreAt := 0;
  962. if (StorSize > 0) and (RestoreAt = StorSize) then
  963. begin
  964. Result := True;
  965. Exit;
  966. end;
  967. if RestoreAt > StorSize then
  968. RestoreAt := 0;
  969. FTPCommand('ALLO ' + IntToStr(StorSize - RestoreAt));
  970. if FCanResume then
  971. if (FTPCommand('REST ' + IntToStr(RestoreAt)) div 100) <> 3 then
  972. Exit;
  973. SendStream.Position := RestoreAt;
  974. if (FTPCommand(Command) div 100) <> 1 then
  975. Exit;
  976. Result := DataWrite(SendStream);
  977. finally
  978. if FDirectFile then
  979. SendStream.Free;
  980. end;
  981. end;
  982. function TFTPSend.StoreFile(const FileName: string; Restore: Boolean): Boolean;
  983. var
  984. RestoreAt: int64;
  985. begin
  986. Result := False;
  987. if FileName = '' then
  988. Exit;
  989. RestoreAt := 0;
  990. Restore := Restore and FCanResume;
  991. if Restore then
  992. begin
  993. RestoreAt := Self.FileSize(FileName);
  994. if RestoreAt < 0 then
  995. RestoreAt := 0;
  996. end;
  997. Result := InternalStor('STOR ' + FileName, RestoreAt);
  998. end;
  999. function TFTPSend.StoreUniqueFile: Boolean;
  1000. begin
  1001. Result := InternalStor('STOU', 0);
  1002. end;
  1003. function TFTPSend.AppendFile(const FileName: string): Boolean;
  1004. begin
  1005. Result := False;
  1006. if FileName = '' then
  1007. Exit;
  1008. Result := InternalStor('APPE ' + FileName, 0);
  1009. end;
  1010. function TFTPSend.NoOp: Boolean;
  1011. begin
  1012. Result := (FTPCommand('NOOP') div 100) = 2;
  1013. end;
  1014. function TFTPSend.RenameFile(const OldName, NewName: string): Boolean;
  1015. begin
  1016. Result := False;
  1017. if (FTPCommand('RNFR ' + OldName) div 100) <> 3 then
  1018. Exit;
  1019. Result := (FTPCommand('RNTO ' + NewName) div 100) = 2;
  1020. end;
  1021. function TFTPSend.DeleteFile(const FileName: string): Boolean;
  1022. begin
  1023. Result := (FTPCommand('DELE ' + FileName) div 100) = 2;
  1024. end;
  1025. function TFTPSend.FileSize(const FileName: string): int64;
  1026. var
  1027. s: string;
  1028. begin
  1029. Result := -1;
  1030. if (FTPCommand('SIZE ' + FileName) div 100) = 2 then
  1031. begin
  1032. s := Trim(SeparateRight(ResultString, ' '));
  1033. s := Trim(SeparateLeft(s, ' '));
  1034. {$IFDEF VER100}
  1035. Result := StrToIntDef(s, -1);
  1036. {$ELSE}
  1037. Result := StrToInt64Def(s, -1);
  1038. {$ENDIF}
  1039. end;
  1040. end;
  1041. function TFTPSend.ChangeWorkingDir(const Directory: string): Boolean;
  1042. begin
  1043. Result := (FTPCommand('CWD ' + Directory) div 100) = 2;
  1044. end;
  1045. function TFTPSend.ChangeToParentDir: Boolean;
  1046. begin
  1047. Result := (FTPCommand('CDUP') div 100) = 2;
  1048. end;
  1049. function TFTPSend.ChangeToRootDir: Boolean;
  1050. begin
  1051. Result := ChangeWorkingDir('/');
  1052. end;
  1053. function TFTPSend.DeleteDir(const Directory: string): Boolean;
  1054. begin
  1055. Result := (FTPCommand('RMD ' + Directory) div 100) = 2;
  1056. end;
  1057. function TFTPSend.CreateDir(const Directory: string): Boolean;
  1058. begin
  1059. Result := (FTPCommand('MKD ' + Directory) div 100) = 2;
  1060. end;
  1061. function TFTPSend.GetCurrentDir: String;
  1062. begin
  1063. Result := '';
  1064. if (FTPCommand('PWD') div 100) = 2 then
  1065. begin
  1066. Result := SeparateRight(FResultString, '"');
  1067. Result := Trim(Separateleft(Result, '"'));
  1068. end;
  1069. end;
  1070. procedure TFTPSend.Abort;
  1071. begin
  1072. FSock.SendString('ABOR' + CRLF);
  1073. FDSock.StopFlag := True;
  1074. end;
  1075. procedure TFTPSend.TelnetAbort;
  1076. begin
  1077. FSock.SendString(#$FF + #$F4 + #$FF + #$F2);
  1078. Abort;
  1079. end;
  1080. {==============================================================================}
  1081. procedure TFTPListRec.Assign(Value: TFTPListRec);
  1082. begin
  1083. FFileName := Value.FileName;
  1084. FDirectory := Value.Directory;
  1085. FReadable := Value.Readable;
  1086. FFileSize := Value.FileSize;
  1087. FFileTime := Value.FileTime;
  1088. FOriginalLine := Value.OriginalLine;
  1089. FMask := Value.Mask;
  1090. end;
  1091. constructor TFTPList.Create;
  1092. begin
  1093. inherited Create;
  1094. FList := TList.Create;
  1095. FLines := TStringList.Create;
  1096. FMasks := TStringList.Create;
  1097. FUnparsedLines := TStringList.Create;
  1098. //various UNIX
  1099. FMasks.add('pppppppppp $!!!S*$TTT$DD$hh mm ss$YYYY$n*');
  1100. FMasks.add('pppppppppp $!!!S*$DD$TTT$hh mm ss$YYYY$n*');
  1101. FMasks.add('pppppppppp $!!!S*$TTT$DD$UUUUU$n*'); //mostly used UNIX format
  1102. FMasks.add('pppppppppp $!!!S*$DD$TTT$UUUUU$n*');
  1103. //MacOS
  1104. FMasks.add('pppppppppp $!!S*$TTT$DD$UUUUU$n*');
  1105. FMasks.add('pppppppppp $!S*$TTT$DD$UUUUU$n*');
  1106. //Novell
  1107. FMasks.add('d $!S*$TTT$DD$UUUUU$n*');
  1108. //Windows
  1109. FMasks.add('MM DD YY hh mmH !S* n*');
  1110. FMasks.add('MM DD YY hh mmH $ d!n*');
  1111. FMasks.add('MM DD YYYY hh mmH !S* n*');
  1112. FMasks.add('MM DD YYYY hh mmH $ d!n*');
  1113. FMasks.add('DD MM YYYY hh mmH !S* n*');
  1114. FMasks.add('DD MM YYYY hh mmH $ d!n*');
  1115. //VMS
  1116. FMasks.add('v*$ DD TTT YYYY hh mm');
  1117. FMasks.add('v*$!DD TTT YYYY hh mm');
  1118. FMasks.add('n*$ YYYY MM DD hh mm$S*');
  1119. //AS400
  1120. FMasks.add('!S*$MM DD YY hh mm ss !n*');
  1121. FMasks.add('!S*$DD MM YY hh mm ss !n*');
  1122. FMasks.add('n*!S*$MM DD YY hh mm ss d');
  1123. FMasks.add('n*!S*$DD MM YY hh mm ss d');
  1124. //VxWorks
  1125. FMasks.add('$S* TTT DD YYYY hh mm ss $n* $ d');
  1126. FMasks.add('$S* TTT DD YYYY hh mm ss $n*');
  1127. //Distinct
  1128. FMasks.add('d $S*$TTT DD YYYY hh mm$n*');
  1129. FMasks.add('d $S*$TTT DD$hh mm$n*');
  1130. //PC-NFSD
  1131. FMasks.add('nnnnnnnn.nnn dSSSSSSSSSSS MM DD YY hh mmH');
  1132. //VOS
  1133. FMasks.add('- SSSSS YY MM DD hh mm ss n*');
  1134. FMasks.add('- d= SSSSS YY MM DD hh mm ss n*');
  1135. //Unissys ClearPath
  1136. FMasks.add('nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn SSSSSSSSS MM DD YYYY hh mm');
  1137. FMasks.add('n*\x SSSSSSSSS MM DD YYYY hh mm');
  1138. //IBM
  1139. FMasks.add('- SSSSSSSSSSSS d MM DD YYYY hh mm n*');
  1140. //OS9
  1141. FMasks.add('- YY MM DD hhmm d SSSSSSSSS n*');
  1142. //tandem
  1143. FMasks.add('nnnnnnnn SSSSSSS DD TTT YY hh mm ss');
  1144. //MVS
  1145. FMasks.add('- YYYY MM DD SSSSS d=O n*');
  1146. //BullGCOS8
  1147. FMasks.add(' $S* MM DD YY hh mm ss !n*');
  1148. FMasks.add('d $S* MM DD YY !n*');
  1149. //BullGCOS7
  1150. FMasks.add(' TTT DD YYYY n*');
  1151. FMasks.add(' d n*');
  1152. end;
  1153. destructor TFTPList.Destroy;
  1154. begin
  1155. Clear;
  1156. FList.Free;
  1157. FLines.Free;
  1158. FMasks.Free;
  1159. FUnparsedLines.Free;
  1160. inherited Destroy;
  1161. end;
  1162. procedure TFTPList.Clear;
  1163. var
  1164. n:integer;
  1165. begin
  1166. for n := 0 to FList.Count - 1 do
  1167. if Assigned(FList[n]) then
  1168. TFTPListRec(FList[n]).Free;
  1169. FList.Clear;
  1170. FLines.Clear;
  1171. FUnparsedLines.Clear;
  1172. end;
  1173. function TFTPList.Count: integer;
  1174. begin
  1175. Result := FList.Count;
  1176. end;
  1177. function TFTPList.GetListItem(Index: integer): TFTPListRec;
  1178. begin
  1179. Result := nil;
  1180. if Index < Count then
  1181. Result := TFTPListRec(FList[Index]);
  1182. end;
  1183. procedure TFTPList.Assign(Value: TFTPList);
  1184. var
  1185. flr: TFTPListRec;
  1186. n: integer;
  1187. begin
  1188. Clear;
  1189. for n := 0 to Value.Count - 1 do
  1190. begin
  1191. flr := TFTPListRec.Create;
  1192. flr.Assign(Value[n]);
  1193. Flist.Add(flr);
  1194. end;
  1195. Lines.Assign(Value.Lines);
  1196. Masks.Assign(Value.Masks);
  1197. UnparsedLines.Assign(Value.UnparsedLines);
  1198. end;
  1199. procedure TFTPList.ClearStore;
  1200. begin
  1201. Monthnames := '';
  1202. BlockSize := '';
  1203. DirFlagValue := '';
  1204. FileName := '';
  1205. VMSFileName := '';
  1206. Day := '';
  1207. Month := '';
  1208. ThreeMonth := '';
  1209. YearTime := '';
  1210. Year := '';
  1211. Hours := '';
  1212. HoursModif := '';
  1213. Minutes := '';
  1214. Seconds := '';
  1215. Size := '';
  1216. Permissions := '';
  1217. DirFlag := '';
  1218. end;
  1219. function TFTPList.ParseByMask(Value, NextValue, Mask: AnsiString): Integer;
  1220. var
  1221. Ivalue, IMask: integer;
  1222. MaskC, LastMaskC: AnsiChar;
  1223. c: AnsiChar;
  1224. s: string;
  1225. begin
  1226. ClearStore;
  1227. Result := 0;
  1228. if Value = '' then
  1229. Exit;
  1230. if Mask = '' then
  1231. Exit;
  1232. Ivalue := 1;
  1233. IMask := 1;
  1234. Result := 1;
  1235. LastMaskC := ' ';
  1236. while Imask <= Length(mask) do
  1237. begin
  1238. if (Mask[Imask] <> '*') and (Ivalue > Length(Value)) then
  1239. begin
  1240. Result := 0;
  1241. Exit;
  1242. end;
  1243. MaskC := Mask[Imask];
  1244. if Ivalue > Length(Value) then
  1245. Exit;
  1246. c := Value[Ivalue];
  1247. case MaskC of
  1248. 'n':
  1249. FileName := FileName + c;
  1250. 'v':
  1251. VMSFileName := VMSFileName + c;
  1252. '.':
  1253. begin
  1254. if c in ['.', ' '] then
  1255. FileName := TrimSP(FileName) + '.'
  1256. else
  1257. begin
  1258. Result := 0;
  1259. Exit;
  1260. end;
  1261. end;
  1262. 'D':
  1263. Day := Day + c;
  1264. 'M':
  1265. Month := Month + c;
  1266. 'T':
  1267. ThreeMonth := ThreeMonth + c;
  1268. 'U':
  1269. YearTime := YearTime + c;
  1270. 'Y':
  1271. Year := Year + c;
  1272. 'h':
  1273. Hours := Hours + c;
  1274. 'H':
  1275. HoursModif := HoursModif + c;
  1276. 'm':
  1277. Minutes := Minutes + c;
  1278. 's':
  1279. Seconds := Seconds + c;
  1280. 'S':
  1281. Size := Size + c;
  1282. 'p':
  1283. Permissions := Permissions + c;
  1284. 'd':
  1285. DirFlag := DirFlag + c;
  1286. 'x':
  1287. if c <> ' ' then
  1288. begin
  1289. Result := 0;
  1290. Exit;
  1291. end;
  1292. '*':
  1293. begin
  1294. s := '';
  1295. if LastMaskC in ['n', 'v'] then
  1296. begin
  1297. if Imask = Length(Mask) then
  1298. s := Copy(Value, IValue, Maxint)
  1299. else
  1300. while IValue <= Length(Value) do
  1301. begin
  1302. if Value[Ivalue] = ' ' then
  1303. break;
  1304. s := s + Value[Ivalue];
  1305. Inc(Ivalue);
  1306. end;
  1307. if LastMaskC = 'n' then
  1308. FileName := FileName + s
  1309. else
  1310. VMSFileName := VMSFileName + s;
  1311. end
  1312. else
  1313. begin
  1314. while IValue <= Length(Value) do
  1315. begin
  1316. if not(Value[Ivalue] in ['0'..'9']) then
  1317. break;
  1318. s := s + Value[Ivalue];
  1319. Inc(Ivalue);
  1320. end;
  1321. case LastMaskC of
  1322. 'S':
  1323. Size := Size + s;
  1324. end;
  1325. end;
  1326. Dec(IValue);
  1327. end;
  1328. '!':
  1329. begin
  1330. while IValue <= Length(Value) do
  1331. begin
  1332. if Value[Ivalue] = ' ' then
  1333. break;
  1334. Inc(Ivalue);
  1335. end;
  1336. while IValue <= Length(Value) do
  1337. begin
  1338. if Value[Ivalue] <> ' ' then
  1339. break;
  1340. Inc(Ivalue);
  1341. end;
  1342. Dec(IValue);
  1343. end;
  1344. '$':
  1345. begin
  1346. while IValue <= Length(Value) do
  1347. begin
  1348. if not(Value[Ivalue] in [' ', #9]) then
  1349. break;
  1350. Inc(Ivalue);
  1351. end;
  1352. Dec(IValue);
  1353. end;
  1354. '=':
  1355. begin
  1356. s := '';
  1357. case LastmaskC of
  1358. 'S':
  1359. begin
  1360. while Imask <= Length(Mask) do
  1361. begin
  1362. if not(Mask[Imask] in ['0'..'9']) then
  1363. break;
  1364. s := s + Mask[Imask];
  1365. Inc(Imask);
  1366. end;
  1367. Dec(Imask);
  1368. BlockSize := s;
  1369. end;
  1370. 'T':
  1371. begin
  1372. Monthnames := Copy(Mask, IMask, 12 * 3);
  1373. Inc(IMask, 12 * 3);
  1374. end;
  1375. 'd':
  1376. begin
  1377. Inc(Imask);
  1378. DirFlagValue := Mask[Imask];
  1379. end;
  1380. end;
  1381. end;
  1382. '\':
  1383. begin
  1384. Value := NextValue;
  1385. IValue := 0;
  1386. Result := 2;
  1387. end;
  1388. end;
  1389. Inc(Ivalue);
  1390. Inc(Imask);
  1391. LastMaskC := MaskC;
  1392. end;
  1393. end;
  1394. function TFTPList.CheckValues: Boolean;
  1395. var
  1396. x, n: integer;
  1397. begin
  1398. Result := false;
  1399. if FileName <> '' then
  1400. begin
  1401. if pos('?', VMSFilename) > 0 then
  1402. Exit;
  1403. if pos('*', VMSFilename) > 0 then
  1404. Exit;
  1405. end;
  1406. if VMSFileName <> '' then
  1407. if pos(';', VMSFilename) <= 0 then
  1408. Exit;
  1409. if (FileName = '') and (VMSFileName = '') then
  1410. Exit;
  1411. if Permissions <> '' then
  1412. begin
  1413. if length(Permissions) <> 10 then
  1414. Exit;
  1415. for n := 1 to 10 do
  1416. if not(Permissions[n] in
  1417. ['a', 'b', 'c', 'd', 'h', 'l', 'p', 'r', 's', 't', 'w', 'x', 'y', '-']) then
  1418. Exit;
  1419. end;
  1420. if Day <> '' then
  1421. begin
  1422. Day := TrimSP(Day);
  1423. x := StrToIntDef(day, -1);
  1424. if (x < 1) or (x > 31) then
  1425. Exit;
  1426. end;
  1427. if Month <> '' then
  1428. begin
  1429. Month := TrimSP(Month);
  1430. x := StrToIntDef(Month, -1);
  1431. if (x < 1) or (x > 12) then
  1432. Exit;
  1433. end;
  1434. if Hours <> '' then
  1435. begin
  1436. Hours := TrimSP(Hours);
  1437. x := StrToIntDef(Hours, -1);
  1438. if (x < 0) or (x > 24) then
  1439. Exit;
  1440. end;
  1441. if HoursModif <> '' then
  1442. begin
  1443. if not (HoursModif[1] in ['a', 'A', 'p', 'P']) then
  1444. Exit;
  1445. end;
  1446. if Minutes <> '' then
  1447. begin
  1448. Minutes := TrimSP(Minutes);
  1449. x := StrToIntDef(Minutes, -1);
  1450. if (x < 0) or (x > 59) then
  1451. Exit;
  1452. end;
  1453. if Seconds <> '' then
  1454. begin
  1455. Seconds := TrimSP(Seconds);
  1456. x := StrToIntDef(Seconds, -1);
  1457. if (x < 0) or (x > 59) then
  1458. Exit;
  1459. end;
  1460. if Size <> '' then
  1461. begin
  1462. Size := TrimSP(Size);
  1463. for n := 1 to Length(Size) do
  1464. if not (Size[n] in ['0'..'9']) then
  1465. Exit;
  1466. end;
  1467. if length(Monthnames) = (12 * 3) then
  1468. for n := 1 to 12 do
  1469. CustomMonthNames[n] := Copy(Monthnames, ((n - 1) * 3) + 1, 3);
  1470. if ThreeMonth <> '' then
  1471. begin
  1472. x := GetMonthNumber(ThreeMonth);
  1473. if (x = 0) then
  1474. Exit;
  1475. end;
  1476. if YearTime <> '' then
  1477. begin
  1478. YearTime := ReplaceString(YearTime, '-', ':');
  1479. if pos(':', YearTime) > 0 then
  1480. begin
  1481. if (GetTimeFromstr(YearTime) = -1) then
  1482. Exit;
  1483. end
  1484. else
  1485. begin
  1486. YearTime := TrimSP(YearTime);
  1487. x := StrToIntDef(YearTime, -1);
  1488. if (x = -1) then
  1489. Exit;
  1490. if (x < 1900) or (x > 2100) then
  1491. Exit;
  1492. end;
  1493. end;
  1494. if Year <> '' then
  1495. begin
  1496. Year := TrimSP(Year);
  1497. x := StrToIntDef(Year, -1);
  1498. if (x = -1) then
  1499. Exit;
  1500. if Length(Year) = 4 then
  1501. begin
  1502. if not((x > 1900) and (x < 2100)) then
  1503. Exit;
  1504. end
  1505. else
  1506. if Length(Year) = 2 then
  1507. begin
  1508. if not((x >= 0) and (x <= 99)) then
  1509. Exit;
  1510. end
  1511. else
  1512. if Length(Year) = 3 then
  1513. begin
  1514. if not((x >= 100) and (x <= 110)) then
  1515. Exit;
  1516. end
  1517. else
  1518. Exit;
  1519. end;
  1520. Result := True;
  1521. end;
  1522. procedure TFTPList.FillRecord(const Value: TFTPListRec);
  1523. var
  1524. s: string;
  1525. x: integer;
  1526. myear: Word;
  1527. mmonth: Word;
  1528. mday: Word;
  1529. mhours, mminutes, mseconds: word;
  1530. n: integer;
  1531. begin
  1532. s := DirFlagValue;
  1533. if s = '' then
  1534. s := 'D';
  1535. s := Uppercase(s);
  1536. Value.Directory := s = Uppercase(DirFlag);
  1537. if FileName <> '' then
  1538. Value.FileName := SeparateLeft(Filename, ' -> ');
  1539. if VMSFileName <> '' then
  1540. begin
  1541. Value.FileName := VMSFilename;
  1542. Value.Directory := Pos('.DIR;',VMSFilename) > 0;
  1543. end;
  1544. Value.FileName := TrimSPRight(Value.FileName);
  1545. Value.Readable := not Value.Directory;
  1546. if BlockSize <> '' then
  1547. x := StrToIntDef(BlockSize, 1)
  1548. else
  1549. x := 1;
  1550. {$IFDEF VER100}
  1551. Value.FileSize := x * StrToIntDef(Size, 0);
  1552. {$ELSE}
  1553. Value.FileSize := x * StrToInt64Def(Size, 0);
  1554. {$ENDIF}
  1555. DecodeDate(Date,myear,mmonth,mday);
  1556. mhours := 0;
  1557. mminutes := 0;
  1558. mseconds := 0;
  1559. if Day <> '' then
  1560. mday := StrToIntDef(day, 1);
  1561. if Month <> '' then
  1562. mmonth := StrToIntDef(Month, 1);
  1563. if length(Monthnames) = (12 * 3) then
  1564. for n := 1 to 12 do
  1565. CustomMonthNames[n] := Copy(Monthnames, ((n - 1) * 3) + 1, 3);
  1566. if ThreeMonth <> '' then
  1567. mmonth := GetMonthNumber(ThreeMonth);
  1568. if Year <> '' then
  1569. begin
  1570. myear := StrToIntDef(Year, 0);
  1571. if (myear <= 99) and (myear > 50) then
  1572. myear := myear + 1900;
  1573. if myear <= 50 then
  1574. myear := myear + 2000;
  1575. end;
  1576. if YearTime <> '' then
  1577. begin
  1578. if pos(':', YearTime) > 0 then
  1579. begin
  1580. YearTime := TrimSP(YearTime);
  1581. mhours := StrToIntDef(Separateleft(YearTime, ':'), 0);
  1582. mminutes := StrToIntDef(SeparateRight(YearTime, ':'), 0);
  1583. if (Encodedate(myear, mmonth, mday)
  1584. + EncodeTime(mHours, mminutes, 0, 0)) > now then
  1585. Dec(mYear);
  1586. end
  1587. else
  1588. myear := StrToIntDef(YearTime, 0);
  1589. end;
  1590. if Minutes <> '' then
  1591. mminutes := StrToIntDef(Minutes, 0);
  1592. if Seconds <> '' then
  1593. mseconds := StrToIntDef(Seconds, 0);
  1594. if Hours <> '' then
  1595. begin
  1596. mHours := StrToIntDef(Hours, 0);
  1597. if HoursModif <> '' then
  1598. if Uppercase(HoursModif[1]) = 'P' then
  1599. if mHours <> 12 then
  1600. mHours := MHours + 12;
  1601. end;
  1602. Value.FileTime := Encodedate(myear, mmonth, mday)
  1603. + EncodeTime(mHours, mminutes, mseconds, 0);
  1604. if Permissions <> '' then
  1605. begin
  1606. Value.Permission := Permissions;
  1607. Value.Readable := Uppercase(permissions)[2] = 'R';
  1608. if Uppercase(permissions)[1] = 'D' then
  1609. begin
  1610. Value.Directory := True;
  1611. Value.Readable := false;
  1612. end
  1613. else
  1614. if Uppercase(permissions)[1] = 'L' then
  1615. Value.Directory := True;
  1616. end;
  1617. end;
  1618. function TFTPList.ParseEPLF(Value: string): Boolean;
  1619. var
  1620. s, os: string;
  1621. flr: TFTPListRec;
  1622. begin
  1623. Result := False;
  1624. if Value <> '' then
  1625. if Value[1] = '+' then
  1626. begin
  1627. os := Value;
  1628. Delete(Value, 1, 1);
  1629. flr := TFTPListRec.create;
  1630. flr.FileName := SeparateRight(Value, #9);
  1631. s := Fetch(Value, ',');
  1632. while s <> '' do
  1633. begin
  1634. if s[1] = #9 then
  1635. Break;
  1636. case s[1] of
  1637. '/':
  1638. flr.Directory := true;
  1639. 'r':
  1640. flr.Readable := true;
  1641. 's':
  1642. {$IFDEF VER100}
  1643. flr.FileSize := StrToIntDef(Copy(s, 2, Length(s) - 1), 0);
  1644. {$ELSE}
  1645. flr.FileSize := StrToInt64Def(Copy(s, 2, Length(s) - 1), 0);
  1646. {$ENDIF}
  1647. 'm':
  1648. flr.FileTime := (StrToIntDef(Copy(s, 2, Length(s) - 1), 0) / 86400)
  1649. + 25569;
  1650. end;
  1651. s := Fetch(Value, ',');
  1652. end;
  1653. if flr.FileName <> '' then
  1654. if (flr.Directory and ((flr.FileName = '.') or (flr.FileName = '..')))
  1655. or (flr.FileName = '') then
  1656. flr.free
  1657. else
  1658. begin
  1659. flr.OriginalLine := os;
  1660. flr.Mask := 'EPLF';
  1661. Flist.Add(flr);
  1662. Result := True;
  1663. end;
  1664. end;
  1665. end;
  1666. procedure TFTPList.ParseLines;
  1667. var
  1668. flr: TFTPListRec;
  1669. n, m: Integer;
  1670. S: string;
  1671. x: integer;
  1672. b: Boolean;
  1673. begin
  1674. n := 0;
  1675. while n < Lines.Count do
  1676. begin
  1677. if n = Lines.Count - 1 then
  1678. s := ''
  1679. else
  1680. s := Lines[n + 1];
  1681. b := False;
  1682. x := 0;
  1683. if ParseEPLF(Lines[n]) then
  1684. begin
  1685. b := True;
  1686. x := 1;
  1687. end
  1688. else
  1689. for m := 0 to Masks.Count - 1 do
  1690. begin
  1691. x := ParseByMask(Lines[n], s, Masks[m]);
  1692. if x > 0 then
  1693. if CheckValues then
  1694. begin
  1695. flr := TFTPListRec.create;
  1696. FillRecord(flr);
  1697. flr.OriginalLine := Lines[n];
  1698. flr.Mask := Masks[m];
  1699. if flr.Directory and ((flr.FileName = '.') or (flr.FileName = '..')) then
  1700. flr.free
  1701. else
  1702. Flist.Add(flr);
  1703. b := True;
  1704. Break;
  1705. end;
  1706. end;
  1707. if not b then
  1708. FUnparsedLines.Add(Lines[n]);
  1709. Inc(n);
  1710. if x > 1 then
  1711. Inc(n, x - 1);
  1712. end;
  1713. end;
  1714. {==============================================================================}
  1715. function FtpGetFile(const IP, Port, FileName, LocalFile,
  1716. User, Pass: string): Boolean;
  1717. begin
  1718. Result := False;
  1719. with TFTPSend.Create do
  1720. try
  1721. if User <> '' then
  1722. begin
  1723. Username := User;
  1724. Password := Pass;
  1725. end;
  1726. TargetHost := IP;
  1727. TargetPort := Port;
  1728. if not Login then
  1729. Exit;
  1730. DirectFileName := LocalFile;
  1731. DirectFile:=True;
  1732. Result := RetrieveFile(FileName, False);
  1733. Logout;
  1734. finally
  1735. Free;
  1736. end;
  1737. end;
  1738. function FtpPutFile(const IP, Port, FileName, LocalFile,
  1739. User, Pass: string): Boolean;
  1740. begin
  1741. Result := False;
  1742. with TFTPSend.Create do
  1743. try
  1744. if User <> '' then
  1745. begin
  1746. Username := User;
  1747. Password := Pass;
  1748. end;
  1749. TargetHost := IP;
  1750. TargetPort := Port;
  1751. if not Login then
  1752. Exit;
  1753. DirectFileName := LocalFile;
  1754. DirectFile:=True;
  1755. Result := StoreFile(FileName, False);
  1756. Logout;
  1757. finally
  1758. Free;
  1759. end;
  1760. end;
  1761. function FtpInterServerTransfer(
  1762. const FromIP, FromPort, FromFile, FromUser, FromPass: string;
  1763. const ToIP, ToPort, ToFile, ToUser, ToPass: string): Boolean;
  1764. var
  1765. FromFTP, ToFTP: TFTPSend;
  1766. s: string;
  1767. x: integer;
  1768. begin
  1769. Result := False;
  1770. FromFTP := TFTPSend.Create;
  1771. toFTP := TFTPSend.Create;
  1772. try
  1773. if FromUser <> '' then
  1774. begin
  1775. FromFTP.Username := FromUser;
  1776. FromFTP.Password := FromPass;
  1777. end;
  1778. if ToUser <> '' then
  1779. begin
  1780. ToFTP.Username := ToUser;
  1781. ToFTP.Password := ToPass;
  1782. end;
  1783. FromFTP.TargetHost := FromIP;
  1784. FromFTP.TargetPort := FromPort;
  1785. ToFTP.TargetHost := ToIP;
  1786. ToFTP.TargetPort := ToPort;
  1787. if not FromFTP.Login then
  1788. Exit;
  1789. if not ToFTP.Login then
  1790. Exit;
  1791. if (FromFTP.FTPCommand('PASV') div 100) <> 2 then
  1792. Exit;
  1793. FromFTP.ParseRemote(FromFTP.ResultString);
  1794. s := ReplaceString(FromFTP.DataIP, '.', ',');
  1795. s := 'PORT ' + s + ',' + IntToStr(StrToIntDef(FromFTP.DataPort, 0) div 256)
  1796. + ',' + IntToStr(StrToIntDef(FromFTP.DataPort, 0) mod 256);
  1797. if (ToFTP.FTPCommand(s) div 100) <> 2 then
  1798. Exit;
  1799. x := ToFTP.FTPCommand('RETR ' + FromFile);
  1800. if (x div 100) <> 1 then
  1801. Exit;
  1802. x := FromFTP.FTPCommand('STOR ' + ToFile);
  1803. if (x div 100) <> 1 then
  1804. Exit;
  1805. FromFTP.Timeout := 21600000;
  1806. x := FromFTP.ReadResult;
  1807. if (x div 100) <> 2 then
  1808. Exit;
  1809. ToFTP.Timeout := 21600000;
  1810. x := ToFTP.ReadResult;
  1811. if (x div 100) <> 2 then
  1812. Exit;
  1813. Result := True;
  1814. finally
  1815. ToFTP.Free;
  1816. FromFTP.Free;
  1817. end;
  1818. end;
  1819. end.