(c) BigSpeed Computing Inc. - Secure private networking
// *** Delphi 7 example of secure file sharing server ***
unit uMain;
interface
uses
ActiveX, Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
StdCtrls, ComCtrls, ToolWin, Menus, ActnList, ImgList, StrUtils, Contnrs,
ExtCtrls, Registry, Variants, ShellAPI, Buttons, IniFiles,
bsFileSrvLib_TLB;
const
WM_MYMEMO_ENTER = WM_USER + 500;
type
TClient = class
Handle: Integer;
Username: WideString;
ListItem: TListItem;
UpFileName, DnFileName: String;
UpFileHandle, UpFileSize, UpFileCount: Integer;
DnFileHandle, DnFileSize, DnFileCount: Integer;
UpFileItem, DnFileItem: TListItem;
end;
TfMain = class(TForm)
StatusBar: TStatusBar;
GroupBox3: TGroupBox;
mmLog: TMemo;
GroupBox2: TGroupBox;
lvClients: TListView;
btnRemove: TButton;
btnClearLog: TButton;
CoolBar1: TCoolBar;
ToolBar1: TToolBar;
ToolButton3: TToolButton;
ToolButton2: TToolButton;
ToolButton4: TToolButton;
ToolButton5: TToolButton;
btnStart: TToolButton;
btnStop: TToolButton;
btnSettings: TToolButton;
btnUsers: TToolButton;
ToolButton1: TToolButton;
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
procedure btnExitClick(Sender: TObject);
procedure btnAboutClick(Sender: TObject);
procedure btnSettingsClick(Sender: TObject);
procedure btnMyIPClick(Sender: TObject);
procedure lvClientsChange(Sender: TObject; Item: TListItem; Change: TItemChange);
procedure btnStartClick(Sender: TObject);
procedure btnStopClick(Sender: TObject);
procedure FormShow(Sender: TObject);
procedure btnRemoveClick(Sender: TObject);
procedure mmLogChange(Sender: TObject);
procedure mmLogEnter(Sender: TObject);
procedure mmLogExit(Sender: TObject);
procedure btnClearLogClick(Sender: TObject);
procedure btnUsersClick(Sender: TObject);
private
{ Private declarations }
FileSrv: TBSFileSrvX;
MyClients: TObjectList;
procedure WMMYMEMOENTER(var Message: TMessage); message WM_MYMEMO_ENTER;
procedure LoadForm;
procedure SaveForm;
procedure SetProperties;
procedure LogMsg(aText: String);
procedure UpdateStatus;
procedure RemoveClient(aCln: TClient);
//Event handlers
procedure doNewClient(Sender: TObject; aHandle: Integer);
procedure doClientDisconnected(Sender: TObject; aHandle: Integer);
procedure doKeyChanged(Sender: TObject; aHandle: Integer);
procedure doSignin(Sender: TObject; aHandle, aCode: Integer);
procedure doSignout(Sender: TObject; aHandle: Integer);
procedure doNeedPassword(Sender: TObject; aHandle: Integer; const aUsername: WideString; var aOkay: WordBool; var aPassword: WideString);
procedure doNeedList(Sender: TObject; aHandle: Integer; const aPath: WideString; var aOkay: WordBool; var aRoot: WideString);
procedure doNeedCreateFolder(Sender: TObject; aHandle: Integer; const aPath: WideString; var aOkay: WordBool; var aRoot: WideString);
procedure doNeedDeleteFolder(Sender: TObject; aHandle: Integer; const aPath: WideString; var aOkay: WordBool; var aRoot: WideString);
procedure doNeedDeleteFile(Sender: TObject; aHandle: Integer; const aPath: WideString; var aOkay: WordBool; var aRoot: WideString);
procedure doNeedRenameFolder(Sender: TObject; aHandle: Integer; const aPath: WideString; var aOkay: WordBool; var aRoot: WideString);
procedure doNeedRenameFile(Sender: TObject; aHandle: Integer; const aPath: WideString; var aOkay: WordBool; var aRoot: WideString);
procedure doNeedDownload(Sender: TObject; aHandle: Integer; const aPath: WideString; var aOkay: WordBool; var aRoot: WideString);
procedure doDownloadDone(Sender: TObject; aHandle: Integer; aCode: Integer);
procedure doNeedUpload(Sender: TObject; aHandle: Integer; const aPath: WideString; var aOkay: WordBool; var aRoot: WideString);
procedure doUploadDone(Sender: TObject; aHandle: Integer; aCode: Integer);
procedure doNeedOpenStream(Sender: TObject; aHandle: Integer; const aPath: WideString; var aOkay: WordBool; var aRoot: WideString);
procedure doStreamClosed(Sender: TObject; aHandle: Integer; aCode: Integer);
procedure doNeedZip(Sender: TObject; aHandle: Integer; const aPath: WideString; var aOkay: WordBool; var aRoot: WideString);
procedure doZipDone(Sender: TObject; aHandle: Integer; aCode: Integer);
procedure doNeedUnzip(Sender: TObject; aHandle: Integer; const aPath: WideString; var aOkay: WordBool; var aRoot: WideString);
procedure doUnzipDone(Sender: TObject; aHandle: Integer; aCode: Integer);
procedure doNeedSearch(Sender: TObject; aHandle: Integer; const aPath: WideString; var aOkay: WordBool; var aRoot: WideString);
procedure doSearchDone(Sender: TObject; aHandle: Integer; aCode: Integer);
public
{ Public declarations }
end;
var
fMain: TfMain;
implementation
uses uAbout, uSettings, uAdd, uUsers;
{$R *.DFM}
// *** Misc
//Add a trailing slash
function AddSlash(aPath: String): String;
begin
Result := aPath;
if RightStr(Result, 1) = '\' then Exit;
Result := Result + '\';
end;
//Remove the trailing slash
function SlashOff(aPath: String): String;
begin
Result := aPath;
if RightStr(Result, 1) <> '\' then Exit;
Delete(Result, Length(Result), 1);
end;
//Insert a leading slash
function PreSlash(aPath: String): String;
begin
Result := aPath;
if LeftStr(Result, 1) = '\' then Exit;
Result := '\' + Result;
end;
//Set a name to the default user
function DUN(aName: WideString): String;
begin
Result := aName;
if Result > '' then Exit;
Result := 'default user';
end;
// *** General
procedure TfMain.FormCreate(Sender: TObject);
begin
LoadForm;
MyClients := TObjectList.Create;
try
FileSrv := TBSFileSrvX.Create(Self);
FileSrv.Parent := Self;
FileSrv.OnNewClient := doNewClient;
FileSrv.OnClientDisconnected := doClientDisconnected;
FileSrv.OnKeyChanged := doKeyChanged;
FileSrv.OnSignin := doSignin;
FileSrv.OnSignout := doSignout;
FileSrv.OnNeedPassword := doNeedPassword;
FileSrv.OnNeedListFolder := doNeedList;
FileSrv.OnNeedCreateFolder := doNeedCreateFolder;
FileSrv.OnNeedDeleteFolder := doNeedDeleteFolder;
FileSrv.OnNeedDeleteFile := doNeedDeleteFile;
FileSrv.OnNeedRenameFolder := doNeedRenameFolder;
FileSrv.OnNeedRenameFile := doNeedRenameFile;
FileSrv.OnNeedDownload := doNeedDownload;
FileSrv.OnDownloadDone := doDownloadDone;
FileSrv.OnNeedUpload := doNeedUpload;
FileSrv.OnUploadDone := doUploadDone;
FileSrv.OnNeedOpenStream := doNeedOpenStream;
FileSrv.OnStreamClosed := doStreamClosed;
FileSrv.OnNeedZip := doNeedZip;
FileSrv.OnZipDone := doZipDone;
FileSrv.OnNeedUnzip := doNeedUnzip;
FileSrv.OnUnzipDone := doUnzipDone;
FileSrv.OnNeedSearch := doNeedSearch;
FileSrv.OnSearchDone := doSearchDone;
except
MessageDlg('BigSpeed File Server control is not registered on your system!', mtError, [mbOk], 0);
Halt;
end;
end;
procedure TfMain.FormDestroy(Sender: TObject);
begin
SaveForm;
MyClients.Free;
end;
procedure TfMain.FormShow(Sender: TObject);
begin
SetProperties;
btnStart.Click;
end;
procedure TfMain.LoadForm;
var
Ini: TIniFile;
begin
try
Ini := TIniFile.Create(ExtractFilePath(Application.ExeName)+'settings.ini');
except
Ini := nil;
end;
if Ini = nil then Exit;
try
with Ini do
begin
Left := ReadInteger('Last', 'Left', Left);
Top := ReadInteger('Last', 'Top', Top);
end;
finally
Ini.Free;
end;
end;
procedure TfMain.SaveForm;
var
Ini: TIniFile;
begin
try
Ini := TIniFile.Create(ExtractFilePath(Application.ExeName)+'settings.ini');
except
Ini := nil;
end;
if Ini = nil then Exit;
try
with Ini do
begin
WriteInteger('Last', 'Left', Left);
WriteInteger('Last', 'Top', Top);
end;
finally
Ini.Free;
end;
end;
procedure TfMain.SetProperties;
begin
FileSrv.ListeningPort := fSettings.edPort.Text;
FileSrv.CryptoKey := fSettings.edKey.Text;
FileSrv.UseCompression := fSettings.cbxCompression.Checked;
end;
procedure TfMain.LogMsg(aText: String);
begin
mmLog.Lines.Add(TimeToStr(Now) + ': ' + aText);
end;
//Update the status text
procedure TfMain.UpdateStatus;
begin
if FileSrv.Running then
begin
StatusBar.Panels[0].Text := ' Started';
btnStart.Enabled := False;
btnStop.Enabled := True;
end
else
begin
StatusBar.Panels[0].Text := ' Stopped';
btnStart.Enabled := True;
btnStop.Enabled := False;
end;
if lvClients.Items.Count = 0 then
StatusBar.Panels[1].Text := ' No active connection'
else
StatusBar.Panels[1].Text := ' ' + IntToStr(lvClients.Items.Count) + ' connection(s)';
end;
procedure TfMain.RemoveClient(aCln: TClient);
begin
if aCln = nil then Exit;
LogMsg('Remove user ' + aCln.Username + ' ' + FileSrv.GetClientAddress(aCln.Handle) + ':' + FileSrv.GetClientPort(aCln.Handle));
FileSrv.RemoveClient(aCln.Handle);
lvClients.Items.Delete(aCln.ListItem.Index);
MyClients.Remove(aCln);
end;
//*** Hide log box caret
procedure TfMain.WMMYMEMOENTER(var Message: TMessage) ;
begin
CreateCaret(mmLog.Handle,0,0,0) ;
end;
procedure TfMain.mmLogChange(Sender: TObject);
begin
CreateCaret(mmLog.handle,0,0,0);
end;
procedure TfMain.mmLogEnter(Sender: TObject);
begin
PostMessage(Handle, WM_MYMEMO_ENTER, 0, 0);
end;
procedure TfMain.mmLogExit(Sender: TObject);
begin
CreateCaret(mmLog.handle,1,1,1);
end;
//************ User Events
//Terminate the application
procedure TfMain.btnExitClick(Sender: TObject);
begin
Application.Terminate;
end;
procedure TfMain.btnAboutClick(Sender: TObject);
begin
fAbout.ShowModal;
end;
procedure TfMain.btnSettingsClick(Sender: TObject);
begin
if fSettings.ShowModal <> mrOk then Exit;
SetProperties;
end;
procedure TfMain.btnMyIPClick(Sender: TObject);
begin
ShowMessage(FileSrv.LocalIP);
end;
procedure TfMain.lvClientsChange(Sender: TObject; Item: TListItem; Change: TItemChange);
begin
if Change <> ctState then Exit;
btnRemove.Enabled := lvClients.SelCount = 1;
UpdateStatus;
end;
//Start the server
procedure TfMain.btnStartClick(Sender: TObject);
begin
if FileSrv.Start then
LogMsg('Server started')
else
ShowMessage('Cannot start the server!');
UpdateStatus;
end;
//Stop the server
procedure TfMain.btnStopClick(Sender: TObject);
var
Cln: TClient;
i: Integer;
begin
FileSrv.Stop;
for i := lvClients.Items.Count-1 downto 0 do
begin
Cln := TClient(lvClients.Items[i].Data);
RemoveClient(Cln);
end;
UpdateStatus;
LogMsg('Server stopped');
end;
//Remove a client connection
procedure TfMain.btnRemoveClick(Sender: TObject);
var
Cln: TClient;
begin
if lvClients.Selected = nil then Exit;
Cln := TClient(lvClients.Selected.Data);
RemoveClient(Cln);
end;
//Clear the log
procedure TfMain.btnClearLogClick(Sender: TObject);
begin
mmLog.Clear;
end;
//Edit the user's rights
procedure TfMain.btnUsersClick(Sender: TObject);
begin
fUsers.Ask;
end;
// *** Client events
//A new connection is available
procedure TfMain.doNewClient(Sender: TObject; aHandle: Integer);
var
LI: TListItem;
Cln: TClient;
begin
Cln := TClient.Create;
MyClients.Add(Cln);
Cln.Handle := aHandle;
LI := lvClients.Items.Add;
LI.Data := Pointer(Cln);
Cln.ListItem := LI;
LI.Caption := 'Not signed in';
LI.Subitems.Add(FileSrv.GetClientAddress(aHandle));
LI.Subitems.Add(FileSrv.GetClientPort(aHandle));
LI.Subitems.Add(TimeToStr(Now));
LI.Subitems.Add('Connected');
FileSrv.SetMoniker(aHandle, Integer(Cln));
UpdateStatus;
LogMsg('New connection from ' + LI.SubItems[0] + ':' + LI.SubItems[1]);
end;
//A connection is broken
procedure TfMain.doClientDisconnected(Sender: TObject; aHandle: Integer);
var
Cln: TClient;
begin
Cln := TClient(FileSrv.GetMoniker(aHandle));
if Cln = nil then Exit;
LogMsg('Disconnected ' + Cln.Username + ' ' + FileSrv.GetClientAddress(aHandle) + ':' + FileSrv.GetClientPort(aHandle));
RemoveClient(Cln);
end;
//Key matching is changed
procedure TfMain.doKeyChanged(Sender: TObject; aHandle: Integer);
var
Cln: TClient;
begin
Cln := TClient(FileSrv.GetMoniker(aHandle));
if Cln = nil then Exit;
LogMsg('Key changed for ' + Cln.Username + ' ' + FileSrv.GetClientAddress(aHandle) + ':' + FileSrv.GetClientPort(aHandle));
if FileSrv.WrongKey(Cln.Handle) then
Cln.ListItem.Subitems[3] := 'Wrong key'
else
Cln.ListItem.Subitems[3] := 'Connected';
end;
//An user is signed-in
procedure TfMain.doSignin(Sender: TObject; aHandle, aCode: Integer);
var
Cln: TClient;
S: String;
begin
Cln := TClient(FileSrv.GetMoniker(aHandle));
if Cln = nil then Exit;
Cln.Username := DUN(FileSrv.GetUserName(aHandle));
Cln.ListItem.Caption := Cln.Username;
S := 'User ' + Cln.Username + ' ' + FileSrv.GetClientAddress(aHandle) + ':' + FileSrv.GetClientPort(aHandle);
if aCode = 0 then
S := S + ' signed in successfully'
else
S := S + ' failed sign-in';
LogMsg(S);
end;
//An user is signed-out
procedure TfMain.doSignout(Sender: TObject; aHandle: Integer);
var
Cln: TClient;
S: String;
begin
Cln := TClient(FileSrv.GetMoniker(aHandle));
if Cln = nil then Exit;
S := 'User ' + Cln.ListItem.Caption + ' ' + FileSrv.GetClientAddress(aHandle) + ':' + FileSrv.GetClientPort(aHandle);
S := S + ' signed out';
LogMsg(S);
Cln.ListItem.Caption := 'Not signed in';
end;
//Request for a password
procedure TfMain.doNeedPassword(Sender: TObject; aHandle: Integer; const aUsername: WideString; var aOkay: WordBool; var aPassword: WideString);
begin
aOkay := fUsers.GetPassword(aUsername, aPassword);
end;
//Request to list the folder content
procedure TfMain.doNeedList(Sender: TObject; aHandle: Integer; const aPath: WideString; var aOkay: WordBool; var aRoot: WideString);
var
User: String;
begin
User := FileSrv.GetUserName(aHandle);
aOkay := fUsers.HasRight(User, arList);
if not aOkay then Exit;
aRoot := fUsers.GetRoot(User);
LogMsg(DUN(User) + ': list folder ' + PreSlash(aPath));
end;
//Request to create a folder
procedure TfMain.doNeedCreateFolder(Sender: TObject; aHandle: Integer; const aPath: WideString; var aOkay: WordBool; var aRoot: WideString);
var
User: String;
begin
User := FileSrv.GetUserName(aHandle);
aOkay := fUsers.HasRight(User, arCreateFolder);
if not aOkay then Exit;
aRoot := fUsers.GetRoot(User);
LogMsg(DUN(User) + ': create folder ' + aPath);
end;
//Request to delete a folder
procedure TfMain.doNeedDeleteFolder(Sender: TObject; aHandle: Integer; const aPath: WideString; var aOkay: WordBool; var aRoot: WideString);
var
User: String;
begin
User := FileSrv.GetUserName(aHandle);
aOkay := fUsers.HasRight(User, arDeleteFolder);
if not aOkay then Exit;
aRoot := fUsers.GetRoot(User);
LogMsg(DUN(User) + ': delete folder ' + aPath);
end;
//Request to delete a file
procedure TfMain.doNeedDeleteFile(Sender: TObject; aHandle: Integer; const aPath: WideString; var aOkay: WordBool; var aRoot: WideString);
var
User: String;
begin
User := FileSrv.GetUserName(aHandle);
aOkay := fUsers.HasRight(User, arDeleteFile);
if not aOkay then Exit;
aRoot := fUsers.GetRoot(User);
LogMsg(DUN(User) + ': delete file ' + aPath);
end;
//Request to rename a folder
procedure TfMain.doNeedRenameFolder(Sender: TObject; aHandle: Integer; const aPath: WideString; var aOkay: WordBool; var aRoot: WideString);
var
User: String;
begin
User := FileSrv.GetUserName(aHandle);
aOkay := fUsers.HasRight(User, arRenameFolder);
if not aOkay then Exit;
aRoot := fUsers.GetRoot(User);
LogMsg(DUN(User) + ': rename folder ' + aPath);
end;
//Request to rename a file
procedure TfMain.doNeedRenameFile(Sender: TObject; aHandle: Integer; const aPath: WideString; var aOkay: WordBool; var aRoot: WideString);
var
User: String;
begin
User := FileSrv.GetUserName(aHandle);
aOkay := fUsers.HasRight(User, arRenameFile);
if not aOkay then Exit;
aRoot := fUsers.GetRoot(User);
LogMsg(DUN(User) + ': rename file ' + aPath);
end;
//Request to download
procedure TfMain.doNeedDownload(Sender: TObject; aHandle: Integer; const aPath: WideString; var aOkay: WordBool; var aRoot: WideString);
var
User: String;
begin
User := FileSrv.GetUserName(aHandle);
aOkay := fUsers.HasRight(User, arDownload);
if not aOkay then Exit;
aRoot := fUsers.GetRoot(User);
LogMsg(DUN(User) + ': start downloading ' + aPath);
end;
//Download is completed
procedure TfMain.doDownloadDone(Sender: TObject; aHandle: Integer; aCode: Integer);
begin
LogMsg(DUN(FileSrv.GetUserName(aHandle)) + ': finish downloading - ' + IntToStr(aCode));
end;
//Request to upload
procedure TfMain.doNeedUpload(Sender: TObject; aHandle: Integer; const aPath: WideString; var aOkay: WordBool; var aRoot: WideString);
var
User: String;
begin
User := FileSrv.GetUserName(aHandle);
aOkay := fUsers.HasRight(User, arUpload);
if not aOkay then Exit;
aRoot := fUsers.GetRoot(User);
LogMsg(DUN(User) + ': start uploading ' + aPath);
end;
//Upload is completed
procedure TfMain.doUploadDone(Sender: TObject; aHandle: Integer; aCode: Integer);
begin
LogMsg(DUN(FileSrv.GetUserName(aHandle)) + ': finish uploading - ' + IntToStr(aCode));
end;
//Request to open a stream
procedure TfMain.doNeedOpenStream(Sender: TObject; aHandle: Integer; const aPath: WideString; var aOkay: WordBool; var aRoot: WideString);
var
User: String;
begin
User := FileSrv.GetUserName(aHandle);
aOkay := fUsers.HasRight(User, arOpenStream);
if not aOkay then Exit;
aRoot := fUsers.GetRoot(User);
LogMsg(DUN(User) + ': open stream ' + aPath);
end;
//Stream is closed
procedure TfMain.doStreamClosed(Sender: TObject; aHandle: Integer; aCode: Integer);
begin
LogMsg(DUN(FileSrv.GetUserName(aHandle)) + ': stream closed');
end;
//Request to zip
procedure TfMain.doNeedZip(Sender: TObject; aHandle: Integer; const aPath: WideString; var aOkay: WordBool; var aRoot: WideString);
var
User: String;
begin
User := FileSrv.GetUserName(aHandle);
aOkay := fUsers.HasRight(User, arZip);
if not aOkay then Exit;
aRoot := fUsers.GetRoot(User);
LogMsg(DUN(User) + ': start zipping to ' + aPath);
end;
//Zip is completed
procedure TfMain.doZipDone(Sender: TObject; aHandle: Integer; aCode: Integer);
begin
LogMsg(DUN(FileSrv.GetUserName(aHandle)) + ': finish zipping - ' + IntToStr(aCode));
end;
//Request to unzip
procedure TfMain.doNeedUnzip(Sender: TObject; aHandle: Integer; const aPath: WideString; var aOkay: WordBool; var aRoot: WideString);
var
User: String;
begin
User := FileSrv.GetUserName(aHandle);
aOkay := fUsers.HasRight(User, arUnzip);
if not aOkay then Exit;
aRoot := fUsers.GetRoot(User);
LogMsg(DUN(User) + ': start unzipping from ' + aPath);
end;
//Unzip is completed
procedure TfMain.doUnzipDone(Sender: TObject; aHandle: Integer; aCode: Integer);
begin
LogMsg(DUN(FileSrv.GetUserName(aHandle)) + ': finish unzipping - ' + IntToStr(aCode));
end;
//Request to search
procedure TfMain.doNeedSearch(Sender: TObject; aHandle: Integer; const aPath: WideString; var aOkay: WordBool; var aRoot: WideString);
var
User: String;
begin
User := FileSrv.GetUserName(aHandle);
aOkay := fUsers.HasRight(User, arSearch);
if not aOkay then Exit;
aRoot := fUsers.GetRoot(User);
LogMsg(DUN(User) + ': start searching in ' + aPath);
end;
//Search is completed
procedure TfMain.doSearchDone(Sender: TObject; aHandle: Integer; aCode: Integer);
begin
LogMsg(DUN(FileSrv.GetUserName(aHandle)) + ': finish searching - ' + IntToStr(aCode));
end;
end.
(c) BigSpeed Computing Inc. - Secure private networking