📄 overbyte.ics.ftpclient.pas
字号:
{* * * *}
{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
constructor TCustomFtpCli.Create(
AOwner: {$IFDEF ICS_COMPONENT}TComponent
{$ELSE}TObject{$ENDIF});
begin
inherited Create(AOwner);
FOnDisplay := nil;
FOnDisplayFile := nil;
FType := 'I';
FPort := 'ftp';
FDataPortRangeStart := 0; {JT}
FDataPortRangeEnd := 0; {JT}
FProxyPort := 'ftp';
FState := ftpReady;
FShareMode := fmShareExclusive;
FConnectionType := ftpDirect;
FProxyServer := ''; { Should Socks properties be set to '' as well? }
FOptions := [ftpAcceptLF];
FLocalAddr := '0.0.0.0'; {bb}
FControlSocket := TFtpWSocket.Create(Self);
FControlSocket.OnSessionConnected := ControlSocketSessionConnected;
FControlSocket.OnDataAvailable := ControlSocketDataAvailable;
FControlSocket.OnSessionClosed := ControlSocketSessionClosed;
FControlSocket.OnDnsLookupDone := ControlSocketDnsLookupDone;
FDataSocket := TFtpWSocket.Create(Self);
FStreamFlag := FALSE;
SetLength(FReceiveBuffer, FTP_RCV_BUF_SIZE);
end;
{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
destructor TCustomFtpCli.Destroy;
begin
{ Be sure to have LocalStream closed }
{$IFDEF TODO}
DestroyLocalStream;
{$ENDIF}
inherited Destroy;
end;
{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
procedure TCustomFtpCli.WndProc(var MsgRec: TMessage);
begin
try
with MsgRec do begin
case Msg of
WM_FTP_REQUEST_DONE : WMFtpRequestDone(MsgRec);
WM_FTP_SENDDATA : WMFtpSendData(MsgRec);
else
inherited WndProc(MsgRec);
end;
end;
except
on E:Exception do
HandleBackGroundException(E);
end;
end;
{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
procedure TCustomFtpCli.WMFtpRequestDone(var msg: TMessage);
begin
if Assigned(FOnRequestDone) then
FOnRequestDone(Self, FRequestType, Msg.LParam);
end;
{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
{$IFDEF ICS_COMPONENT}
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;
{$ENDIF}
{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
procedure TCustomFtpCli.SetErrorMessage;
begin
if FErrorMessage = '' then
FErrorMessage := FLastResponse;
end;
{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
procedure TCustomFtpCli.DestroyLocalStream;
begin
if Assigned(FLocalStream) and (FStreamFlag = FALSE) then begin
FLocalStream.Free;
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.SetDataPortRangeStart(NewValue: DWORD); {JT}
begin
if NewValue > 65535 then
HandleError('DataPortRangeStart must be in the range 0..65535')
else
FDataPortRangeStart := NewValue;
end;
{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
procedure TCustomFtpCli.SetDataPortRangeEnd(NewValue: DWORD); {JT}
begin
if NewValue > 65535 then
HandleError('DataPortRangeEnd must be in the range 0..65535')
else
FDataPortRangeEnd := NewValue
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, ftpPasvReady]);
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;
{ V2.90 some FTP responses are multiline, welcome banner, FEAT command, }
{ keep them all }
FLastMultiResponse := '' ;
FRequestDoneFlag := FALSE;
FNext := NextExecAsync;
FDoneAsync := DoneAsync;
FErrormessage := '';
StateChange(ftpWaitingResponse);
SendCommand(Cmd);
end;
{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
procedure TCustomFtpCli.ExtractMoreResults;
var
NumericCode : LongInt;
nIndex : Integer;
begin
if FRequestResult = 0 then begin
if FFctPrv in [ftpFctSize] then begin
nIndex := 1;
GetInteger(FLastResponse, nIndex, NumericCode);
GetInteger(FLastResponse, nIndex, FSizeResult);
end;
if FFctPrv in [ftpFctCDup, ftpFctPwd, ftpFctMkd, ftpFctCwd] then begin
nIndex := 1;
GetInteger(FLastResponse, nIndex, NumericCode);
GetQuotedString(FLastResponse, nIndex, FDirResult);
end;
end;
end;
{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
procedure TCustomFtpCli.NextExecAsync;
var
I : Integer;
nIndex : Integer;
begin
WSocketTriggerDebugEvent(Self, 'NextExecAsync');
DisplayLastResponse;
if (FLastResponse[1] < '0') or (FLastResponse[1] > '9') then
Exit; { Continuation line, nothing to do }
nIndex := 1;
GetInteger(FLastResponse, nIndex, FStatusCode);
if FLastResponse[nIndex] = '-' 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
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -