📄 ftpcli.pas
字号:
if CanAbort then begin
try
Abort;
except
end;
end;
end;
{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
procedure TCustomFtpCli.WMFtpRequestDone(var msg: TMessage);
begin
if Assigned(FOnRequestDone) then
FOnRequestDone(Self, FRequestType, Msg.LParam);
end;
{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
procedure TCustomFtpCli.Notification(AComponent: TComponent; Operation: TOperation);
begin
inherited Notification(AComponent, Operation);
if Operation = opRemove then begin
if AComponent = FControlSocket then
FControlSocket := nil
else if AComponent = FDataSocket then
FDataSocket := nil;
end;
end;
{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
procedure TCustomFtpCli.SetErrorMessage;
begin
if FErrorMessage = '' then
FErrorMessage := FLastResponse;
end;
{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
procedure TCustomFtpCli.DestroyLocalStream;
begin
if Assigned(FLocalStream) and not FStreamFlag then
begin
FLocalStream.Destroy;
FLocalStream := nil;
end;
end;
{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
procedure TCustomFtpCli.SetLocalFileName (FileName:String);
begin
FLocalFileName:=FileName;
if FileName<>'' then FStreamFlag:=False;
end;
{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
procedure TCustomFtpCli.SetLocalStream (Stream:TStream);
begin
FLocalStream:=Stream;
FStreamFlag:=(Stream<>NIL);
if FStreamFlag then FLocalFileName:='';
end;
{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
procedure TCustomFtpCli.TriggerDisplay(Msg : String);
begin
if Assigned(FOnDisplay) then
FOnDisplay(Self, Msg);
end;
{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
procedure TCustomFtpCli.TriggerDisplayFile(Msg : String);
begin
if Assigned(FOnDisplayFile) then
FOnDisplayFile(Self, Msg);
end;
{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
procedure TCustomFtpCli.TriggerError(Msg : String);
begin
if Assigned(FOnError) then
FOnError(Self, Msg);
end;
{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
procedure TCustomFtpCli.DisplayLastResponse;
begin
TriggerDisplay('< ' + FLastResponse);
end;
{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
procedure TCustomFtpCli.StateChange(NewState : TFtpState);
begin
if FState <> NewState then begin
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 CheckReady then
Exit;
if not FConnected then begin
HandleError('FTP component not connected');
Exit;
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;
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;
begin
if Length(FUserName) <= 0 then begin
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -