1 - How it works


Scripts can be used to react on events and commands available through the server.
Supported scripts languages are VBScript, JScript.
Every script must be located in /scripts/ to be usable.

 2 - Available script resources


Here is the list of functions that are called.

OnSiteXXXXX where XXXXX is your SITE command in lowercase.
This command occurs when a user issues a SITE command (e.g. "SITE BLA test test2" will call the function OnSitebla("test test2")).

Note : SITE command is in lowercase for case sensitive script engines like JScript; VBScript is case insensitive : SITE TEST will launch OnSitetest, not OnSiteTEST for JScript.

It is up to you to parse parameters.

The following functions are called with no parameters :

OnClientAuthenticated : client just sent its login/password information and it was accepted
OnClientConnected : client just connected to domain
OnClientDisconnected: client disconnected from domain
OnClientBanned : client tried to connect but is banned from domain
OnClientHammering : client has hammered the server and was banned and disconnected
OnSameIPConnect : client was disconnected because too many clients are connected with the same IP
OnTooManyClient : client was disconnected because there are too many clients connected

OnClientTimeOut : the client timed out and was killed/disconnected
OnClientLoggedIn : the client just logged in
OnDomainClosed : domain has gone offline
OnDomainOpened : domain has opened : domain is listening for incoming connections
OnDomainStarted : a domain was created
OnDomainStopped : a domain was deleted
OnEvery05Minutes, OnEveryDay, OnEveryHour : only called for domain scripts
OnDirCreated : a directory was created
OnDirDeleted : a directory was deleted
OnDirListed : a directory was listed
OnFileBanned : client tried to upload a banned file
OnFileDeleted : client deleted a file
OnFileDownloaded : client finished to download a file
OnFileRenamed : client successfully renamed a file/directory
OnFileUploaded : client finished to upload a file
OnFileUploadFailed : client aborted or a socket error occurred during the file upload
OnIPChanged : domain's IP changed
OnQuotaExceeded : client exceeded his quota limit

The following function is called with a parameter :

OnScriptError(error) : an error occurred in a script, the parameter being the error description

Note:
Every client has an instance of the script so two scripts may be run at the same time and then a file may be locked by an other script that has open it.

Objects available in scripts :

:-------------------------------------------------------------

Object Script

string FileName : Get the script Filename
boolean IsDomainContext : Return if the script is running in domain context only. If is in domain context then Client object is not available.
int Timeout : Get and set the script timeout, setting a new value resets the script timeout, 0 means unlimited
void Include(string scriptPath) : Load and parse the script
void Sleep(int Msec) : Wait for Msec milliseconds

:-------------------------------------------------------------

Object Tools

string CRCFile(String path) : Compute and return the CRC of a file
string CRCStr(String str) : Compute and return the CRC of a string
string FormatSize(int size) : Return the size formated according to its value, the value will be suffixed by TBytes, GBytes, MBytes, KBytes or Bytes
string FormatSize(int size, int FormatStyle, boolean LongForm, int NumDigitsAfterDecimal) : Return the size formated according to FormatStyle (1 to convert in Bytes, 2 in KBytes, 3 in MBytes ...), LongForm (Long or short suffix : KBytes or KB) and NumDigitsAfterDecimal (the number of digits after the decimal).
string MD5File(String path) : Compute and return the MD5 hash of a file
string MD5Str(String str) : Compute and return the MD5 hash of a string
string SHA1File(String path) : Compute and return the SHA1 hash of a file
string SHA1Str(String str) : Compute and return the SHA1 hash of a string

:-------------------------------------------------------------

Object Server

string CertificatePath : Return the path where certificates are stored
string LogPath : Return the path where log files are stored
string ScriptPath : Return the path where scripts are stored
string ServerPath : Return the application path

:-------------------------------------------------------------

Object Domain

int Bandwidth : Return current bandwidth usage in bytes/second
int Bandwidth_in : Return current bandwidth usage in upload in bytes/second
int Bandwidth_out : Return current bandwidth usage in download in bytes/second
int ClientCount : Return the number of clients connected to the domain
int UserCount : Return the number of clients logged on the domain
int DownloadCount : Return the number of clients downloading
int UploadCount : Return the number of clients uploading
string Name : Return the name of the domain
date StartTime : Return the datetime when domain was started

void WriteLog(String log) : If log is enabled, write to log the parameter

:-------------------------------------------------------------

Object Client

string AccountName : Return the account name the client, it may be different than Username if an alias was used to log in
date ConnectionDateTime : Return connection date time
string HostName : Return client hostname (if ResolveIP enabled)
string ID : Return the unique client ID
string PeerIP : Return the client peer IP address
int PeerPort : Return the client peer port
string LocalIP : Return the client local IP address
int LocalPort : Return the client local port
string Keyword : Return the current command keyword
string Directory : Return the current virtual directory of the client
string DirectoryReal : Return the current path of the client
int Downloaded : Return the amount of bytes sent to the client
int Uploaded : Return the amount of bytes received from the client
boolean Logged : Return true if client is logged in
int RestartPos : Return the restart position marker
string Username : Return the client username
string Filename : Return the current virtual filename (e.g. "/temp/file.txt")
string FilenameReal : Return the current filename (e.g. "C:\temp\file.txt")
int FileSize : Return the size of the last transferred file
int FilePosition
int Speed : Return the average speed of the client over the last 5 seconds in bytes/seconds
int Speed_In : Return the average upload speed of the client over the last 5 seconds in bytes/seconds
int Speed_Out : Return the average download speed of the client over the last 5 seconds in bytes/seconds
int TransferTimeSeconds : Return the transfer time in seconds
string TransferTime : Return the transfer time. It has the form "00:00:00"
int TransferSpeedBps : Return the transfer speed in bytes/s
string TransferSpeed : Return the transfer speed in KBytes/s. It has the form "128 KBytes/s"

boolean IsSecure : Return whether client control connection is secured
boolean IsTransferSecure : Return whether client data connection is secured

void ConvertToReal(string path) : Convert a virtual path (e.g. /temp) to the physical path (e.g. C:\Temp)
void Kick() : Disconnect the client from the server
void Post(string Message) : Post a message to the client : it will be formatted by the server and prepended to the next server reply
void Post(string Message, boolean ProcessTags) : Post a message to the client : it will be formatted by the server and prepended to the next server reply, if ProcessTags is true then tags in Message will be replaced
void Post(string Message, boolean ProcessTags, boolean Append) : Post a message to the client : it will be formatted by the server and prepended or appended to the next server reply
void Send(string Message) : Send a string to the client
void send(int Code, string Message) : Send a FTP formatted string to the client, e.g. 200 ok
void send(int Code, string Message, boolean ProcessTags) : Send a FTP formatted string to the client, if ProcessTags is true then tags in Message will be replaced

 3 - Example


'SCRIPT: Log downloads.vbs
'AUTHOR: Gene6
'DATE: 2002/10/04
'DESC: Log every download to a log file
' Every entry has the form "date time#username#filename#filenamereal#from#to#time#speed

'Constants
Delimiter = "#"
ForAppending = 8

'Create the file path
strYear = Year(Date)

strMonth = Month(Date)
' add the leading zero
if (strMonth < 10) Then
strMonth = "0" & strMonth
end if

strDay = Day(Date)
' add the leading zero
if (strDay < 10) Then
strDay = "0" & strDay
end if

LogFilename = Server.LogPath & Domain.Name & "-" & strYear & "-" & strMonth & "-" & strDay & "-downloads.log"

sub OnFileDownloaded()
Set fso = CreateObject("Scripting.fileSystemObject")
Set LogObj = fso.OpenTextFile(LogFilename, ForAppending, true)

Line = FormatDateTime(Now) & Delimiter & Client.Username & Delimiter & Client.Filename & Delimiter &
Client.FilenameReal & Delimiter & Client.RestartPos & Delimiter & Client.FilePosition & Delimiter &
Client.TransferTime & Delimiter & Client.TransferSpeed

LogObj.WriteLine(Line)
LogObj.Close
end sub

 4 - Advanced scripting


You can also write functions which will be called to react to some clients' actions before they are executed by the FTP server.

For instance, you can create a function which forbids the upload of files not matching a filemask or scan a file for virus and command the server to delete it and reply to user that the file is infected.

A new object allowing modifications of the FTP server behavior is available as a global constant :

Object Hook

boolean DeleteFile : Allow or deny deletion of the file uploaded by the client. Can only be used in HookStoreFinished
int Result : Allow modification of the result of the client's operation.
void SetReply(int Code, string Message) : Modify the response sent to user if Hook.Result is different from 0

This object can be used in the following functions:

HookChangeDirectory(FileName, FileNameReal) : client tries to change directory
Possible returned values of Hook.Result :
0 : allowed
1 : denied
2 : folder not found

HookDeleteFile(FileName, FileNameReal) : client tries to delete a file
Possible returned values of Hook.Result :
0 : allowed
1 : denied
2 : file not found
3 : file could not be removed

HookMakeDirectory(FileName, FileNameReal) : client tries to create a folder
Possible returned values of Hook.Result :
0 : allowed
1 : denied
2 : folder could not be created
3 : folder already exists

HookMove(FileName, FileNameReal, ToFileName, ToFileNameReal) : client tries to rename/move a file or folder
Possible returned values of Hook.Result :
0 : allowed
1 : denied
2 : source file not found
Note:
ToFileName et ToFileNameReal are empty if at RNFR step of the RNFR/RNTO command.

HookRemoveDirectory(FileName, FileNameReal) : client tries to remove a folder
Possible returned values of Hook.Result :
0 : allowed
1 : denied
2 : folder not found
3 : folder could not be deleted

HookRetrieve(FileName, FileNameReal) : client tries to download a file
Possible returned values of Hook.Result :
0 : allowed
1 : denied
2 : file not found
3 : file can't be downloaded
4 : transfer is only allowed over a secure connection
5 : not enough credit to download

sub HookRetrieveFinished(FileName, FileNameReal) : client has finished to download a file
Possible returned values of Hook.Result :
0 : transfer ok
1 : transfer failed
2 : disk error while transfering
3 : not enough credit to continue transfer
4 : quota exceeded
5 : transfer limit has been reached
6 : transfer speed too slow
7 : transfer stopped by the server (banned client, stopped by admin, disabled account, ...)
8 : reserved
9 : partial transfer
10 : idle time-out
11 : secure handshake has failed

HookStore(FileName, FileNameReal) : client tries to upload a file
Possible returned values of Hook.Result :
0 : allowed
1 : denied
2 : file can't be stored
3 : upload is only allowed over a secure connection

HookStoreFinished(FileName, FileNameReal) : client has finished to upload a file
Possible returned values of Hook.Result :
0 : transfer ok
1 : transfer failed
2 : disk error while transfering
3 : reserved
4 : quota exceeded
5 : transfer limit has been reached
6 : transfer speed too slow
7 : transfer stopped by the server (banned client, stopped by admin, disabled account, ...)
8 : reserved
9 : reserved
10 : idle time-out
11 : secure handshake has failed

HookTag(Tag) : an unknown tag was not processed by the FTP Server
Return the value of the tag with Hook.SetText(string text), you can retrieve the tag parameters with int Hook.ParamCount() and string Hook.GetParam(int index)


 5 - Advanced example


'SCRIPT: test hooks.vbs
'AUTHOR: Gene6
'DATE: 2004/08/01
'DESC: Simple script to test hooks

' Constants
cwdOk = 0
cwdNoRight = 1
cwdNotFound = 2

rmOk = 0
rmNoRight = 1
rmNotfound = 2
rmFailed = 3

mkdOk = 0
mkdNoRight = 1
mkdFailed = 2
mkdAlreadyExists = 3

mvOk = 0
mvNoRight = 1
mvNotfound = 2
mvFailed = 3

orOk = 0
orNoRight = 1
orNotfound = 2
orFailed = 3
orSecureTransferOnly = 4
orNotEnoughCredits = 5

owOk = 0
owNoRight = 1
owFailed = 2
owSecureTransferOnly = 3

tNormal = 0
tFailed = 1
tDiskError = 2
tRatioError = 3
tQuotaExceeded = 4
tTransferLimitReached = 5
tTransferTooSlow = 6
tAborted = 7
tCantOpenDataConnection = 8
tPartial = 9
tSessionTimeOut = 10
tSSLNegotiationFailed = 11


sub HookChangeDirectory(FileName, FileNameReal)
Hook.SetReply 550, "No right"
Hook.Result = cwdNoRight
end sub


sub HookDeleteFile(FileName, FileNameReal)
Hook.SetReply 550, "No right"
Hook.Result = rmNoRight
end sub


sub HookMakeDirectory(FileName, FileNameReal)
Hook.SetReply 550, "No right"
Hook.Result = mkdNoRight
end sub


sub HookMove(FileName, FileNameReal, ToFileName, ToFileNameReal)
Hook.SetReply 550, "No right"
Hook.Result = mvNoRight
end sub


sub HookRemoveDirectory(FileName, FileNameReal)
Hook.SetReply 550, "No right"
Hook.Result = rmNoRight
end sub


sub HookRetrieve(FileName, FileNameReal)
if StrComp(Right(FileNameReal, 4), ".zip", 1) < > 0 Then
Hook.SetReply 550, "No right, you can only download *.zip files"
Hook.Result = orNoRight
end if
end sub


sub HookRetrieveFinished(FileName, FileNameReal)
' place code here to do something when a client transfer stops
end sub


sub HookStore(FileName, FileNameReal)
if StrComp(Right(FileNameReal, 4), ".zip", 1) < > 0 Then
Hook.SetReply 550, "No right, you can only upload *.zip files"
Hook.Result = owNoRight
end if
end sub


sub HookStoreFinished(FileName, FileNameReal)
Set fso = CreateObject("Scripting.fileSystemObject")
Set fil = fso.OpenTextFile(FileNameReal, 1, true)

if StrComp(fil.Read(2), "PK", 0) < > 0 Then
Hook.SetReply 550, "This .zip file is not a true zip file ! It will be deleted."
Hook.Result = tFailed
Hook.DeleteFile = true
end if
end sub

sub HookTag(Tag)
'this will write the tag in the file c:\tags.txt
Set fso = CreateObject("Scripting.fileSystemObject")
Set fil = fso.OpenTextFile("c:\tags.txt", 8, true)
fil.WriteLine(Tag)
fil.Close

'Handle the tag $TEST(param1, param2, ..)
if StrComp(Tag, "Test", 1) = 0 Then
Params = ""

for I = 0 to Hook.ParamCount-1
Params = Params & Hook.GetParam(I) & " "
Next

Hook.SetText "Hello " & Client.Username & chr(13) & "This is a test tag and it seems to be working," & chr(13) & _
Hook.ParamCount & " parameters were passed, here is the list: " & chr(13) & _
Params & chr(13)
end if
end sub