📄 ftpcli.pas
字号:
FState := NewState;
TriggerStateChange;
end;
end;
{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
function TCustomFtpCli.GetBinary : Boolean;
begin
Result := (FType = 'I');
end;
{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
procedure TCustomFtpCli.SetBinary(Value : Boolean);
begin
if Value then
FType := 'I'
else
FType := 'A';
end;
{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
function TCustomFtpCli.Progress : Boolean;
var
Abort : Boolean;
begin
Abort := FALSE;
if Assigned(FOnProgress) then
FOnProgress(Self, FByteCount + FResumeAt, Abort);
if Abort then begin
TriggerDisplay('! Abort requested');
FDataSocket.Close;
end;
Result := not Abort;
end;
{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
procedure TCustomFtpCli.SendCommand(Cmd : String);
begin
if Assigned(FOnCommand) then
FOnCommand(Self, Cmd);
TriggerDisplay('> ' + Cmd);
if FControlSocket.State = wsConnected then
FControlSocket.SendStr(Cmd + #13 + #10);
end;
{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
procedure TCustomFtpCli.HandleError(const Msg : String);
begin
if Assigned(FOnError) then
TriggerError(Msg)
else
raise FtpException.Create(Msg);
end;
{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
{* Return TRUE if component is ready for next operation. }
{* Trigger an error or return FALSE if not ready }
function TCustomFtpCli.CheckReady : Boolean;
begin
Result := (FState in [ftpReady, ftpInternalReady]);
if not Result then
HandleError('FTP component not ready');
end;
{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
procedure TCustomFtpCli.OpenAsync;
begin
if not CheckReady then
Exit;
if FConnected then begin
HandleError('FTP component already connected');
Exit;
end;
if not FHighLevelFlag then
FRequestType := ftpOpenAsync;
FRequestDoneFlag := FALSE;
FReceiveLen := 0;
FRequestResult := 0;
FDnsResult := '';
StateChange(ftpDnsLookup);
case FConnectionType of
ftpDirect, ftpSocks4, ftpSocks4A, ftpSocks5: FControlSocket.DnsLookup(FHostName);
ftpProxy: FControlSocket.DnsLookup(FProxyServer);
end;
end;
{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
procedure TCustomFtpCli.ExecAsync(
RqType : TFtpRequest;
Cmd : String; { Command to execute }
OkResponses : array of Word; { List of responses like '200 221 342' }
DoneAsync : TFtpNextProc); { What to do when done }
var
I : Integer;
begin
if not((Cmd = 'ABOR') or (Cmd = 'STAT') or (Cmd = 'QUIT')) then begin
if not CheckReady then
Exit;
if not FConnected then begin
HandleError('FTP component not connected');
Exit;
end;
end;
if not FHighLevelFlag then
FRequestType := RqType;
for I := 0 to High(OkResponses) do
FOkResponses[I] := OkResponses[I];
FOkResponses[High(OkResponses) + 1] := 0;
FRequestDoneFlag := FALSE;
FNext := NextExecAsync;
FDoneAsync := DoneAsync;
FErrormessage := '';
StateChange(ftpWaitingResponse);
SendCommand(Cmd);
end;
{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
procedure TCustomFtpCli.ExtractMoreResults;
var
NumericCode : LongInt;
p : PChar;
begin
if FRequestResult = 0 then begin
if FFctPrv in [ftpFctSize] then begin
p := GetInteger(@FLastResponse[1], NumericCode);
GetInteger(p, FSizeResult);
end;
if FFctPrv in [ftpFctCDup, ftpFctPwd, ftpFctMkd, ftpFctCwd] then begin
p := GetInteger(@FLastResponse[1], NumericCode);
GetQuotedString(p, FDirResult);
end;
end;
end;
{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
procedure TCustomFtpCli.NextExecAsync;
var
I : Integer;
p : PChar;
begin
DisplayLastResponse;
if not (FLastResponse[1] in ['0'..'9']) then
Exit; { Continuation line, nothing to do }
p := GetInteger(@FLastResponse[1], FStatusCode);
if p^ = '-' then
Exit; { Continuation line, nothing to do }
if FOkResponses[0] = 0 then begin
{ The list of ok responses is empty }
if FStatusCode >= 500 then begin
{ Not a good response }
FRequestResult := FStatusCode;
SetErrorMessage;
end
else
FRequestResult := 0;
end
else begin
{ We have a list of ok response codes }
for I := 0 to High(FOkResponses) do begin
if FOkResponses[I] = 0 then begin
{ No good response found }
FRequestResult := FStatusCode;
SetErrorMessage;
break;
end;
if FOkResponses[I] = FStatusCode then begin
{ Good response found }
FRequestResult := 0;
Break;
end;
end;
end;
if FPassive and (FStatusCode = 227) then
FPasvResponse := FLastResponse;
ExtractMoreResults;
if Assigned(FDoneAsync) then
FDoneAsync
else
TriggerRequestDone(FRequestResult);
end;
{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
procedure TCustomFtpCli.QuitAsync;
begin
DestroyLocalStream;
FFctPrv := ftpFctQuit;
ExecAsync(ftpQuitAsync, 'QUIT', [221], DoneQuitAsync);
end;
{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
procedure TCustomFtpCli.DoneQuitAsync;
begin
FControlSocket.Close;
end;
{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
procedure TCustomFtpCli.CwdAsync;
begin
if Length(FHostDirName) <= 0 then begin
HandleError('HostDirName emtpy');
Exit;
end;
FFctPrv := ftpFctCwd;
ExecAsync(ftpCwdAsync, 'CWD '+ FHostDirName, [200, 250, 257], nil);
end;
{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
procedure TCustomFtpCli.UserAsync;
var
CmdBuf : String;
begin
if Length(FUserName) <= 0 then begin
HandleError('UserName emtpy');
Exit;
end;
FFctPrv := ftpFctUser;
if FConnectionType = ftpProxy then begin
if (CompareText(FPort, 'ftp') = 0) or
(CompareText(FPort, '21') = 0) then
CmdBuf := 'USER ' + FUserName + '@' + FHostName
else
CmdBuf := 'USER ' + FUserName + '@' + FHostName + ':' + FPort;
end
else
CmdBuf := 'USER ' + FUserName;
ExecAsync(ftpUserAsync, CmdBuf, [331, 230], nil);
end;
{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
procedure TCustomFtpCli.PassAsync;
begin
if Length(FPassword) <= 0 then begin
HandleError('Password emtpy');
Exit;
end;
FFctPrv := ftpFctPass;
ExecAsync(ftpPassAsync, 'PASS '+ FPassword, [230], nil);
end;
{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
procedure TCustomFtpCli.SystAsync;
begin
FFctPrv := ftpFctSyst;
ExecAsync(ftpSystAsync, 'SYST', [215], nil);
end;
{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
procedure TCustomFtpCli.RestAsync;
begin
FFctPrv := ftpFctRest;
{ When restarting a download, we always start from current local file }
{ size. When restarting a upload, we restart from ResumeAt property }
{ value. This property could be initialized using Size command. }
if (not (FRequestType in [ftpRestartPutAsync, ftpRestPutAsync])) and
(not (ftpNoAutoResumeAt in FOptions)) then
FResumeAt := GetFileSize(FLocalFileName);
if FResumeAt > 0 then
ExecAsync(ftpRestAsync, 'REST ' + IntToStr(FResumeAt), [0], nil)
else begin
FRequestDoneFlag := FALSE;
FNext := NextExecAsync;
FDoneAsync := nil;
TriggerRequestDone(0);
end;
end;
{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
procedure TCustomFtpCli.SizeAsync;
begin
FSizeResult := 0;
FFctPrv := ftpFctSize;
ExecAsync(ftpSizeAsync, 'SIZE ' + FHostFileName, [213], nil);
end;
{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
procedure TCustomFtpCli.TypeSetAs
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -