Using Script with UltraFXP

1. Pascal syntax
1.1 Identifiers
1.2 Assign statements
1.3 Character strings
1.4 Comments
1.5 Variables
1.6 Indexes
1.7 Arrays
1.8 if statements
1.9 while statements
1.10 repeat statements
1.11 for statements
1.12 case statements
1.13 function and procedure declaration
2. Function lib for UltraFXP
2.1 Date function
2.2 String function
2.3 miscellaneous routines
3. Access UltraFXP via Script
3.1 Include other script files
3.2 Global variable
3.3 Global object
3.3.1 Main Window
3.3.2 Server Manager
3.4 Global function
3.4.1 Get text from Windows Clipboard
3.4.2 Sleep for some seconds
3.4.3 Accept User Input Text
3.4.4 Show a Message Box Dialog
3.4.5 Match Strings
3.4.6 Send text to mIRC
3.4.7 Execute a application at windows
3.5 Script function for FTP
3.5.1 Connect to FTP
3.5.2 Send raw command to FTP
3.5.3 Change directory with FTP Bookmark
3.5.4 Disconnect from FTP Servers
3.5.5 Execute command at FTP and return result to mIRC
3.5.6 Remove Directory or File at FTP
3.6 Script function for FXP
3.6.1 UF_FXPDIR (FXP from 1 FTP to another FTP via script)
3.6.2 UF_FXPDIREX (FXP from 1 FTP to another FTP via script)
3.6.3 UF_FXPDIRAPPEND (FXP from 1 FTP to many FTP via script)
3.6.4 UF_CHAINFXPDIR (FXP to Many FTP Server at Same Time via script)
1. Pascal syntax

> begin .. end constructor
> procedure and function declarations
> if .. then .. else constructor
> for .. to .. do .. step constructor
> while .. do constructor
> repeat .. until constructor
> try .. except and try .. finally blocks
> case statements
> with statements
> as / is statements
> array constructors (x:=[ 1, 2, 3 ];)
> ^ , * , / , and , + , - , or , <> , >=, <= , = , > , < , div , mod , xor , shl , shr operators
> access to object properties and methods ( ObjectName.SubObject.Property )

1.1 Identifiers

> Identifier names in script (variable names, function and procedure names, etc.) follow the most common rules in pascal :
> should begin with a character (a..z or A..Z), or '_', and can be followed by alphanumeric chars or '_' char. Cannot contain
> any other character os spaces.

> > Valid identifiers:
> > VarName
> > _Some
> > V1A2
> > _____Some____

> > Invalid identifiers:
> > 2Var
> > My Name
> > Some-more
> > This,is,not,valid

1.2 Assign statements

> Just like in Pascal, assign statements (assign a value or expression result to a variable or object property) are built using
> ":=". Examples:

> > MyVar:=2;
> > Button.Caption:='This ' + 'is ok.';

1.3 Character strings

> strings (sequence of characters) are declared in pascal using single quote (') character. Double quotes (") are not used.
> You can also use #nn to declare a character inside a string. There is no need to use '+' operator to add a character to a
> string. Some examples:

> > A:='This is a text';
> > Str:='Text '+'concat';
> > B:='String with CR and LF char at the end'#13#10;
> > C:='String with '#33#34' characters in the middle';

1.4 Comments

> Comments can be inserted inside script. You can use // chars or (* *) or { } blocks. Using // char the comment will
> finish at the end of line.

> > //This is a comment before ShowMessage
> > ShowMessage('Ok');
> > (* This is another comment *)
> > ShowMessage('More ok!');
> > { And this is a comment
> > with two lines }
> > ShowMessage('End of okays');

1.5 Variables

> There is no need to declare variable types in script. Thus, you declare variable just using var directive and its name.
> There is no need to declare variables if scripter property OptionExplicit is set to false. In this case, variables are implicit
> declared. If you want to have more control over the script, set OptionExplicit property to true. This will raise a compile
> error if variable is used but not declared in script. Examples:

> > SCRIPT 1:
> > procedure Msg;
> > var S;
> > begin
> > S:='Hello world!';
> > ShowMessage(S);
> > end;
> > SCRIPT 2:
> > var A;
> > begin
> > A:=0;
> > A:=A+1;
> > end;
> > SCRIPT 3:
> > var S;
> > S:='Hello World!';
> > ShowMessage(S);

> Note that if script property OptionExplicit is set to false, then var declarations are not necessary in any of scripts above.

1.6 Indexes

> Strings, arrays and array properties can be indexed using "[" and "]" chars. For example, if Str is a string variable, the
> expression Str[3] returns the third character in the string denoted by Str, while Str[I + 1] returns the character
> immediately after the one indexed by I. More examples:

> > MyChar:=MyStr[2];
> > MyStr[1]:='A';
> > MyArray[1,2]:=1530;
> > Lines.Strings[2]:='Some text';

1.7 Arrays

> Script support array constructors and support to variant arrays. To construct an array, use "[" and "]" chars. You can
> construct multi-index array nesting array constructors. You can then access arrays using indexes. If array is multi-index,
> separate indexes using ",".
> If variable is a variant array, script automatically support indexing in that variable. A variable is a variant array is it was
> assigned using an array constructor, if it is a direct reference to a Delphi variable which is a variant array (see Delphi
> integration later) or if it was created using VarArrayCreate procedure.
> Arrays in script are 0-based index. Some examples:

> > NewArray := [ 2,4,6,8 ];
> > Num:=NewArray[1]; //Num receives "4"
> > MultiArray := [ ['green','red','blue'] , ['apple','orange','lemon'] ];
> > Str:=MultiArray[0,2]; //Str receives 'blue'
> > MultiArray[1,1]:='new orange';

1.8 if statements

> There are two forms of if statement: if...then and the if...then...else. Like normal pascal, if the if expression is true, the
> statement (or block) is executed. If there is else part and expression is false, statement (or block) after else is execute.
> Examples:

> > if J <> 0 then Result := I/J;
> > if J = 0 then Exit else Result := I/J;
> > if J <> 0 then
> > begin
> > Result := I/J;
> > Count := Count + 1;
> > end
> > else
> > Done := True;

1.9 while statements

> A while statement is used to repeat a statement or a block, while a control condition (expression) is evaluated as true.
> The control condition is evaluated before the statement. Hence, if the constrol condition is false at first iteration, the
> statement sequence is never executed. The while statement executes its constituent statement (or block) repeatedly,
> testing expression before each iteration. As long as expression returns True, execution continues. Examples:

> > while Data[I] <> X do I := I + 1;
> > while I > 0 do
> > begin
> > if Odd(I) then Z := Z * X;
> > I := I div 2;
> > X := Sqr(X);
> > end;
> > while not Eof(InputFile) do
> > begin
> > Readln(InputFile, Line);
> > Process(Line);
> > end;

1.10 repeat statements

> The syntax of a repeat statement is repeat statement1; ...; statementn; until expression where expression returns a
> Boolean value. The repeat statement executes its sequence of constituent statements continually, testing expression after
> each iteration. When expression returns True, the repeat statement terminates. The sequence is always executed at least
> once because expression is not evaluated until after the first iteration. Examples:

> > repeat
> > K := I mod J;
> > I := J;
> > J := K;
> > until J = 0;
> > repeat
> > Write('Enter a value (0..9): ');
> > Readln(I);
> > until (I >= 0) and (I <= 9);

1.11 for statements

> Scripter support for statements with the following syntax: for counter := initialValue to finalValue do statement
> For statement set counter to initialValue, repeats execution of statement (or block) and increment value of counter until
> counter reachs finalValue. Examples:

> > for i:=a to b do
> > begin
> > j:=i^2;
> > sum:=sum+j;
> > end;

1.12 case statements

> if selectorExpression matches the result of one of caseexprn expressions, the respective statement (or block) will be
> execute. Otherwise, elsestatement will be execute. Else part of case statement is optional. Different from Delphi, case
> statement in script doesn't need to use only ordinal values. You can use expressions of any type in both selector
> expression and case expression. Example:

> > case uppercase(Fruit) of
> > 'lime': ShowMessage('green');
> > 'orange': ShowMessage('orange');
> > 'apple': ShowMessage('red');
> > else
> > ShowMessage('black');
> > end;

1.13 function and procedure declaration

> Declaration of functions and procedures are similar to Object Pascal in Delphi, with the difference you don't specify
> variable types. Just like OP, to return function values, use implicited declared result variable. Parameters by reference
> can also be used, with the restriction mentioned: no need to specify variable types. Some examples:

> > procedure HelloWord;
> > begin
> > ShowMessage('Hello world!');
> > end;

> > procedure UpcaseMessage(Msg);
> > begin
> > ShowMessage(Uppercase(Msg));
> > end;

> > function TodayAsString;
> > begin
> > result:=DateToStr(Date);
> > end;

> > function Max(A,B);
> > begin
> > if A>B then
> > result:=A
> > else
> > result:=B;
> > end;

> > procedure SwapValues(var A, B);
> > Var Temp;
> > begin
> > Temp:=A;
> > A:=B;
> > B:=Temp;
> > end;

2.1 Date function

> function Date: TDateTime;

> > Use Date to obtain the current date as a TDateTime value.

> function Time: TDateTime;

> > Time returns the current time as a TDateTime value.

> function Now: TDateTime;

> > Returns the current date and time, corresponding to Date + Time.

> function DateTimeToStr(DateTime: TDateTime): string;

> > DateTimeToString converts the TDateTime value given by DateTime using the format given by the ShortDateFormat global variable, followed by the time using the format given by the LongTimeFormat global variable. The time is not displayed if the fractional part of the DateTime value is zero.

> function DayOfWeek(Date: TDateTime): Integer;

> > DayOfWeek returns the day of the week of the specified date as an integer between 1 and 7, where Sunday is the first day of the week and Saturday is the seventh.

> function StrToDate(const S: string): TDateTime;

> > Call StrToDate to parse a string that specifies a date. If S does not contain a valid date

> procedure DecodeDateAndTime(Date: TDateTime; var Y,M,D: word; Time: TDateTime; var H,Min,S: word);

> > Call DecodeDateAndTime to decode current date and time. Example:

> > > Y:=0;
> > > M:=0;
> > > D:=0;
> > > H:=0;
> > > Min:=0;
> > > S:=0;
> > > DecodeDateAndTime(Date,Y,M,D,Time,H,Min,S);
> > > ShowMessage('This is year '+IntToStr(Y));
> > > ShowMessage('Current month is '+IntToStr(M));
> > > ShowMessage('Today is day number '+IntToStr(D));
> > > ShowMessage('Current hour is '+IntToStr(H));
> > > ShowMessage('Minutes pass current hour: '+IntToStr(Min));
> > > ShowMessage('Finally, seconds: '+IntToStr(S));

2.2 String function

> function Pos(Substr: string; S: string): Integer;

> > Pos searches for Substr within S and returns an integer value that is the index of the first character of Substr within S. Pos is case-sensitive. If Substr is not found, Pos returns zero.

> function Copy(S: string; Index, Count: Integer): string;

> > If Index is larger than the length of S, Copy returns an empty string.If Count specifies more characters than are available, only the characters or elements from S[Index] to the end of S are returned.

> procedure Insert(Source: string; var S: string; Index: Integer);

> > Insert merges Source into S at the position S[index]. Source is a string-type expression. S is a string-type variable of any length. Index is an integer-type expression. It is a character index and not a byte index.

> procedure Delete(var S: string; Index, Count:Integer);

> > Delete removes a substring of Count characters from string S starting with S[Index]. S is a string-type variable. Index and Count are integer-type expressions. If Index is larger than the length of S, no characters are deleted. If Count specifies more characters than remain starting at the S[Index], Delete removes the rest of the string.

> function Length(S: string): Integer;

> > Length returns the number of characters actually used in the string or the number of elements in the array.

> function IntToStr(Value: Integer): string;

> > IntToStr converts an integer into a string containing the decimal representation of that number.

> function UpperCase(const S: string): string;

> > UpperCase returns a copy of the string S, with the same text but with all 7-bit ASCII characters between 'a' and 'z' converted to uppercase.

> function LowerCase(const S: string): string;

> > LowerCase returns a string with the same text as the string passed in S, but with all letters converted to lowercase. The conversion affects only 7-bit ASCII characters between 'A' and 'Z'.

> function Trim(const S: string): string;

> > Trim removes leading and trailing spaces and control characters from the given string S.

> function TrimLeft(const S: string): string;

> > TrimLeft returns a copy of the string S with leading spaces and control characters removed.

> function TrimRight(const S: string): string;

> > TrimRight returns a copy of the string S with trailing spaces and control characters removed.

> function IsSameText(S1, S2: string): Boolean;

> > IsSameText compares S1 to S2, without case sensitivity. The compare operation is controlled by the current Windows locale. The return value is True if the two strings have the same value, False otherwise.

> function IsSameString(S1, S2: string): Boolean;

> > IsSameString compares S1 to S2, with case sensitivity. The compare operation is controlled by the current Windows locale. The return value is True if the two strings have the same value, False otherwise.

> See also: UF_MATCH

2.3 miscellaneous routines

> procedure Beep;

> > Beep calls the Windows API MessageBeep.

> function Low(X);

> > Call Low to obtain the lowest value or first element of an Array. Result type is X, or the index type of X where X is either a type identifier or a variable reference.

> function High(X);

> > Call High to obtain the upper limit of an Array. The result type is X, or the index type of X.

> procedure ShowMessage(const Msg: string);

> > Call ShowMessage to display a simple message box with an OK button. The Msg parameter is the message string that appears in the message box. The name of the application's executable file appears as the caption of the message box. But ShowMessage procedure cant running in thread mode, to working with dialog with thread mode, try UF_MsgBox

3.1 Include other script files

> UltraFXP support include a script file into script, to do this, at begining of script, write:

> > {$I some_script_file.usp}

> then UltraFXP will find some_script_file.usp at directory and load it to merge with script.
> You can include many script file with the {$I filename.usp}, If script file not at directory of UltraFXP you must write full path for the script file.

3.2 Global variable

3.3 Global object

3.3.1 Main Window

> Main Window is the UltraFXP main window, in script, the variable name is fmUltra, this variable is not working at THREAD MODE

> property Caption: string; //the title of main window of UltraFXP

> > //Script call
> > ShowMessage(fmUltra.Caption);

> property Top : Integer; // Specifies the Y coordinate of the top left corner of main window

> > //Script call
> > fmUltra.top := 10;

> property Left : Integer; //Specifies the X cooridnate of the left edge of main window

> property Width: Integer; //Specifies the horizontal size of main window

> property Height: Integer; //Specifies the vertical size of main window

> procedure PopupToFront; //show main window at topmost postion of your desktop evenif UltraFXP is at system tray

> > //Script call
> > fmUltra.PopupToFront;

3.3.2 Server Manager

> Server Manager is a manager of ftp server object. the variable name is ServerMgr

> property GetActiveServerCount : Integer //total count of current all connected ftp

> > //Script call
> > ShowMessage('Total count of connected servers: '+IntToStr(ServerMgr.GetActiveServerCount));

3.4 Global function

3.4.1 Get text from Windows Clipboard

> function UF_GetClipText:string;
> Usage: UF_RAW('FtpA', 'MKD ' + UF_GetClipText);
> Comment: If you have a text at clipboard, and the text is 'Here.Is.Sam', will make a directory named 'Here.Is.Sam' at FtpA

3.4.2 Sleep for some seconds

> procedure UF_Sleep(Amillisecond: Integer);
> Usage: UF_Sleep(1000);
> Comment: will sleep 1 second then continue to run , when script running with thread mode, this function will let script wait for some seconds at background, If script isnt running with thread mode, a long time sleep will make whole application lost response

3.4.3 Accept User Input Text

> function UF_InputQuery(Caption, Text: string; var Value: string): Boolean;
> Description
> The value of Caption is caption of dialog
> The value of Text is prompt for input
> The value of Value is result of input text
> Return Values
> The return value is true if use input text is not empty, else return is false;
> Usage:
> defaultInputText := 'Drivers';
> if UF_InputQuery('change to bookmark?' , 'bookmark name', defaultInput) then
> UF_GotoBM('',defaultInputText);
> Comment:
> popup a dialog wait use input a bookmark name, default input text is 'Drivers', user can change this text or left it as default, after user press ok button, all active servers will change to 'Drivers' bookmark if server have a bookmark named 'Drivers'

3.4.4 Show a Message Box Dialog

> function UF_MsgBox(Caption: string; Text: string; Type: Integer): Integer;
> Description
> The value of Caption is used for the dialog box title
> The value of Text is containing the message to be displayed
> The value of Type specifies a set of bit flags that determine the contents and behavior of the dialog box
> Flag Meaning
> 0 The message box contains one push button: OK. This is the default.
> 1 The message box contains two push buttons: OK and Cancel.
> 2 The message box contains three push buttons: Abort, Retry, and Ignore.
> 4 The message box contains two push buttons: Yes and No.
> 3 The message box contains three push buttons: Yes, No, and Cancel.
> 5 The message box contains two push buttons: Retry and Cancel.
> Return Values
> The return value is zero if there is not enough memory to create the message box.
> Value Meaning
> 1 OK button was selected.
> 2 Cancel button was selected.
> 3 Abort button was selected.
> 4 Retry button was selected.
> 5 Ignore button was selected.
> 6 Yes button was selected.
> 7 No button was selected.
> Usage: UF_MsgBox('Error' , 'No this site name!', 0);
> Comment: Show a dialog with 1 OK button and Text is 'No this site name');
> Usage: UF_MsgBox('Confirm', 'Do you want to FXP this dir?', 1);
> Comment: Show a dialog with OK and Cancel Button and Text is 'Do you want to FXP this dir?'
> Usage: if UF_MsgBox('Confirm', 'Do you want to FXP this dir?', 1)=1 then
> UF_FXPDIR('FtpA', '/Win32/Drivers', 'FtpB', '/Drivers/','',-1);
> Comment: FXP directory 'TestDir' from FtpA to FtpB if press OK button , See also: UF_FXPDIR

3.4.5 Match Strings

> function UF_MATCH(ASource: string; APattern: string);
> Usage: if UF_MATCH(UF_GetClipText,'*Idle*')=1 then UF_RAW('','NOOP');
> Comment: if find 'idle' at clipboard text, then send 'NOOP' to all connected sites

3.4.6 Send text to mIRC

> procedure UF_MIRC(ALog: string);
> Usage: UF_MIRC('UltraFXP is best');
> Comment: Send text 'UltraFXP is best' to mIRC if have 1 or more mIRC running.

> Usage: UF_MIRC('\server 127.0.0.1');
> Comment: when '\' as first char, UltraFXP will replace it as '/', so this call do same as '/server 127.0.0.1' at mIRC

3.4.7 Execute a application at windows

> procedure UF_ShellExecute(ExecutableFile: string; Param: string; Reversed: Integer);

> Description
> The value of ExecutableFile is an executable file or a document file
> The value of Param: when ExecutableFile parem is not empty, Param specifies specifies parameters to be passed to the application, if ExecutableFile is empty, Param can use to execute a DOS program or Batch file
> The value of Reversed is reversed, set it to 0.
> Example

> > UF_ShellExecute('c:\winrar.exe','a -ep1 -r c:\test.zip c:\temp\', 0);
> > UF_ShellExecute('','c:\temp\test.bat', 0);

3.5 Script function for FTP

3.5.1 Connect to FTP

> procedure UF_CON(sitename: string);

> > Usage: UF_CON('sitea');
> > Comment: connect to site named sitea
> > Usage: UF_CON('sitea siteb sitec');
> > Comment: connect to sitea siteb sitec at same time, SPACE as delimeter

> procedure UF_CON_EX(SitenameList: string; RemotePathOrBookMark: string);

> > Usage: UF_CON_EX('siteA','/somedir/');
> > Comment: connect to siteA and change directory to /somedir/
> > Usage: UF_CON_EX('siteA','drivers');
> > Comment: connect to siteA and change directory to the directory of bookmark 'drivers'
> > Usage: UF_CON_EX('siteA siteB','drivers');
> > Comment: connect to siteA and siteB then change directory to the directory of bookmark 'drivers'

3.5.2 Send raw command to FTP

> procedure UF_RAW(sitename,command: string);
> Usage: UF_RAW('FtpA', 'site who');
> Comment: send 'site who' command to FtpA
> Usage: UF_RAW('FtpA FtpB', 'site who');
> Comment: send 'site who' command to FtpA and FtpB, SPACE as delimeter
> Usage: UF_RAW('','site who');
> Comment: send 'site who' command to all connected FTP servers at UltraFXP

3.5.3 Change directory with FTP Bookmark

> procedure UF_GotoBM(sitename,bookmark: string);
> Usage: UF_GotoBM('FtpA','Drivers');
> Comment: let FtpA change to bookmark directory named 'Drivers'
> Usage: UF_GotoBM('FtpA FtpB FtpC','Drivers');
> Comment: let FtpA FtpB FtpC all change to bookmark directory named 'Drivers', SPACE as delimeter
> Usage: UF_GotoBM('','Drivers');
> Comment: let all connected FTP servers change to bookmark directory named 'Drivers'

3.5.4 Disconnect from FTP Servers

> procedure UF_EXIT(sitename: string);
> Usage: UF_EXIT('FtpA');
> Comment: find FtpA and disconnect it
> Usage: UF_EXIT('FtpA FtpB FtpC');
> Comment: disconnect from FtpA FtpB FtpC, SPACE as delimeter

3.5.5 Execute command at FTP and return result to mIRC

> procedure UF_Raw_MIRC(FtpName: string; rawCommand: string; mode: Integer;disconnect: Integer); //working for reg version only

> Description
> The value of FtpName is name of FTP server
> The value of rawCommand is the command execute at FTP Server
> The value of mode set to 0 means use default UltraFXP mIRC annouce setting
> The value of disconnect: 0(disconnect)/1(dont disconnect)
> Usage: UF_Raw_MIRC('FtpA','site who',0,0);
> Comment: Connect to FtpA and execute 'site who' command and reply command result to mIRC,and disconnect from FtpA when command executed,to use this function, must check "enabled mIRC announcements"/"execute script".

3.5.6 Remove Directory or File at FTP

> procedure UF_RemoveDirOrFile(FtpName: string; bookmarkname: string; dirname: string; folderKind: Integer; bookmarkKind: Integer; disconnect: Integer);

> Description
> The value of FtpName is name of FTP server
> The value of bookmarkname is the FTP path or a bookmark , decided by bookmarkKind param.
> The value of dirname is the name of folder or a file, decided by folderKind param.
> The value of folderKind: 0(dir)/1(file)
> The value of bookmarkKind: bookmarkKind = 0(bookmark)/1(path)
> The value of disconnect: 0(disconnect)/1(dont disconnect)
> Usage: UF_RemoveDirOrFile('FtpA','/Drivers/','win32vga.zip',1,1,0);
> Comment: Connect to FtpA and delete the file 'win32vga.zip' at /Drivers/ directory. then disconnect from FtpA

3.6 Script function for FXP

3.6.1 UF_FXPDIR (FXP from 1 FTP to another FTP via script)

> UF_FXPDIR can help user mirror 2 FTP servers easy.

> procedure UF_FXPDIR(src, srcdir, dest, destdir, dirname: string; subdirCount: Integer);
> Description
> The value of src is source ftp server
> The value of srcdir is a real ftp directory or a bookmark
> The value of dest is dest ftp server
> The value of destdir is a real ftp directory or a bookmark
> The value of dirname is a directory name
> The value of subdirCount is how many sub directory will be added to queue, -1 means add all sub directory , 1 means add lastest 1 irectory to queue only, 2 means add lastest 2 directory to queue only. etc.. the count starts from topmost of sub directories and follow the folder sort order rules.
> Usage: UF_FXPDIR('FtpA', '/Win32/', 'FtpB', '/Drivers/','',-1);
> Comment: FXP all directory from FtpA 's /Win32/ directory to FtpB's /Drivers/ directory
> Usage: UF_FXPDIR('FtpA,'Drivers','FtpB','Drivers','',-1);
> Comment: FXP all directory from FtpA 's Drivers bookmark to FtpB's Drivers bookmark

3.6.2 UF_FXPDIREX (FXP from 1 FTP to another FTP via script)

> procedure UF_FxpDirEx(src, srcdir, dest, destdir, dirname: string; subdirCount: Integer,Flag: string);

> Description
> The value of src is source ftp server
> The value of srcdir is a real ftp directory or a bookmark
> The value of dest is dest ftp server
> The value of destdir is a real ftp directory or a bookmark
> The value of dirname is a directory name
> The value of subdirCount is how many sub directory will be added to queue, -1 means add all sub directory , 1 means add lastest 1 irectory to queue only, 2 means add lastest 2 directory to queue only. etc.. the count starts from topmost of sub directories and follow the folder sort order rules.
> The value of Flag is to extend use, the first 7 chars, can control Queue Thread disconnect from Both FTP with 'LOGOUT', or let user make a custom filter for folder/files when transfering.
> Usage: UF_FXPDIREX('FtpA', '/Win32/', 'FtpB', '/Drivers/','',-1,'LOGOUT');
> Comment: FXP all directory from FtpA 's /Win32/ directory to FtpB's /Drivers/ directory, and disconnect from both FTP when transfer finished.
> Usage: UF_FXPDIREX('FtpA', '/Win32/', 'FtpB', '/Drivers/','',-1,'LOGOUT;%D%*;%F%*.html');
> Comment: FXP all directory from FtpA 's /Win32/ directory to FtpB's /Drivers/ directory, and disconnect from both FTP when transfer finished. and all folders at FTPA /Win32/ directory will be transfered, for files at FTPA/Win32/, only filename match '*.html' will be transfered.
> Usage: UF_FXPDIREX('FtpA', '/Win32/', 'FtpB', '/Drivers/','',-1,'ANYANY;%D%*text*;%F%*');
> Comment: FXP all directory from FtpA 's /Win32/ directory to FtpB's /Drivers/ directory, and idle at both FTP when transfer finished. and all folders at FTPA /Win32/ directory match '*text*'will be transfered, for all files at FTPA/Win32/ will be transfered.

3.6.3 UF_FXPDIRAPPEND (FXP from 1 FTP to many FTP via script)

> procedure UF_FXPDIRAPPEND(FtpNameList,BookmarkName,DirName: string; subdirCount: Integer,Flag: string);

> Description
> The value of FtpNameList is a list of FTP servers, split with ';'
> The value of BookmarkName is a bookmark of FTP and must ALL EXISTS at the list of FTP servers
> The value of Dirname is the directory inside bookmark , can be a empty string
> The value of subdirCount is how many sub directory will be added to queue, -1 means add all sub directory , 1 means add lastest 1 irectory to queue only, 2 means add lastest 2 directory to queue only. etc.. the count starts from topmost of sub directories and follow the folder sort order rules.
> The value of Flag is to extend use, the first 7 chars, can control Queue Thread disconnect from Both FTP with 'LOGOUT', or let user make a custom filter for folder/files when transfering.

> Usage: UF_FXPDIREX('FtpA;FtpB;FtpC', 'Backup', '', -1,'LOGOUT');
> Comment: FXP all directory from FtpA 's 'Backup' bookmark FtpB's 'Backup' bookmark, then FXP all directory from FtpB 's 'Backup' bookmark to FtpC's 'Backup' bookmark, and disconnect from FtpA,FtpB,FtpC when transfer finished.
> Usage: UF_FXPDIREX('FtpA;FtpB;FtpC', 'Backup', '', -1,'LOGOUT;%D%*;%F%*.html');
> Comment: FXP all directory from FtpA 's 'Backup' bookmark FtpB's 'Backup' bookmark, then FXP all directory from FtpB 's 'Backup' bookmark to FtpC's 'Backup' bookmark, and disconnect from FtpA,FtpB,FtpC when transfer finished. and all folders at FtpA/FtpB 'Backup' bookmark will be transfered, for files at FtpA/FtpB 'Backup' bookmark, only filename match '*.html' will be transfered.
> Usage: UF_FXPDIREX('FtpA;FtpB;FtpC', 'Backup', '', -1,'ANYANY;%D%*text*;%F%*');
> Comment: FXP all directory from FtpA 's 'Backup' bookmark FtpB's 'Backup' bookmark, then FXP all directory from FtpB 's 'Backup' bookmark to FtpC's 'Backup' bookmark, and idle at FtpA,FtpB,FtpC when transfer finished.. and all folders at FtpA/FtpB 'Backup' bookmark match '*text*'will be transfered, for all files at FtpA/FtpB 'Backup' bookmark will be transfered.

3.6.4 UF_CHAINFXPDIR (FXP to Many FTP Server at Same Time via script)

> procedure UF_CHAINFXPDIR(FtpNameList,bookmark,dirname: string; repeatcount: Integer);

> > Description
> > The value of FtpNameList is a FTP name list , ';' as as delimeter
> > The value of bookmark is site bookmark
> > The value of dirname is a directory name without '/'
> > The value of repeatcount must larger than zero. means how many times need refresh when no files to FXP, This param is smart, If you set a refresh count to 10, and UltraFXP did 9 times refresh, at the 10th refresh UltraFXP compare both FTP directory and found have new file, the repeatcount will reset to 10.
> > Usage: UF_CHAINFXPDIR('FtpA;FtpB;FtpC','Backup','TodayBackup',10);
> > Comment: will make 2 queue, FtpA -> FtpB, FtpB -> FtpC, with bookmark 'Backup' and transfer the directory named 'TodayBackup', the Queue will refresh 10 times
> > Notes:
> > If dirname at Global Skip List, nothing will transfer
> > If dirname at Site Skip List, this site will be removed from CHAIN
> > if Site is Disable, this site will be removed from CHAIN
> > RepeatCount set to 10 is enough.
> > This function is useful if user want to mirror 2+ FTP and need away from computer to do something.
> > UltraFXP have a option named 'SMART ChainFXPDIR', if enabled, and source FTP have some script installed, UltraFXP will fetch the complete flag and auto stop Queue Thread when found source FTP already completed.

> function UF_STOPLASTCHAINFXPDIR;

> > Description
> > Call this function will stop the last function call of UF_CHAINFXPDIR asap from stack.