📄 ftpserv1.pas
字号:
{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
procedure TFtpServerForm.FtpServer1RetrDataSent(Sender: TObject;
Client: TFtpCtrlSocket; Data: TWSocket; Error: Word);
begin
if Error <> 0 then
InfoMemo.Lines.Add('! ' + Client.GetPeerAddr +
' Data sent. Error #' + IntToStr(Error));
end;
{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
{ This event handler is called when the data session for a get file has }
{ been opened. This is a good place build a file or a stream if the data }
{ requested is not already stored in a file on the file system. }
{ This feature is very powerfull and enable the FTP protocol to be used to }
{ retrieve any kind of data. It this sample, we just check for C:\VIRTUAL }
{ directory. If this directory is curent, then a TMemoryStream is created }
{ on the fly with some data. If another directory is selected, the FTP }
{ server works as any other: just send the requested file, if it exist ! }
{ This event handler is also a place where you can abort the file transfer. }
{ Simply trigger an exception and transfer will not take place. }
{ Note that if you just wants to prohibe access to some directory or file, }
{ the best place to code that is in the OnValidateGet or OnValidatePut }
{ event handlers. }
procedure TFtpServerForm.FtpServer1RetrSessionConnected(Sender: TObject;
Client : TFtpCtrlSocket;
Data : TWSocket;
Error : Word);
var
Buf : String;
begin
if Error <> 0 then
InfoMemo.Lines.Add('! ' + Client.GetPeerAddr +
' Data session connected. Error #' + IntToStr(Error))
else if Copy(UpperCase(Client.FilePath), 1, 19) = 'C:\VIRTUAL\FORBIDEN' then
raise Exception.Create('Access prohibed !')
else if Copy(UpperCase(Client.FilePath), 1, 11) = 'C:\VIRTUAL\' then begin
InfoMemo.Lines.Add('! VIRTUAL FILE');
Client.UserData := 1; { Remember we created a stream }
if Assigned(Client.DataStream) then
Client.DataStream.Destroy; { Prevent memory leaks }
Client.DataStream := TMemoryStream.Create;
Buf := 'This is a file created on the fly by the FTP server' + #13#10 +
'It could result of a query to a database or anything else.' + #13#10 +
'The request was: ''' + Client.FilePath + '''' + #13#10;
Client.DataStream.Write(Buf[1], Length(Buf));
Client.DataStream.Seek(0, 0);
end;
end;
{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
procedure TFtpServerForm.FtpServer1RetrSessionClosed(Sender: TObject;
Client: TFtpCtrlSocket; Data: TWSocket; Error: Word);
begin
if Error <> 0 then
InfoMemo.Lines.Add('! ' + Client.GetPeerAddr +
' Data session closed. Error #' + IntToStr(Error));
if Client.UserData = 1 then begin
{ We created a stream for a virtual file or dir. Delete the TStream }
if Assigned(Client.DataStream) then begin
{ There is no reason why we should not come here, but who knows ? }
Client.DataStream.Destroy;
Client.DataStream := nil;
end;
Client.UserData := 0; { Reset the flag }
end;
end;
{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
{ This event handler is called when the FTP component needs to build a }
{ directory listing. You can just return without doing anything then the }
{ component will build the directory for you, based on the actual disk }
{ content. But you can also build your own directory listing with anything }
{ you like in it. Just create a stream with the required content. The }
{ example below construct a virtual directory when the user is on the }
{ C:\VIRTUAL subdirectory (use elsewhere in this sample program). }
procedure TFtpServerForm.FtpServer1BuildDirectory(
Sender : TObject;
Client : TFtpCtrlSocket;
var Directory : TFtpString;
Detailed : Boolean);
var
Buf : String;
begin
if UpperCase(Client.Directory) <> 'C:\VIRTUAL\' then
Exit;
InfoMemo.Lines.Add('! VIRTUAL DIR');
Client.UserData := 1; { Remember we created a stream }
if Assigned(Client.DataStream) then
Client.DataStream.Destroy; { Prevent memory leaks }
Client.DataStream := TMemoryStream.Create;
if Detailed then
{ We need to format directory lines according to the Unix standard }
Buf :=
'-rwxrwxrwx 1 ftp ftp 0 Apr 30 19:00 FORBIDEN' + #13#10 +
'-rwxrwxrwx 1 ftp ftp 0 Apr 30 19:00 TEST' + #13#10 +
'drwxrwxrwx 1 ftp ftp 0 Apr 30 19:00 SOME DIR' + #13#10
else
Buf := 'FORBIDEN' + #13#10 +
'TEST' + #13#10;
Client.DataStream.Write(Buf[1], Length(Buf));
Client.DataStream.Seek(0, 0);
end;
{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
{ This event handler is called by the FTP component once it has built the }
{ directory listing. We can use this handler to alter the listing, adding }
{ or removing some info. This sample add the 'virtual' directory. }
procedure TFtpServerForm.FtpServer1AlterDirectory(
Sender : TObject;
Client : TFtpCtrlSocket;
var Directory : TFtpString;
Detailed : Boolean);
var
Buf : String;
begin
if UpperCase(Client.Directory) <> 'C:\' then
Exit;
{ Add our 'virtual' directory to the list }
if Detailed then begin
{ We need to format directory lines according to the Unix standard }
Buf :=
'drwxrwxrwx 1 ftp ftp 0 Apr 30 19:00 VIRTUAL' + #13#10;
Client.DataStream.Write(Buf[1], Length(Buf));
end;
end;
{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
procedure TFtpServerForm.FtpServer1ClientCommand(Sender: TObject;
Client: TFtpCtrlSocket; var Keyword, Params, Answer: TFtpString);
begin
InfoMemo.Lines.Add('< ' + Client.GetPeerAddr + ' ' +
Keyword + ' ' + Params);
end;
{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
procedure TFtpServerForm.FtpServer1AnswerToClient(Sender: TObject;
Client: TFtpCtrlSocket; var Answer: TFtpString);
begin
InfoMemo.Lines.Add('> ' + Client.GetPeerAddr + ' ' + Answer)
end;
{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
procedure TFtpServerForm.FtpServer1Authenticate(Sender: TObject;
Client: TFtpCtrlSocket; UserName, Password: TFtpString;
var Authenticated: Boolean);
begin
{ You should place here the code needed to authenticate the user. }
{ For example a text file with all permitted username/password. }
{ If the user can't be authenticated, just set Authenticated to }
{ false before returning. }
{ It is also the right place to setup Client.HomeDir }
{ If you need to store info about the client for later processing }
{ you can use Client.UserData to store a pointer to an object or }
{ a record with the needed info. }
InfoMemo.Lines.Add('! ' + Client.GetPeerAddr +
' User ''' + UserName + ''' is authenticated');
if Password = 'bad' then
Authenticated := FALSE;
end;
{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
procedure TFtpServerForm.FtpServer1ChangeDirectory(Sender: TObject;
Client: TFtpCtrlSocket; Directory: TFtpString; var Allowed: Boolean);
begin
{$IFDEF NEVER}
{ It the right place to check if a user has access to a given directory }
{ The example below disable C:\ access to non root user. }
if (UpperCase(Client.UserName) <> 'ROOT') and
(UpperCase(Client.Directory) = 'C:\') then
Allowed := FALSE;
{$ENDIF}
end;
{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
procedure TFtpServerForm.Cleardisplay1Click(Sender: TObject);
begin
InfoMemo.Clear;
end;
{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
procedure TFtpServerForm.MnuListClientsClick(Sender: TObject);
var
I : Integer;
begin
if FtpServer1.ClientCount <= 0 then begin
InfoMemo.Lines.Add('No client');
Exit;
end;
for I := 0 to FtpServer1.ClientCount - 1 do begin
InfoMemo.Lines.Add('Client ' + IntToStr(I + 1) + ': ' +
FtpServer1.Client[I].GetPeerAddr + '/' +
FtpServer1.Client[I].GetPeerPort);
end;
end;
{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
procedure TFtpServerForm.DisconnectAllMnuClick(Sender: TObject);
begin
FtpServer1.DisconnectAll;
end;
{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
{$IFDEF VER80} { Sorry, Delphi 1 doesn't support multi-threading }
procedure TFtpServerForm.FtpServer1GetProcessing(
Sender : TObject;
Client : TFtpCtrlSocket;
var DelayedSend : Boolean);
begin
{ Nothing to do here... }
end;
{$ENDIF}
{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
{$IFNDEF VER80} { 32 bits support multi-threading }
procedure TFtpServerForm.FtpServer1GetProcessing(
Sender : TObject;
Client : TFtpCtrlSocket;
var DelayedSend : Boolean);
var
MyServer : TFtpServer;
MyClient : TMyClient;
begin
MyServer := Sender as TFtpServer;
MyClient := Client as TMyClient;
{ If client request a *.ZZZ file, then start a thread to do some }
{ processing (here the thread just sleep 10 sec to show other clients }
{ are not blocked. }
if UpperCase(ExtractFileExt(MyClient.FileName)) = '.ZZZ' then begin
MyClient.FWorkerThread := TGetProcessingThread.Create(TRUE);
MyClient.FWorkerThread.Server := MyServer;
MyClient.FWorkerThread.Client := MyClient;
MyClient.FWorkerThread.FreeOnTerminate := TRUE;
MyClient.FWorkerThread.OnTerminate := WorkerThreadTerminated;
MyClient.FWorkerThread.Resume;
{ Ask server component to not start sending immediately }
{ We will ask to start sending from WorkerThreadTerminated event }
DelayedSend := TRUE;
end;
end;
{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
procedure TFtpServerForm.WorkerThreadTerminated(Sender : TObject);
var
MyThread : TGetProcessingThread;
begin
MyThread := Sender as TGetProcessingThread;
MyThread.Server.DoStartSendData(MyThread.Client);
end;
{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
procedure TGetProcessingThread.Execute;
begin
Sleep(10000);
end;
{$ENDIF}
{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
end.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -