home *** CD-ROM | disk | FTP | other *** search
/ Chip 2002 November / Chip_2002-11_cd1.bin / zkuste / delphi / kompon / d3456 / SYNAPSE.ZIP / source / lib / FTPsend.pas < prev    next >
Pascal/Delphi Source File  |  2002-08-06  |  33KB  |  1,141 lines

  1. {==============================================================================|
  2. | Project : Delphree - Synapse                                   | 002.003.001 |
  3. |==============================================================================|
  4. | Content: FTP client                                                          |
  5. |==============================================================================|
  6. | Copyright (c)1999-2002, 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-2002.               |
  37. | All Rights Reserved.                                                         |
  38. |==============================================================================|
  39. | Contributor(s):                                                              |
  40. |   Petr Esner <petr.esner@atlas.cz>                                           |
  41. |==============================================================================|
  42. | History: see HISTORY.HTM from distribution package                           |
  43. |          (Found at URL: http://www.ararat.cz/synapse/)                       |
  44. |==============================================================================}
  45.  
  46. {$WEAKPACKAGEUNIT ON}
  47.  
  48. unit FTPsend;
  49.  
  50. interface
  51.  
  52. uses
  53.   SysUtils, Classes,
  54.   blcksock, SynaUtil, SynaCode;
  55.  
  56. const
  57.   cFtpProtocol = 'ftp';
  58.   cFtpDataProtocol = 'ftp-data';
  59.  
  60.   FTP_OK = 255;
  61.   FTP_ERR = 254;
  62.  
  63. type
  64.   TLogonActions = array [0..17] of byte;
  65.  
  66.   TFTPStatus = procedure(Sender: TObject; Response: Boolean;
  67.     const Value: string) of object;
  68.  
  69.   TFTPListRec = class(TObject)
  70.   public
  71.     FileName: string;
  72.     Directory: Boolean;
  73.     Readable: Boolean;
  74.     FileSize: Longint;
  75.     FileTime: TDateTime;
  76.   end;
  77.  
  78.   TFTPList = class(TObject)
  79.   private
  80.     FList: TList;
  81.   public
  82.     constructor Create;
  83.     destructor Destroy; override;
  84.     procedure Clear;
  85.     function ParseLine(Value: string): Boolean;
  86.   published
  87.     property List: TList read FList;
  88.   end;
  89.  
  90.   TFTPSend = class(TSynaClient)
  91.   private
  92.     FOnStatus: TFTPStatus;
  93.     FSock: TTCPBlockSocket;
  94.     FDSock: TTCPBlockSocket;
  95.     FResultCode: Integer;
  96.     FResultString: string;
  97.     FFullResult: TStringList;
  98.     FUsername: string;
  99.     FPassword: string;
  100.     FAccount: string;
  101.     FFWHost: string;
  102.     FFWPort: string;
  103.     FFWUsername: string;
  104.     FFWPassword: string;
  105.     FFWMode: integer;
  106.     FDataStream: TMemoryStream;
  107.     FDataIP: string;
  108.     FDataPort: string;
  109.     FDirectFile: Boolean;
  110.     FDirectFileName: string;
  111.     FCanResume: Boolean;
  112.     FPassiveMode: Boolean;
  113.     FForceDefaultPort: Boolean;
  114.     FFtpList: TFTPList;
  115.     function Auth(Mode: integer): Boolean;
  116.     function Connect: Boolean;
  117.     function InternalStor(const Command: string; RestoreAt: integer): Boolean;
  118.     function DataSocket: Boolean;
  119.     function AcceptDataSocket: Boolean;
  120.     function DataRead(const DestStream: TStream): Boolean;
  121.     function DataWrite(const SourceStream: TStream): Boolean;
  122.   protected
  123.     procedure DoStatus(Response: Boolean; const Value: string);
  124.   public
  125.     CustomLogon: TLogonActions;
  126.     constructor Create;
  127.     destructor Destroy; override;
  128.     function ReadResult: Integer;
  129.     procedure ParseRemote(Value: string);
  130.     function FTPCommand(const Value: string): integer;
  131.     function Login: Boolean;
  132.     procedure Logout;
  133.     procedure Abort;
  134.     function List(Directory: string; NameList: Boolean): Boolean;
  135.     function RetriveFile(const FileName: string; Restore: Boolean): Boolean;
  136.     function StoreFile(const FileName: string; Restore: Boolean): Boolean;
  137.     function StoreUniqueFile: Boolean;
  138.     function AppendFile(const FileName: string): Boolean;
  139.     function RenameFile(const OldName, NewName: string): Boolean;
  140.     function DeleteFile(const FileName: string): Boolean;
  141.     function FileSize(const FileName: string): integer;
  142.     function NoOp: Boolean;
  143.     function ChangeWorkingDir(const Directory: string): Boolean;
  144.     function ChangeToRootDir: Boolean;
  145.     function DeleteDir(const Directory: string): Boolean;
  146.     function CreateDir(const Directory: string): Boolean;
  147.     function GetCurrentDir: String;
  148.   published
  149.     property ResultCode: Integer read FResultCode;
  150.     property ResultString: string read FResultString;
  151.     property FullResult: TStringList read FFullResult;
  152.     property Username: string read FUsername Write FUsername;
  153.     property Password: string read FPassword Write FPassword;
  154.     property Account: string read FAccount Write FAccount;
  155.     property FWHost: string read FFWHost Write FFWHost;
  156.     property FWPort: string read FFWPort Write FFWPort;
  157.     property FWUsername: string read FFWUsername Write FFWUsername;
  158.     property FWPassword: string read FFWPassword Write FFWPassword;
  159.     property FWMode: integer read FFWMode Write FFWMode;
  160.     property Sock: TTCPBlockSocket read FSock;
  161.     property DSock: TTCPBlockSocket read FDSock;
  162.     property DataStream: TMemoryStream read FDataStream;
  163.     property DataIP: string read FDataIP;
  164.     property DataPort: string read FDataPort;
  165.     property DirectFile: Boolean read FDirectFile Write FDirectFile;
  166.     property DirectFileName: string read FDirectFileName Write FDirectFileName;
  167.     property CanResume: Boolean read FCanResume;
  168.     property PassiveMode: Boolean read FPassiveMode Write FPassiveMode;
  169.     property ForceDefaultPort: Boolean read FForceDefaultPort Write FForceDefaultPort;
  170.     property OnStatus: TFTPStatus read FOnStatus write FOnStatus;
  171.     property FtpList: TFTPList read FFtpList;
  172.   end;
  173.  
  174. function FtpGetFile(const IP, Port, FileName, LocalFile,
  175.   User, Pass: string): Boolean;
  176. function FtpPutFile(const IP, Port, FileName, LocalFile,
  177.   User, Pass: string): Boolean;
  178. function FtpInterServerTransfer(
  179.   const FromIP, FromPort, FromFile, FromUser, FromPass: string;
  180.   const ToIP, ToPort, ToFile, ToUser, ToPass: string): Boolean;
  181.  
  182. implementation
  183.  
  184. const
  185.   CRLF = #13#10;
  186.  
  187. constructor TFTPSend.Create;
  188. begin
  189.   inherited Create;
  190.   FFullResult := TStringList.Create;
  191.   FDataStream := TMemoryStream.Create;
  192.   FSock := TTCPBlockSocket.Create;
  193.   FDSock := TTCPBlockSocket.Create;
  194.   FFtpList := TFTPList.Create;
  195.   FTimeout := 300000;
  196.   FTargetPort := cFtpProtocol;
  197.   FUsername := 'anonymous';
  198.   FPassword := 'anonymous@' + FSock.LocalName;
  199.   FDirectFile := False;
  200.   FPassiveMode := True;
  201.   FForceDefaultPort := False;
  202.   FAccount := '';
  203.   FFWHost := '';
  204.   FFWPort := cFtpProtocol;
  205.   FFWUsername := '';
  206.   FFWPassword := '';
  207.   FFWMode := 0;
  208. end;
  209.  
  210. destructor TFTPSend.Destroy;
  211. begin
  212.   FDSock.Free;
  213.   FSock.Free;
  214.   FFTPList.Free;
  215.   FDataStream.Free;
  216.   FFullResult.Free;
  217.   inherited Destroy;
  218. end;
  219.  
  220. procedure TFTPSend.DoStatus(Response: Boolean; const Value: string);
  221. begin
  222.   if assigned(OnStatus) then
  223.     OnStatus(Self, Response, Value);
  224. end;
  225.  
  226. function TFTPSend.ReadResult: Integer;
  227. var
  228.   s,c: string;
  229. begin
  230.   Result := 0;
  231.   FFullResult.Clear;
  232.   c := '';
  233.   repeat
  234.     s := FSock.RecvString(FTimeout);
  235.     if c = '' then
  236.       c :=Copy(s, 1, 3)+' ';
  237.     FResultString := s;
  238.     FFullResult.Add(s);
  239.     if FSock.LastError <> 0 then
  240.       Break;
  241.   until Pos(c, s) = 1;
  242.   s := FFullResult[0];
  243.   if Length(s) >= 3 then
  244.     Result := StrToIntDef(Copy(s, 1, 3), 0);
  245.   FResultCode := Result;
  246. end;
  247.  
  248. function TFTPSend.FTPCommand(const Value: string): integer;
  249. begin
  250.   FSock.SendString(Value + CRLF);
  251.   DoStatus(False, Value);
  252.   Result := ReadResult;
  253.   DoStatus(True, FResultString);
  254. end;
  255.  
  256. // based on idea by Petr Esner <petr.esner@atlas.cz>
  257. function TFTPSend.Auth(Mode: integer): Boolean;
  258. const
  259.   // Direct connection USER[+PASS[+ACCT]]
  260.   Action0: TLogonActions =
  261.     (0, FTP_OK, 3, 1, FTP_OK, 6, 2, FTP_OK, FTP_ERR, 0, 0, 0, 0, 0, 0, 0, 0, 0);
  262.   // SITE <hostname>
  263.   Action1: TLogonActions =
  264.     (3, 6, 3, 4, 6, FTP_ERR, 5, FTP_ERR, 9, 0, FTP_OK, 12, 1, FTP_OK, 15, 2,
  265.     FTP_OK, FTP_ERR);
  266.   // USER after logon
  267.   Action2: TLogonActions =
  268.     (3, 6, 3, 4, 6, FTP_ERR, 6, FTP_OK, 9, 1, FTP_OK, 12, 2, FTP_OK, FTP_ERR,
  269.      0, 0, 0);
  270.   // Transparent
  271.   Action3: TLogonActions =
  272.     (3, 6, 3, 4, 6, FTP_ERR, 0, FTP_OK, 9, 1, FTP_OK, 12, 2, FTP_OK, FTP_ERR,
  273.      0, 0, 0);
  274.   // proxy OPEN
  275.   Action4: TLogonActions =
  276.     (7, 3, 3, 0, FTP_OK, 6, 1, FTP_OK, 9, 2, FTP_OK, FTP_ERR,
  277.      0, 0, 0, 0, 0, 0);
  278.   // USER with no logon
  279.   Action5: TLogonActions =
  280.     (6, FTP_OK, 3, 1, FTP_OK, 6, 2, FTP_OK, FTP_ERR, 0, 0, 0, 0, 0, 0, 0, 0, 0);
  281.   // USER fireID@remotehost
  282.   Action6: TLogonActions =
  283.     (8, 6, 3, 4, 6, FTP_ERR, 0, FTP_OK, 9, 1, FTP_OK, 12, 2, FTP_OK, FTP_ERR,
  284.      0, 0, 0);
  285.   // USER remoteID@remotehost fireID
  286.   Action7: TLogonActions =
  287.     (9, FTP_ERR, 3, 1, FTP_OK, 6, 2, FTP_OK, FTP_ERR, 0, 0, 0, 0, 0, 0, 0, 0, 0);
  288.   // USER remoteID@fireID@remotehost
  289.   Action8: TLogonActions =
  290.     (10, FTP_OK, 3, 11, FTP_OK, 6, 2, FTP_OK, FTP_ERR, 0, 0, 0, 0, 0, 0, 0, 0, 0);
  291. var
  292.   FTPServer: string;
  293.   LogonActions: TLogonActions;
  294.   i: integer;
  295.   s: string;
  296.   x: integer;
  297. begin
  298.   Result := False;
  299.   if FFWHost = '' then
  300.     Mode := 0;
  301.   if (FTargetPort = cFtpProtocol) or (FTargetPort = '21') then
  302.     FTPServer := FTargetHost
  303.   else
  304.     FTPServer := FTargetHost + ':' + FTargetPort;
  305.   case Mode of
  306.     -1:
  307.       LogonActions := CustomLogon;
  308.     1:
  309.       LogonActions := Action1;
  310.     2:
  311.       LogonActions := Action2;
  312.     3:
  313.       LogonActions := Action3;
  314.     4:
  315.       LogonActions := Action4;
  316.     5:
  317.       LogonActions := Action5;
  318.     6:
  319.       LogonActions := Action6;
  320.     7:
  321.       LogonActions := Action7;
  322.     8:
  323.       LogonActions := Action8;
  324.   else
  325.     LogonActions := Action0;
  326.   end;
  327.   i := 0;
  328.   repeat
  329.     case LogonActions[i] of
  330.       0:  s := 'USER ' + FUserName;
  331.       1:  s := 'PASS ' + FPassword;
  332.       2:  s := 'ACCT ' + FAccount;
  333.       3:  s := 'USER ' + FFWUserName;
  334.       4:  s := 'PASS ' + FFWPassword;
  335.       5:  s := 'SITE ' + FTPServer;
  336.       6:  s := 'USER ' + FUserName + '@' + FTPServer;
  337.       7:  s := 'OPEN ' + FTPServer;
  338.       8:  s := 'USER ' + FFWUserName + '@' + FTPServer;
  339.       9:  s := 'USER ' + FUserName + '@' + FTPServer + ' ' + FFWUserName;
  340.       10: s := 'USER ' + FUserName + '@' + FFWUserName + '@' + FTPServer;
  341.       11: s := 'PASS ' + FPassword + '@' + FFWPassword;
  342.     end;
  343.     x := FTPCommand(s);
  344.     x := x div 100;
  345.     if (x <> 2) and (x <> 3) then
  346.       Exit;
  347.     i := LogonActions[i + x - 1];
  348.     case i of
  349.       FTP_ERR:
  350.         Exit;
  351.       FTP_OK:
  352.         begin
  353.           Result := True;
  354.           Exit;
  355.         end;
  356.     end;
  357.   until False;
  358. end;
  359.  
  360.  
  361. function TFTPSend.Connect: Boolean;
  362. begin
  363.   FSock.CloseSocket;
  364.   FSock.CreateSocket;
  365.   FSock.Bind(FIPInterface, cAnyPort);
  366.   if FFWHost = '' then
  367.     FSock.Connect(FTargetHost, FTargetPort)
  368.   else
  369.     FSock.Connect(FFWHost, FFWPort);
  370.   Result := FSock.LastError = 0;
  371. end;
  372.  
  373. function TFTPSend.Login: Boolean;
  374. begin
  375.   Result := False;
  376.   FCanResume := False;
  377.   if not Connect then
  378.     Exit;
  379.   if (ReadResult div 100) <> 2 then
  380.     Exit;
  381.   if not Auth(FFWMode) then
  382.     Exit;
  383.   FTPCommand('TYPE I');
  384.   FTPCommand('STRU F');
  385.   FTPCommand('MODE S');
  386.   if FTPCommand('REST 0') = 350 then
  387.     if FTPCommand('REST 1') = 350 then
  388.     begin
  389.       FTPCommand('REST 0');
  390.       FCanResume := True;
  391.     end;
  392.   Result := True;
  393. end;
  394.  
  395. procedure TFTPSend.Logout;
  396. begin
  397.   FTPCommand('QUIT');
  398.   FSock.CloseSocket;
  399. end;
  400.  
  401. procedure TFTPSend.ParseRemote(Value: string);
  402. var
  403.   n: integer;
  404.   nb, ne: integer;
  405.   s: string;
  406.   x: integer;
  407. begin
  408.   Value := trim(Value);
  409.   nb := Pos('(',Value);
  410.   ne := Pos(')',Value);
  411.   if (nb = 0) or (ne = 0) then
  412.   begin
  413.     nb:=RPos(' ',Value);
  414.     s:=Copy(Value, nb + 1, Length(Value) - nb);
  415.   end
  416.   else
  417.   begin
  418.     s:=Copy(Value,nb+1,ne-nb-1);
  419.   end;
  420.   for n := 1 to 4 do
  421.     if n = 1 then
  422.       FDataIP := Fetch(s, ',')
  423.     else
  424.       FDataIP := FDataIP + '.' + Fetch(s, ',');
  425.   x := StrToIntDef(Fetch(s, ','), 0) * 256;
  426.   x := x + StrToIntDef(Fetch(s, ','), 0);
  427.   FDataPort := IntToStr(x);
  428. end;
  429.  
  430. function TFTPSend.DataSocket: boolean;
  431. var
  432.   s: string;
  433. begin
  434.   Result := False;
  435.   if FPassiveMode then
  436.   begin
  437.     if (FTPCommand('PASV') div 100) <> 2 then
  438.       Exit;
  439.     ParseRemote(FResultString);
  440.     FDSock.CloseSocket;
  441.     FDSock.CreateSocket;
  442.     FSock.Bind(FIPInterface, cAnyPort);
  443.     FDSock.Connect(FDataIP, FDataPort);
  444.     Result := FDSock.LastError = 0;
  445.   end
  446.   else
  447.   begin
  448.     FDSock.CloseSocket;
  449.     FDSock.CreateSocket;
  450.     if FForceDefaultPort then
  451.       s := cFtpDataProtocol
  452.     else
  453.       s := '0';
  454.     //IP cannot be '0.0.0.0'!
  455.     if FIPInterface = cAnyHost then
  456.       FDSock.Bind(FDSock.LocalName, s)
  457.     else
  458.       FSock.Bind(FIPInterface, s);
  459.     if FDSock.LastError <> 0 then
  460.       Exit;
  461.     FDSock.Listen;
  462.     FDSock.GetSins;
  463.     FDataIP := FDSock.GetLocalSinIP;
  464.     FDataIP := FDSock.ResolveName(FDataIP);
  465.     FDataPort := IntToStr(FDSock.GetLocalSinPort);
  466.     s := StringReplace(FDataIP, '.', ',');
  467.     s := 'PORT ' + s + ',' + IntToStr(FDSock.GetLocalSinPort div 256)
  468.       + ',' + IntToStr(FDSock.GetLocalSinPort mod 256);
  469.     Result := (FTPCommand(s) div 100) = 2;
  470.   end;
  471. end;
  472.  
  473. function TFTPSend.AcceptDataSocket: Boolean;
  474. var
  475.   x: integer;
  476. begin
  477.   if FPassiveMode then
  478.     Result := True
  479.   else
  480.   begin
  481.     Result := False;
  482.     if FDSock.CanRead(FTimeout) then
  483.     begin
  484.       x := FDSock.Accept;
  485.       if not FDSock.UsingSocks then
  486.         FDSock.CloseSocket;
  487.       FDSock.Socket := x;
  488.       Result := True;
  489.     end;
  490.   end;
  491. end;
  492.  
  493. function TFTPSend.DataRead(const DestStream: TStream): Boolean;
  494. var
  495.   x: integer;
  496.   buf: string;
  497. begin
  498.   Result := False;
  499.   try
  500.     if not AcceptDataSocket then
  501.       Exit;
  502.     repeat
  503.       buf := FDSock.RecvPacket(FTimeout);
  504.       if FDSock.LastError = 0 then
  505.         DestStream.Write(Pointer(buf)^, Length(buf));
  506.     until FDSock.LastError <> 0;
  507.     FDSock.CloseSocket;
  508.     x := ReadResult;
  509.     Result := (x div 100) = 2;
  510.   finally
  511.     FDSock.CloseSocket;
  512.   end;
  513. end;
  514.  
  515. function TFTPSend.DataWrite(const SourceStream: TStream): Boolean;
  516. const
  517.   BufSize = 8192;
  518. var
  519.   Bytes: integer;
  520.   bc, lb: integer;
  521.   n, x: integer;
  522.   Buf: string;
  523. begin
  524.   Result := False;
  525.   try
  526.     if not AcceptDataSocket then
  527.       Exit;
  528.     Bytes := SourceStream.Size - SourceStream.Position;
  529.     bc := Bytes div BufSize;
  530.     lb := Bytes mod BufSize;
  531.     SetLength(Buf, BufSize);
  532.     for n := 1 to bc do
  533.     begin
  534.       SourceStream.read(Pointer(buf)^, BufSize);
  535.       FDSock.SendBuffer(Pchar(buf), BufSize);
  536.       if FDSock.LastError <> 0 then
  537.         Exit;
  538.     end;
  539.     SetLength(Buf, lb);
  540.     SourceStream.read(Pointer(buf)^, lb);
  541.     FDSock.SendBuffer(Pchar(buf), lb);
  542.     if FDSock.LastError <> 0 then
  543.       Exit;
  544.     FDSock.CloseSocket;
  545.     x := ReadResult;
  546.     Result := (x div 100) = 2;
  547.   finally
  548.     FDSock.CloseSocket;
  549.   end;
  550. end;
  551.  
  552. function TFTPSend.List(Directory: string; NameList: Boolean): Boolean;
  553. var
  554.   x: integer;
  555.   l: TStringList;
  556. begin
  557.   Result := False;
  558.   FDataStream.Clear;
  559.   FFTPList.Clear;
  560.   if Directory <> '' then
  561.     Directory := ' ' + Directory;
  562.   if not DataSocket then
  563.     Exit;
  564.   FTPCommand('TYPE A');
  565.   if NameList then
  566.     x := FTPCommand('NLST' + Directory)
  567.   else
  568.     x := FTPCommand('LIST' + Directory);
  569.   if (x div 100) <> 1 then
  570.     Exit;
  571.   Result := DataRead(FDataStream);
  572.   if not NameList then
  573.   begin
  574.     l := TStringList.Create;
  575.     try
  576.       FDataStream.Seek(0, soFromBeginning);
  577.       l.LoadFromStream(FDataStream);
  578.       for x := 0 to l.Count - 1 do
  579.         FFTPList.ParseLine(l[x]);
  580.     finally
  581.       l.Free;
  582.     end;
  583.   end;
  584.   FDataStream.Seek(0, soFromBeginning);
  585. end;
  586.  
  587. function TFTPSend.RetriveFile(const FileName: string; Restore: Boolean): Boolean;
  588. var
  589.   RetrStream: TStream;
  590. begin
  591.   Result := False;
  592.   if FileName = '' then
  593.     Exit;
  594.   Restore := Restore and FCanResume;
  595.   if FDirectFile then
  596.     if Restore and FileExists(FDirectFileName) then
  597.       RetrStream := TFileStream.Create(FDirectFileName,
  598.         fmOpenReadWrite  or fmShareExclusive)
  599.     else
  600.       RetrStream := TFileStream.Create(FDirectFileName,
  601.         fmCreate or fmShareDenyWrite)
  602.   else
  603.     RetrStream := FDataStream;
  604.   try
  605.     if not DataSocket then
  606.       Exit;
  607.     FTPCommand('TYPE I');
  608.     if Restore then
  609.     begin
  610.       RetrStream.Seek(0, soFromEnd);
  611.       if (FTPCommand('REST ' + IntToStr(RetrStream.Size)) div 100) <> 3 then
  612.         Exit;
  613.     end
  614.     else
  615.       if RetrStream is TMemoryStream then
  616.         TMemoryStream(RetrStream).Clear;
  617.     if (FTPCommand('RETR ' + FileName) div 100) <> 1 then
  618.       Exit;
  619.     Result := DataRead(RetrStream);
  620.     if not FDirectFile then
  621.       RetrStream.Seek(0, soFromBeginning);
  622.   finally
  623.     if FDirectFile then
  624.       RetrStream.Free;
  625.   end;
  626. end;
  627.  
  628. function TFTPSend.InternalStor(const Command: string; RestoreAt: integer): Boolean;
  629. var
  630.   SendStream: TStream;
  631.   StorSize: integer;
  632. begin
  633.   Result := False;
  634.   if FDirectFile then
  635.     if not FileExists(FDirectFileName) then
  636.       Exit
  637.     else
  638.       SendStream := TFileStream.Create(FDirectFileName,
  639.         fmOpenRead or fmShareDenyWrite)
  640.   else
  641.     SendStream := FDataStream;
  642.   try
  643.     if not DataSocket then
  644.       Exit;
  645.     FTPCommand('TYPE I');
  646.     StorSize := SendStream.Size;
  647.     if not FCanResume then
  648.       RestoreAt := 0;
  649.     if RestoreAt = StorSize then
  650.     begin
  651.       Result := True;
  652.       Exit;
  653.     end;
  654.     if RestoreAt > StorSize then
  655.       RestoreAt := 0;
  656.     FTPCommand('ALLO ' + IntToStr(StorSize - RestoreAt));
  657.     if FCanResume then
  658.       if (FTPCommand('REST ' + IntToStr(RestoreAt)) div 100) <> 3 then
  659.         Exit;
  660.     SendStream.Seek(RestoreAt, soFromBeginning);
  661.     if (FTPCommand(Command) div 100) <> 1 then
  662.       Exit;
  663.     Result := DataWrite(SendStream);
  664.   finally
  665.     if FDirectFile then
  666.       SendStream.Free;
  667.   end;
  668. end;
  669.  
  670. function TFTPSend.StoreFile(const FileName: string; Restore: Boolean): Boolean;
  671. var
  672.   RestoreAt: integer;
  673. begin
  674.   Result := False;
  675.   if FileName = '' then
  676.     Exit;
  677.   RestoreAt := 0;
  678.   Restore := Restore and FCanResume;
  679.   if Restore then
  680.   begin
  681.     RestoreAt := Self.FileSize(FileName);
  682.     if RestoreAt < 0 then
  683.       RestoreAt := 0;
  684.   end;
  685.   Result := InternalStor('STOR ' + FileName, RestoreAt);
  686. end;
  687.  
  688. function TFTPSend.StoreUniqueFile: Boolean;
  689. begin
  690.   Result := InternalStor('STOU', 0);
  691. end;
  692.  
  693. function TFTPSend.AppendFile(const FileName: string): Boolean;
  694. begin
  695.   Result := False;
  696.   if FileName = '' then
  697.     Exit;
  698.   Result := InternalStor('APPE '+FileName, 0);
  699. end;
  700.  
  701. function TFTPSend.NoOp: Boolean;
  702. begin
  703.   Result := (FTPCommand('NOOP') div 100) = 2;
  704. end;
  705.  
  706. function TFTPSend.RenameFile(const OldName, NewName: string): Boolean;
  707. begin
  708.   Result := False;
  709.   if (FTPCommand('RNFR ' + OldName) div 100) <> 3  then
  710.     Exit;
  711.   Result := (FTPCommand('RNTO ' + NewName) div 100) = 2;
  712. end;
  713.  
  714. function TFTPSend.DeleteFile(const FileName: string): Boolean;
  715. begin
  716.   Result := (FTPCommand('DELE ' + FileName) div 100) = 2;
  717. end;
  718.  
  719. function TFTPSend.FileSize(const FileName: string): integer;
  720. var
  721.   s: string;
  722. begin
  723.   Result := -1;
  724.   if (FTPCommand('SIZE ' + FileName) div 100) = 2 then
  725.   begin
  726.     s := SeparateRight(ResultString, ' ');
  727.     s := SeparateLeft(s, ' ');
  728.     Result := StrToIntDef(s, -1);
  729.   end;
  730. end;
  731.  
  732. function TFTPSend.ChangeWorkingDir(const Directory: string): Boolean;
  733. begin
  734.   Result := (FTPCommand('CWD ' + Directory) div 100) = 2;
  735. end;
  736.  
  737. function TFTPSend.ChangeToRootDir: Boolean;
  738. begin
  739.   Result := (FTPCommand('CDUP') div 100) = 2;
  740. end;
  741.  
  742. function TFTPSend.DeleteDir(const Directory: string): Boolean;
  743. begin
  744.   Result := (FTPCommand('RMD ' + Directory) div 100) = 2;
  745. end;
  746.  
  747. function TFTPSend.CreateDir(const Directory: string): Boolean;
  748. begin
  749.   Result := (FTPCommand('MKD ' + Directory) div 100) = 2;
  750. end;
  751.  
  752. function TFTPSend.GetCurrentDir: String;
  753. begin
  754.   Result := '';
  755.   if (FTPCommand('PWD') div 100) = 2 then
  756.   begin
  757.     Result := SeparateRight(FResultString, '"');
  758.     Result := Separateleft(Result, '"');
  759.   end;
  760. end;
  761.  
  762. {==============================================================================}
  763.  
  764. constructor TFTPList.Create;
  765. begin
  766.   inherited Create;
  767.   FList := TList.Create;
  768. end;
  769.  
  770. destructor TFTPList.Destroy;
  771. begin
  772.   Clear;
  773.   FList.Free;
  774.   inherited Destroy;
  775. end;
  776.  
  777. procedure TFTPList.Clear;
  778. var
  779.   n:integer;
  780. begin
  781.   for n := 0 to FList.Count - 1 do
  782.     if Assigned(FList[n]) then
  783.       TFTPListRec(FList[n]).Free;
  784.   FList.Clear;
  785. end;
  786.  
  787. // based on idea by D. J. Bernstein, djb@pobox.com
  788. // fixed UNIX style decoding by Alex, akudrin@rosbi.ru
  789. function TFTPList.ParseLine(Value: string): Boolean;
  790. var
  791.   flr: TFTPListRec;
  792.   s: string;
  793.   state: integer;
  794.   year: Word;
  795.   month: Word;
  796.   mday: Word;
  797.   t: TDateTime;
  798.   x: integer;
  799.   al_tmp : array[1..2] of string; // alex
  800. begin
  801.   Result := False;
  802.   if Length(Value) < 2 then
  803.     Exit;
  804.  
  805.   year := 0;
  806.   month := 0;
  807.   mday := 0;
  808.   t := 0;
  809.   flr := TFTPListRec.Create;
  810.   try
  811.     flr.FileName := '';
  812.     flr.Directory := False;
  813.     flr.Readable := False;
  814.     flr.FileSize := 0;
  815.     flr.FileTime := 0;
  816.     Value := Trim(Value);
  817.   {EPLF
  818.     See http://pobox.com/~djb/proto/eplf.txt
  819.   "+i8388621.29609,m824255902,/," + #9 + "tdev"
  820.   "+i8388621.44468,m839956783,r,s10376," + #9 + "RFCEPLF" }
  821.     if Value[1] = '+' then
  822.     begin
  823.       s := Fetch(Value, ',');
  824.       while s <> '' do
  825.       begin
  826.         if s[1] = #9 then
  827.         begin
  828.           flr.FileName := Copy(s, 2, Length(s) - 1);
  829.           Result := True;
  830.         end;
  831.         case s[1] of
  832.           '/':
  833.             flr.Directory := true;
  834.           'r':
  835.             flr.Readable := true;
  836.           's':
  837.             flr.FileSize := StrToIntDef(Copy(s, 2, Length(s) - 1), 0);
  838.           'm':
  839.             flr.FileTime := (StrToIntDef(Copy(s, 2, Length(s) - 1), 0) / 86400)
  840.               + 25569;
  841.         end;
  842.         s := Fetch(Value, ',');
  843.       end;
  844.       Exit;
  845.     end;
  846.  
  847.   {UNIX-style listing, without inum and without blocks
  848.    Permissions   Owner     Group        Size  Date/Time   Name
  849.  
  850.   "-rw-r--r--   1 root     other        531 Jan 29 03:26 README"
  851.   "dr-xr-xr-x   2 root     other        512 Apr  8  1994 etc"
  852.   "dr-xr-xr-x   2 root                  512 Apr  8  1994 etc"
  853.   "lrwxrwxrwx   1 root     other        7   Jan 25 00:17 bin -> usr/bin"
  854.  
  855.     Also produced by Microsoft's FTP servers for Windows:
  856.   "----------   1 owner    group         1803128 Jul 10 10:18 ls-lR.Z"
  857.  
  858.   Also WFTPD for MSDOS:
  859.   "-rwxrwxrwx   1 noone    nogroup      322 Aug 19  1996 message.ftp"
  860.  
  861.   Also NetWare:
  862.   "d [R----F--] supervisor            512       Jan 16 18:53    login"
  863.   "- [R----F--] rhesus             214059       Oct 20 15:27    cx.exe"
  864.  
  865.   Also NetPresenz for the Mac:
  866.   "-------r--         326  1391972  1392298 Nov 22  1995 MegaPhone.sit"
  867.   "drwxrwxr-x               folder        2 May 10  1996 network" }
  868.  
  869.     if (Value[1] = 'b') or
  870.        (Value[1] = 'c') or
  871.        (Value[1] = 'd') or
  872.        (Value[1] = 'l') or
  873.        (Value[1] = 'p') or
  874.        (Value[1] = 's') or
  875.        (Value[1] = '-') then
  876.     begin
  877.  
  878.       // alex begin
  879.       // default year
  880.       DecodeDate(date,year,month,mday);  // alex
  881.       month:=0;
  882.       mday :=0;
  883.  
  884.       if Value[1] = 'd'      then flr.Directory := True
  885.       else if Value[1] = '-' then flr.Readable := True
  886.       else if Value[1] = 'l' then
  887.       begin
  888.         flr.Directory := True;
  889.         flr.Readable := True;
  890.       end;
  891.  
  892.       state:=1;
  893.       s := Fetch(Value, ' ');
  894.       while s<>'' do
  895.       begin
  896.           month:=GetMonthNumber(s);
  897.           if month>0 then
  898.              break;
  899.           al_tmp[state]:=s;
  900.           if state=1 then state:=2
  901.           else            state:=1;
  902.           s := Fetch(Value, ' ');
  903.       end;
  904.       if month>0 then begin
  905.          if state=1 then
  906.               flr.FileSize := StrToIntDef(al_tmp[2], 0)
  907.          else flr.FileSize := StrToIntDef(al_tmp[1], 0);
  908.  
  909.          state:=1;
  910.          s := Fetch(Value, ' ');
  911.          while s <> '' do
  912.          begin
  913.               case state of
  914.                  1 : mday := StrToIntDef(s, 0);
  915.                  2 : begin
  916.                        if (Pos(':', s) > 0) then
  917.                           t := GetTimeFromStr(s)
  918.                        else if Length(s) = 4 then
  919.                           year := StrToIntDef(s, 0)
  920.                        else Exit;
  921.                        if (year = 0) or (month = 0) or (mday = 0) then
  922.                            Exit;
  923.                        flr.FileTime := t + Encodedate(year, month, mday);
  924.                      end;
  925.                  3 : begin
  926.                        if Value <> '' then
  927.                          s := s + ' ' + Value;
  928.                        s := SeparateLeft(s, ' -> ');
  929.                        flr.FileName := s;
  930.                        Result := True;
  931.                        break;
  932.                      end;
  933.               end;
  934.               inc(state);
  935.               s := Fetch(Value, ' ');
  936.          end;
  937.       end;
  938.       // alex end
  939.       exit;
  940.     end;
  941.   {Microsoft NT 4.0 FTP Service
  942.   10-20-98  08:57AM               619098 rizrem.zip
  943.   11-12-98  11:54AM       <DIR>          test         }
  944.     if (Value[1] = '1') or (Value[1] = '0') then
  945.     begin
  946.       if Length(Value) < 8 then
  947.         Exit;
  948.       if (Ord(Value[2]) < 48) or (Ord(Value[2]) > 57) then
  949.         Exit;
  950.       if Value[3] <> '-' then
  951.         Exit;
  952.       s := Fetch(Value, ' ');
  953.       t := GetDateMDYFromStr(s);
  954.       if t = 0 then
  955.         Exit;
  956.       if Value = '' then
  957.         Exit;
  958.       s := Fetch(Value, ' ');
  959.       flr.FileTime := t + GetTimeFromStr(s);
  960.       if Value = '' then
  961.         Exit;
  962.       s := Fetch(Value, ' ');
  963.       if s[1] = '<' then
  964.         flr.Directory := True
  965.       else
  966.       begin
  967.         flr.Readable := true;
  968.         flr.Filesize := StrToIntDef(s, 0);
  969.       end;
  970.       if Value = '' then
  971.         Exit;
  972.       flr.FileName := Trim(s);
  973.       Result := True;
  974.       Exit;
  975.     end;
  976.   {MultiNet
  977.   "00README.TXT;1      2 30-DEC-1996 17:44 [SYSTEM] (RWED,RWED,RE,RE)"
  978.   "CORE.DIR;1          1  8-SEP-1996 16:09 [SYSTEM] (RWE,RWE,RE,RE)"
  979.  
  980.   and non-MutliNet VMS:
  981.   "CII-MANUAL.TEX;1  213/216  29-JAN-1996 03:33:12  [ANONYMOU,ANONYMOUS]   (RWED,RWED,,)" }
  982.     x := Pos(';', Value);
  983.     if x > 0 then
  984.     begin
  985.       s := Fetch(Value, ';');
  986.       if Uppercase(Copy(s,Length(s) - 4, 4)) = '.DIR' then
  987.       begin
  988.         flr.FileName := Copy(s, 1, Length(s) - 4);
  989.         flr.Directory := True;
  990.       end
  991.       else
  992.       begin
  993.         flr.FileName := s;
  994.         flr.Readable := True;
  995.       end;
  996.       s := Fetch(Value, ' ');
  997.       s := Fetch(Value, ' ');
  998.       if Value = '' then
  999.         Exit;
  1000.       s := Fetch(Value, '-');
  1001.       mday := StrToIntDef(s, 0);
  1002.       s := Fetch(Value, '-');
  1003.       month := GetMonthNumber(s);
  1004.       s := Fetch(Value, ' ');
  1005.       year := StrToIntDef(s, 0);
  1006.       s := Fetch(Value, ' ');
  1007.       if Value = '' then
  1008.         Exit;
  1009.       if (year = 0) or (month = 0) or (mday = 0) then
  1010.         Exit;
  1011.       flr.FileTime := GetTimeFromStr(s) + EncodeDate(year, month, mday);
  1012.       Result := True;
  1013.       Exit;
  1014.     end;
  1015.   finally
  1016.     if Result then
  1017.       if flr.Directory and ((flr.FileName = '.') or (flr.FileName = '..')) then
  1018.         Result := False;
  1019.     if Result then
  1020.       FList.Add(flr)
  1021.     else
  1022.       flr.Free;
  1023.   end;
  1024. end;
  1025.  
  1026. {==============================================================================}
  1027.  
  1028. function FtpGetFile(const IP, Port, FileName, LocalFile,
  1029.   User, Pass: string): Boolean;
  1030. begin
  1031.   Result := False;
  1032.   with TFTPSend.Create do
  1033.   try
  1034.     if User <> '' then
  1035.     begin
  1036.       Username := User;
  1037.       Password := Pass;
  1038.     end;
  1039.     TargetHost := IP;
  1040.     TargetPort := Port;
  1041.     if not Login then
  1042.       Exit;
  1043.     DirectFileName := LocalFile;
  1044.     DirectFile:=True;
  1045.     Result := RetriveFile(FileName, False);
  1046.     Logout;
  1047.   finally
  1048.     Free;
  1049.   end;
  1050. end;
  1051.  
  1052. function FtpPutFile(const IP, Port, FileName, LocalFile,
  1053.   User, Pass: string): Boolean;
  1054. begin
  1055.   Result := False;
  1056.   with TFTPSend.Create do
  1057.   try
  1058.     if User <> '' then
  1059.     begin
  1060.       Username := User;
  1061.       Password := Pass;
  1062.     end;
  1063.     TargetHost := IP;
  1064.     TargetPort := Port;
  1065.     if not Login then
  1066.       Exit;
  1067.     DirectFileName := LocalFile;
  1068.     DirectFile:=True;
  1069.     Result := StoreFile(FileName, False);
  1070.     Logout;
  1071.   finally
  1072.     Free;
  1073.   end;
  1074. end;
  1075.  
  1076. function FtpInterServerTransfer(
  1077.   const FromIP, FromPort, FromFile, FromUser, FromPass: string;
  1078.   const ToIP, ToPort, ToFile, ToUser, ToPass: string): Boolean;
  1079. var
  1080.   FromFTP, ToFTP: TFTPSend;
  1081.   s: string;
  1082.   x: integer;
  1083. begin
  1084.   Result := False;
  1085.   FromFTP := TFTPSend.Create;
  1086.   toFTP := TFTPSend.Create;
  1087.   try
  1088.     if FromUser <> '' then
  1089.     begin
  1090.       FromFTP.Username := FromUser;
  1091.       FromFTP.Password := FromPass;
  1092.     end;
  1093.     if ToUser <> '' then
  1094.     begin
  1095.       ToFTP.Username := ToUser;
  1096.       ToFTP.Password := ToPass;
  1097.     end;
  1098.     FromFTP.TargetHost := FromIP;
  1099.     FromFTP.TargetPort := FromPort;
  1100.     ToFTP.TargetHost := ToIP;
  1101.     ToFTP.TargetPort := ToPort;
  1102.     if not FromFTP.Login then
  1103.       Exit;
  1104.     if not ToFTP.Login then
  1105.       Exit;
  1106.     if FromFTP.FTPCommand('PASV') <> 227 then
  1107.       Exit;
  1108.     FromFTP.ParseRemote(FromFTP.ResultString);
  1109.     s := StringReplace(FromFTP.DataIP, '.', ',');
  1110.     s := 'PORT ' + s + ',' + IntToStr(StrToIntDef(FromFTP.DataPort, 0) div 256)
  1111.       + ',' + IntToStr(StrToIntDef(FromFTP.DataPort, 0) mod 256);
  1112.     if ToFTP.FTPCommand(s) <> 200 then
  1113.       Exit;
  1114.     x := FromFTP.FTPCommand('STOR ' + FromFile);
  1115.     if (x <> 125) and (x <> 150) then
  1116.       Exit;
  1117.     x := ToFTP.FTPCommand('RETR ' + ToFile);
  1118.     if (x <> 125) and (x <> 150) then
  1119.       Exit;
  1120.     FromFTP.Timeout := 21600000;
  1121.     x := FromFTP.ReadResult;
  1122.     if (x <> 226) and (x <> 250) then
  1123.       Exit;
  1124.     ToFTP.Timeout := 21600000;
  1125.     x := ToFTP.ReadResult;
  1126.     if (x <> 226) and (x <> 250) then
  1127.       Exit;
  1128.     Result := True;
  1129.   finally
  1130.     ToFTP.Free;
  1131.     FromFTP.Free;
  1132.   end;
  1133. end;
  1134.  
  1135. procedure TFTPSend.Abort;
  1136. begin
  1137.   FDSock.CloseSocket;
  1138. end;
  1139.  
  1140. end.
  1141.