Pharos Scripting Language Primer

A number of example scripts can be found on the Pharos disk image at \tools\plugins\scripts.

Comments

  • Comments are annotations to script code that should help make it more readable
  • C and C++ style comments are supported
  • Comments are ignored by the script compiler, so they do not make the script run slower use them liberally

/* C style comments begin with a /* symbol, and can span multiple lines, ending with a */ symbol */

// C++ style comments begin with //, ending at the end of the line

Variables and Namespaces

  • A variable is a named entity that can contain a value
  • A namespace is a named entity that can contain variables and functions
  • Every variable exists in a namespace, which if not specified is the namespace local to the script
  • Notice that the following statements are terminated by a semicolon ;, as are most statements

new a;

// creates a new uninitialized variable, called a, in the local namespace

a = PlugIn.Client;

// sets a equal to the value of Client in namespace PlugIn

Types and Constants

  • A type describes the nature of a value, for example a bool type value can be only true or false
  • A constant is a value written in the source code, for example 1.0 is a constant of type float
  • The type of a variable is the type of its current value
  • A variable can be assigned a value of any type at any time

new b = true;

// bool type (true or false)

new i = 1;

// int type (32-bit signed integer)

new f = 1.0;

// float type (64-bit floating point number)

new s = "1";

// string type (8-bit ASCII character with C escape codes e.g. "\r")

new l = [false, 0, 0.1, "0", []]

// list type (may contain any type)

b = i;

// now b has a value of type int

b = true;

// now b has a bool again

Expressions and Operators

  • An expression is a fragment of source code involving variables, constants and/or operators
  • An operator is a symbol or word that operates on one expression, for a unary operator, or two expressions for a binary operator, e.g. =, + and and are binary operators, whereas not is a unary operator
  • For all assignment operators except simple assignment, the second expression is converted to the type of the first

b = false;

// assignment expression (simple)

i += 1;

// assignment expression (add)

i -= 1;

// assignment expression (subtract)

i *= 2;

// assignment expression (multiply)

i /= 2;

// assignment expression (divide)

  • Expressions referred to below are the code fragments between the = and the ;
  • For binary operators the second expression is converted to the type of the first

s = "line\r\n";

// constant expression (string)

s = i;

// identifier expression (yields value of i)

l = n.f(s);

// function expression (in namespace n, passing parameter s)

i = l[0];

// subscript expression (yields first element in list l)

i = -i;

// unary expression (minus)

b = not b;

// unary expression (not)

f = f / i * 2;

// multiplicative expression

i = 3 mod 2;

// multiplicative expression (remainder)

i = i + (i 1);

// additive expression (with parenthesized expression)

b = i < 1;

// relational expression (less-than)

b = i <= 1;

// relational expression (less-than-equal)

b = i > 1;

// relational expression (greater-than)

b = i >= 1;

// relational expression (greater-than-equal)

b = i != 1;

// equality expression (not-equal-to)

b = i <> 1;

// equality expression (not-equal-to)

b = i == 1;

// equality expression (equal-to)

b = b and true;

// logical expression (and)

b = b or true;

// logical expression (or)

User- Defined Functions

Uniprint allows you to create your own functions when writing scripts. Functions are like small pieces of programs that can be defined anywhere in your script, and can be used anywhere after its definition. This gives you the ability to break down large scripts into smaller, reusable units. The following section provides you with the basic concepts of writing user-defined functions and examples to help you understand them.

You can find a number of sample scripts with user-defined functions on the Pharos disk at \tools\plugins\scripts. Sample scripts with user-defined functions include Logon - Authenticate and Translate Users.txt, Billing - Pharos Accounts Plus Online Accounts.txt, JobInformation - Notify User of Job Cost.txt.

Defining Functions

User-defined functions are created with the "function" keyword, the name of the function, and a list of parameters enclosed in parentheses (which may be empty). The body of the function is enclosed in curly braces.

function say_hello()

{

IO.PrintLine("Hello world!");

}

function IsAccountAvailable(name)

{

try

{

 IO.PrintLine(sLogPrefix + "Get user by logon id.");

 User.GetUserByLogon(name);

 return true;

}

catch {...}

return false;

}

 

A function can also take more than one parameter. In the following example, the function average has two parameters x and y. You can also use local variables, created in the usual way using "new".

function average(x, y)

{

new sum = x + y;

}

Calling Functions

User-defined functions are called in the same way as built-in functions. To call a function, use the function name followed by a parentheses.

say_hello();

Returning Values

A function may optionally return a value using the "return" statement.The parameters and return value of a function may have any of the standard data types (boolean, integer, float, string, or list).

function average(x, y)

{

new sum = x + y;

return sum / 2;

}

Example 1:

function say_hello()

{

IO.PrintLine("Hello world!");

}

function average(x, y)

{

new sum = x + y;

return sum / 2;

}

say_hello(); // Prints "Hello world!"

new a = 10;

new b = 20;

new c = average(a, b); // Sets c to 15

Inside the body of a function, you can use the function's parameters, as well as any global variables created outside the function. These exist only inside the function, and will disappear when the function returns. A local variable can have the same name as a global variable;the two variables will not interfere with each other.

Functions can call other functions, but a function may not call itself.

new a = 10;

function times_a(x)

{

return a * x;

}

new b = times_a(5); // Sets b to 50

a = 20;

new c = times_a(5); // Sets c to 100

function square(x)

{

return x * x;

}

 

function add_squares(x, y)

{

// Calling another function is allowed

return square(x) + square(y);

}

 

function factorial(n)

{

// ILLEGAL - can't call a function from itself

if (n > 1)

{

return n * factorial(n - 1);

}

else

{

return 1;

}

}

Type Conversions

  • Type conversion occurs when a binary operator is used with expressions of two different types
  • For binary operators (except simple assignment), the second expression is converted to the type of the first

The variables in the examples below have been assigned types as in the examples in the Types and Constants section above, i.e. b is a boolean value, i is an integer, f is a float, l is a list (of five values) and s is a string.

b = b or 0;

// 0 converted to false

b = b and 2;

// 2 (or any non-zero integer or float) converted to true

i = i + "2";

// "2" converted to 2

i = i + 2.6;

// 2.6 converted to 2 by truncation

i = i + l;

// l is converted to 5 (length of l)

f = f + true;

// true converted to 1.0

f = f - "2.6";

// "2.6" converted to 2.6

s = "" + l;

// l converted to "0, 0, 0.1, "0", []"

Statements

  • A script is made up of a sequence of any number of statements
  • A statement is a fragment of source code that is syntactically complete and correct, and which will therefore compile successfully, e.g. a = 1 is an expression, whereas a = 1; is a complete expression statement
  • All statements except if, else, while and compound statements are terminated by a semicolon ;

import "DB";

// import statement (makes DB namespace function calls available)

new a;

// new statement uninitialized (creates a)

new b = false;

// new statement with initializer (b is bool)

a = 2;

// expression statement

f(a);

// expression statement (value discarded)

if (a < i)

// if statement

     ;

// null statement (only do this if a < i)

else

// else statement

     a = f(a);

// (otherwise do this when not (a < i))

while (a < i)

// while statement

{

// compound statement

     a = f(a);

// (do this ...)

     b = f(b);

// (and this while (a < i))

}

// end compound statement

try

// try statement

{

// try block compound statement

     a = f(a);

// jump to catch block if error occurs

     throw

// jump to catch block

}

// end try block

catch

// catch statement (required after a try block)

{

// catch block compound statement (for error handling)

     exit

// terminates the script early without error

}

// end catch block

Namespace Function Interfaces

  • Parameters to functions have a suffix which indicates the type expected, e.g. _int for an integer, _any for a value of any type
  • Unexpected types will be type converted to the expected types
  • Parameters with a suffix of _name expect a variable name of the type prefixed, eg string_name should be a string variable
  • Following the function description will be the return value type, which may also be (any) for any type, or (none) for no return value

Authentication (namespace "Auth")

The Auth namespace is a simple way for scripts to verify a username and password against a third party directory, such as Active Directory or an LDAP server. More advanced functionality may require use of other tools instead of (or in addition to) these functions. In all functions, the default timeout value is 30 (seconds).

Depending on how your LDAP server is configured, you may need more than the submitted username to authenticate. Some LDAP servers will accept a simple username, while others will require more information to authenticate, such as Distinguished Name, or DN (e.g. CN=jsmith, OU=some_department, DC=mydomain, DC=com). If your LDAP server requires a DN to complete a bind, you will need to build this string from what the user types in. Consult your network administrator if necessary.

LdapAD(username_string, password_string, servername_string {, port_int{, timeout_int}});

// Verify the given username and password against Active Directory.
// servername_string may be set to the name of the domain rather than an explicit directory server.
//
// NOTE: This function uses a Microsoft-specific requirement to pass credentials via LDAP. It is
// not appropriate for LDAP systems, but recommended for Active Directory. The credentials are
// not passed in plain text.

// NOTE: LdapAD uses port 389 by default.
// The function returns true if the username and password were considered valid by the server, and
// false otherwise. If a connection error occurs, an exception will be thrown instead.

LdapKerberos(username_string, password_string, servername_string {, port_int{, timeout_int}});

// Verify the given username and password against Active Directory, using Kerberos encryption.
// servername_string may be set to the name of the domain rather than an explicit directory server.
//
// NOTE: This function does not perform Kerberos authentication of the user. Instead, Kerberos
// encryption is used by the operating system to protect the LDAP communication. This function is
// only intended for use with Active Directory systems.

//
// The function returns true if the username and password were considered valid by the server, and
// false otherwise. If a connection error occurs, an exception will be thrown instead.

LdapSsl(username_string, password_string, servername_string {, port_int{, timeout_int}});

// Verify the given username and password against an LDAP server using SSL to protect the connection.
//
// NOTE: LdapSsl uses port 636 by default.
//
// The function returns true if the username and password were considered valid by the server, and
// false otherwise. If a connection error occurs, an exception will be thrown instead.

LdapPlainText(username_string, password_string, servername_string {, port_int{, timeout_int}});

// Verify the given username and password against an LDAP server without using any network encryption.
//
// NOTE: Use of this function is discouraged, except for testing and diagnostic purposes. The lack
// of encryption means user credentials will be passed to the server in plain text.
//
// The function returns true if the username and password were considered valid by the server, and
// false otherwise. If a connection error occurs, an exception will be thrown instead.

The following shows a sample script using the "Auth" namespace

import "Auth";

PlugIn.Result = false;

try

{

if (Auth.LdapAD(PlugIn.UserName, PlugIn.Password, "my.domain.com"))

{

PlugIn.Result = true;

}

else

{

PlugIn.Error = "Your username or password were not correct.";

}

}

catch

{

PlugIn.Error = "The system was unable to verify your credentials at this time.";

}

Database (namespace "DB")

ColIndexFromName(column_string);

// returns results column index (int)

ColNameFromIndex(index_int);

// returns results column name (string)

ColumnByIndex(index_int);

// returns results column value (any)

ColumnByName(column_string);

/ returns results column value (any)

GetNumColumns( );

// returns number of results columns (int)

GetNumRows( );

// returns number of results rows (int)

GetRow( );

// returns whether we got next results row (bool)

As of Uniprint 7.2, you must check for available rows(i.e. making sure that DB.GetRow returns true) when calling DB.ColumnByName() or DB.ColumnByIndex(). In addition, you should always have a try/catch block around any DB.SQL() call. For example, you can have:

try

{

DB.ParametrizedSQL("select * from users where id = @1", PlugIn.UserName);

if (not DB.GetRow())

{

exit;

}

DB.ColumnByName(email);

}

catch{ ... }

Online();

// returns whether or not the database is online, i.e. reachable from the
// server running the script (int). 1 = online, 0 = offline.

ParametrizedSQL(sql_string{, parameter1{,parameter2...parameter n}});

// Creates a DB connection if none present, then executes
// SQL sql_string, using the supplied parameters, which
// replace @1, @2, etc in the SQL statement, e.g.
//
// DB.ParametrizedSQL("select * from users where id = @1", PlugIn.UserName);
//
// DB.ParametrizedSQL("exec pp_user_purse_balances @bill_name = @1, @pstation = @2", PlugIn.BillName, PlugIn.Client);


Using ParametrizedSQL() for passing parameters to stored procedures creates a need to use the SQL keyword "exec" in cases where it isn't necessary with SQL()

SQL(sql_string {,client_name_string});

// Creates a DB connection if none present, with a client name
// of client_name_string (or Anonymous if omitted), then
// executes SQL sql_string (call GetRow( ) etc for results) (none)

Pharos Systems recommends the use of DB.ParametrizedSQL() over DB.SQL(), to reduce the risk of SQL injection attacks.

Input/Output (namespace "IO")

DeleteFile(filename_string)

// Deletes the file named filename_string and
// returns whether the operation succeeded (bool)

LoadFile(string_name, filename_string{, length_int});

// loads up to length_int
// (or all, if omitted) characters from file filename_string into
// string variable string_name
// and returns whether the operation succeeded (bool)

PrintLine(line_string);

// prints each line_string on a separate line (none)

SaveFile(string_name, filename_string{, length_int});

// saves up to length_int (or all, if omitted) characters from
// string variable string_name to file filename_string
// and returns whether the operation succeeded (bool)

List (namespace "List")

Concat(list_name, 0_list{, 1_list ...});

// concatenates 0_list etc to list variable list_name (no return value)

Delete(list_name, pos_int);

// deletes element number pos_int from list variable list_name, where
// pos_int is zero-based (ie 0 is the first element) (no return value)

Insert(list_name, pos_int, value_any);

// inserts value_any into list variable list_name before element number
// pos_int, where pos_int is zero-based (ie 0 is the first element) (no return value)

Length(0_list{, 1_list ...});

// returns the combined length of 0_list etc (returns an int value)

Notify (namespace "Notify")

BalloonBox(client_string, title_string, message_string, timeout_int{, style_int})

// Displays a system tray balloon message at the user workstation specified by client_string
// The message will be titled title_string and has message_string as the content.
// It will display for up to timeout_int seconds unless it is dismissed by the user.
//
// The style is optional. If not supplied, the balloon will be deemed an Informational message.
// 0 = No style specified
// 1 = Information message
// 2 = Warning message
// 3 = Error message
//
// Note: Under MS Windows the style indicator determines which icon is displayed with the message.
// Other operation systems may implement the style indicator differently.

MessageBox(client_string, message_string, timeout_int{, buttons_int})

// sends message_string (with buttons_int) to a user's notify application on machine client_string
// displaying it for up to timeout_int seconds
//
// buttons_int is optional. If not supplied, assumes OK button is wanted
// 0 = OK button only
// 1 = OK + Cancel buttons
// 2 = Abort + Retry + Ignore buttons
// 3 = Yes + No + Cancel
// 4 = Yes + No
// 5 = Retry + Cancel
//
// returns: button that is pressed, as int
// 0 for timeout, 1 for OK, 2 for cancel, 3 for abort, 4 for retry, 5 for ignore, 6 for yes, 7 for no

QuestionBoxFloat(client_string, prompt_string, description_string, timeout_int,
default_string, string_name, minimum_float, maximum_float, places_int);

// displays a question box with prompt prompt_string,
// description description_string and default
// default_string
// on machine (name or IP address) client_string
// for at most timeout_int seconds
//
// returns an int value of -1 for timeout, 0 for
// cancel and 1 for Ok, in which case the user
// selected result is stored in string_name
//
// any result must be between minimum_float and
// maximum_float (inclusive) and at most places_int
// decimal places

QuestionBoxInt(client_string, prompt_string, description_string, timeout_int,
default_string, string_name, minimum_int, maximum_int);

// displays a question box with prompt prompt_string,
// description description_string and default
// default_string
// on machine (name or IP address) client_string
// for at most timeout_int seconds
//
// returns an int value of -1 for timeout, 0 for
// cancel and 1 for Ok, in which case the user
// selected result is stored in string_name
//
// any result must be between minimum_int and
// maximum_int (inclusive)

QuestionBoxList(client_string, prompt_string, description_string, timeout_int,
default_string, string_name, option_list);


// displays a question box with prompt prompt_string,
// description description_string and default
// default_string
// on machine (name or IP address) client_string
// for at most timeout_int seconds
//
// returns an int value of -1 for timeout, 0 for
// cancel and 1 for Ok, in which case the user
// selected result is stored in string_name
//
// any result must be selected from option_list
// which is a list of values all of which will be
// converted to strings when sent to the notification
// function of the Popup Client

QuestionBoxMoney(client_string, prompt_string, description_string, timeout_int,
default_string, string_name, minimum_float, maximum_float);

// displays a question box with prompt prompt_string,
// description description_string and default
// default_string
// on machine (name or IP address) client_string
// for at most timeout_int seconds
//
// returns an int value of -1 for timeout, 0 for
// cancel and 1 for Ok, in which case the user
// selected result is stored in string_name
//
// any result must be between minimum_float and
// maximum_float (inclusive) and the clients local currency
// settings determine the number of decimal places

QuestionBoxString(client_string, prompt_string, description_string, timeout_int,
default_string, string_name, length_int);

// displays a question box with prompt prompt_string,
// description description_string and default
// default_string
// on machine (name or IP address) client_string
// for at most timeout_int seconds
//
// returns an int value of -1 for timeout, 0 for
// cancel and 1 for Ok, in which case the user
// selected result is stored in string_name
// any result must be of length length_int or less

Plug-ins (namespace "PlugIn")

See Plug-in Interfaces for information.

Print Jobs (namespace "PrintJob")

Copy(source_queue_string, job_id_int, dest_queue_string {,offset_int});

// Copies print job job_id_int in queue source_queue_string to queue
// dest_queue_string. By default, PrintJob.Copy() will remove the popup data. The argument [offset_int] is an optional parameter, which can be used to define if the popup data should be retained or removed. Setting the [offset_int] to zero (0) will retain the popup data and setting it to 1 will remove the popup data.
// The print job will always be duplicated to the Job Store with popup data stripped off, if any.
// Returns the job id of the new job, or -1 on error (returns an int value)

FreePrint(job_id_int, free_print_bool);

//Sets whether the job_id_int should be free of charge or not.
// if free_print_bool is true, the job will be marked for free printing,
// otherwise it will be charged as normal.
// Returns true on success, or false if an error occurs.

GetPopupData(queue_string, id_int, key_string);

// returns the value of the key_string popup data field
// from the print job id_int in queue queue_string or
// an empty string if there was no job or popup data (returns a string value)

// key_string is normally the name of the Question you want the answer for,
// however, three "hidden" Questions are available:
// StaticNotifyIP - this is the IP address that the Popup Client's notification function is listening on (if it is present)
// StaticWorkStn - this is the network name of the client PC
// CC_Static - this is the Cost Center data attached to the print job

SaveTo(job_id_int, dest_path_string {,file_length});

// Save a copy of the print job job_id_int to a local path dest_path_string.
// If the file is saved, the function returns true, otherwise false.
// It is the caller's responsibility to cleanup the destination file.

"File length"(specified in bytes) is an optional parameter that defines how much of the job to copy into the new file (from the beginning). If not specified, the whole spool file for a given job is saved.

SetUsername(queue_name_string, job_id_int, username_string);

// sets the user name information in the print job

SetJobName(queue_name_string, job_id_int, jobname_string);

// sets the job name information in the print job

As of 8.3, the queue_name parameter is ignored.

Script (namespace "Script");

Defined(namespace_string);

// Returns whether namespace_string is defined (returns a bool value)

GetChildren(namespace_string);

// Returns a list of the names of namespace children of namespace_string (returns a list value)

GetParent(namespace_string);

// Returns the name of the parent namespace of namespace_string (returns a string value)

GetType(namespace_string);

// Returns the type name of namespace_string (e.g. "bool", "string") (returns a string)

GetErrorMessage();

// Returns the error message of the most recent exception (returns a string value)

GetErrorType();

// Returns the error type of the most recent exception (e.g. "Script", "PSCom", "PS", "MFC", "General exception") (returns a string value)

GetLineNumber();

// Returns the current execution line number (returns an int value)

SetErrorMessage(error_message_string);

// Sets the exception error message to error_message_string (no return value)

SetErrorType(error_type_string);

// Sets the exception error type to error_type_string (no return value)

String (namespace "String")

Concat(string_name, 0_string{, 1_string ...});

// concatenates 0_string etc to string variable string_name (no return value)

Delete(string_name, pos_int{, length_int});

// deletes length_int (or all if omitted) characters from string
// variable string_name starting at and including index pos_int,
// which is zero-based (i.e. index 0 is the first character) (no return value)

Encrypt(string_name);

// encrypts a string using the same algorithm as the Database Server
// can be used to encrypt user passwords

Find(range_string, target_string);

// returns the zero-based index of the first occurrence of
// target_string in range_string, or -1 if not found (returns an int value)

FindLast(range_string, target_string);

// returns the zero-based index of the last occurrence of
// target_string in range_string, or -1 if not found (returns an int value)

Insert(string_name, pos_int, insert_string);

// inserts string insert_string into string variable string_name
// at (i.e. before the text at) zero-based index pos_int (no return value)

IsEmpty(test_string);

// returns true if test_string is empty (""), false otherwise (returns a bool value)

Left(string_name, num_int);

// truncates string variable string_name to leave only its leftmost
// num_int characters remaining (no return value)

Length(0_string{, 1_string ...});

// returns the combined length of 0_string etc (returns an int value)  

LowerCase(string_name);

// converts all characters in string variable string_name to lower
// case (no return value)

Mid(string_name, pos_int, num_int);

// truncates string variable string_name to leave only the num_int (or
// all if num_int omitted) characters starting at and including
// zero-based index pos_int (no return value)

Right(string_name, num_int);

// truncates string variable string_name to leave only its rightmost
// num_int characters remaining (no return value)  

TrimLeft(string_name);

// removes all whitespace (newline, space, tab) characters from the
// start of string variable string_name (no return value)

TrimRight(string_name);

// removes all whitespace (newline, space, tab) characters from the
// end of string variable string_name (no return value)

UpperCase(string_name);

// converts all characters in string variable string_name to uppercase (no return value)

User (namespace "User")

To use the User namespace, create a new user with the User.Insert() function, or load an existing one with any of the User.GetUser*() functions. If no exception is thrown, the corresponding user record will then be available for use. Once a user has been loaded, all subsequent function calls (e.g. User.GetBalance() or User.SetProperty()) will apply to the currently loaded user. The same user record remains loaded until another call is made to the User.Insert() function or one of the User.GetUser*() functions.

Credit(amount_money, cashier_string {, purse_int{, record_transaction_int}});

// credits the user's balance by the specified amount
//
// purse ID must be 1, 2 or 3 (optional - default is 3)
//
// record_transaction = 1 to record a transaction in the database, 0 to not
// record a transaction (default is 1)
//
// negative amounts are converted to positive, i.e. entering a negative
// value does *not* debit the account

Debit(amount_money, cashier_string {, purse_int{, record_transaction_int}});

// debits the user's balance by the specified amount
//
// purse ID must be 1, 2 or 3 (optional - default is 3)
//
// record_transaction = 1 to record a transaction in the database, 0 to not
// record a transaction (default is 1)
//
// Negative amounts are converted to positive, i.e. entering a negative
// value does *not* credit the account.
//
// The debit occurs even if it causes a negative balance for a user with
// "Advance" billing.

GetBalance(purse_int);

// returns the current balance of the specified purse (1, 2 or 3)

GetProperty(property_string);

// returns the value of the specified property. Possible properties are:
//
// user_id - int (this is the internal ID number)
// user - string (this is the user name)
// active - int
// billing_option - string
// last_name - string
// first_names - string
// group_id - int
// access_level - string
// address - string
// phone - string
// comment - string
// rate_id - int
// card_id - string
// offline_limit - money
// offline_amount - money
// user_alias - string
// is_express - int
// is_visitor - int
// is_guest - int
// email - string
// custom1 - string
// custom2 - string
// group - string
// rate - string

GetUser(searchvalue_string {, column_string});

// loads a user record by the specified column from the users table
// if no column is specified, the default is "user_id"

GetUserByAlias(alias_string);

// loads a user record by their alias
// this is the same as GetUser(<user alias>, "alias")

GetUserByCardID(cardid_string);

// loads a user record by their card ID
// this is the same as GetUser(<user card ID>, "card_id")

GetUserByID(internalid_int);

// loads a user record by their internal ID number
// this is the same as GetUser(<user ID>, "user_id")

GetUserByLogon(name_string);

// loads a user record by their user name
// this is the same as GetUser(<user name>, "id")

Insert(username_string {, firstname_string{, lastname_string}});

// creates a User record with the specified username
// firstname and lastname are optional. They could affect the user alias generated.

SetProperty(property_string, value);

// sets the value of the specified property. The type of the value depends on the property.
// Possible properties are:
//
// user - string
// active - int
// billing_option - string
// last_name - string
// first_names - string
// access_level - string
// address - string
// phone - string
// comment - string
// card_id - string
// offline_limit - money
// user_alias - string
// email - string
// custom1 - string
// custom2 - string
// group - string
// rate - string

PasswordVerify(password_string);

// authenticates the current job owner with the supplied password
// requires user to be loaded first
// This function returns 1 on success, and 0 on failure.

UserPasswordVerify(user_string, password_string);

// authenticates the supplied user and password
// This function returns 1 on success, and 0 on failure.

Windows (namespace "Win32")

ExecProcess(command_string {, timeout_int {, output_string}});

// execute command_string as another process, waiting for timeout_int
// (or 30000 if omitted) milliseconds for completion, and pipes the standard
// output of the process into output_string (if provided).
//
// returned is -1 on timeout or system error, otherwise the process
// result code (returns an int value)

GetJob(queue_string, id_int, data_list);

// gets system information on job id_int in queue queue_string (list)
//
// data_list is a list of int field IDs eg [1]
// returned is a list of [field_int, value_any] pairs
// eg [[1, "PrinterName"]]
//
// Field: Field ID: (type) attributes
//
// JobId 0 (int) read-only
// PrinterName 1 (string) read-only
// MachineName 2 (string) read-only - This gets a value representing the workstation that the print job came from.
// UserName 3 - (string) read-write
// Document 4 - (string) read-write
// NotifyName 5 - (string) read-only - This returns the UserName value.
// Datatype 6 - (string) not supported
// PrintProcessor 7 - (string) not supported
// Parameters 8 - (string) not supported
// DriverName 9 - (string) not supported
// DevMode 10 - not supported
// Status 11 - (string) read-only
// SecurityDescriptor 12 - not supported
// Status (Flags) 13 (int) not supported
// Priority 14 (int) not supported
// Position 15 (int) not supported
// StartTime 16 - not supported
// UntilTime 17 - not supported
// TotalPages 18 (int) read-only
// Size 19 (int) read-only
// Submitted 20 - not supported
// Time 21 - not supported
// PagesPrinted 22 - (returns an int value) read-only

TotalPages and PagesPrinted return the same value, which is the number of pages found by the Page Counter.

As of 8.3, the GetJob function no longer supports retrieving values for Data Type, PrintProcessor, Parameters, DriverName, Priority and Position because it is not applicable to the new Secure Release Service.

GetTempFileName({prefix_string {,pathname_string}});

// Returns a temporary filename prefixed by prefix_string (or prefix "Pha" if omitted)
// and pathname_string (or the system pathname from Win32_GetTempPathName
// if omitted) - NOTE: the script is responsible for deleting this file after use (returns a string value)

GetTempPathName( );

// Returns the pathname of the Windows directory for temporary files (returns a string value)

NetSend(user_string, message_string);

// sends a network message message_string to user user_string (no return value)

RegQueryValue(subkey_string, value_name_string {,key_int {,access_int}})

// Opens registry key subkey_string under root key key_int (or HKEY_LOCAL_MACHINE
// if omitted, which is 1 - see Win32 SDK definition of HKEY_LOCAL_MACHINE
// for other root key values) and with access rights access_int (or KEY_ALL_ACCESS
// if omitted - see Win32 SDK definition for other access rights)
// and returns value of value_name_string if it exists, otherwise
// returns bool false (any)

SearchPath(filename_string);

// Searches for file filename_string and returns its 'short' path, without spaces
// or long filenames (returns a string value)

SetJob(queue_string, id_int, data_list);

// sets system information for job id_int in queue queue_string
// returning true on success and false on failure (returns a bool value)
//
// data_list is a list of [field_int, value_any] pairs
// e.g. [[4, "NewDocumentName"]]
// see GetJob( ) for valid field_int IDs (i.e. not read-only etc)

As of 8.3, the SetJob function can now set the user and job name values. Values not supported by Win32.GetJob(..) cannot be set using Win32.SetJob(..). Win32.SetJob (..) will return an error instead of throwing an exception for an invalid field. This causes the scripts to continue working instead of stopping (due to an exception).

SetJobCommand(queue_string, id_int, command_int);

// Performs operation command_int (e.g. JOB_CONTROL_CANCEL, which is 3 - see
// Win32 SDK for other operation values) on print job id_int in queue queue_string
// and returns true if success, false otherwise (returns a bool value)

Beginning with 8.3, this function will do nothing and always return true.

Sleep(milliseconds_int);

// Forces the script thread to sleep for milliseconds_int
// milliseconds before resuming execution (no return value)

Error Handling

A script can respond to errors at run-time with the try-catch block statement. When an error occurs, or a throw statement is encountered inside a try block, the subsequent catch block is executed. Information about the nature of the error can be obtained by calling the following Script namespace functions in the catch block:

new error_message = Script.GetErrorMessage();

new error_type = Script.GetErrorType();

Script errors occur in several situations:

  • run-time script errors (e.g. use of an undeclared variable) will have type "Script".
  • communications errors (e.g. via the DB or Notify namespaces) will have type "PSCom".
  • internal Pharos errors may have type "PS", "MFC" or "General exception".

Throw statements may provide error information by first calling:

Script.SetErrorMessage("My error message");
Script.SetErrorType("My error type");

Handling of Unicode characters

The script compiler that ships with Uniprint has been updated to support Unicode parameters and return values, as well as Unicode script contents (i.e. string literals, comments and so on).

All the standard scripts have also been updated to support Unicode. You can find these scripts on the Pharos disk image at \tools\plugins\scripts.

Pharos Components Interaction with Scripts

Pharos Database

When a script interacts with the Pharos database, Unicode is fully supported. If a script uses the function DB.ParametrizedSQL, parameters containing Unicode characters are handled correctly. Some existing scripts may contain SQL code that explicitly refers to the SQL type "varchar"; this need to be replaced by "nvarchar" if Unicode support is required.

You will also need to update scripts that query the database to support querying with Unicode values. Any SQL query that might include Unicode strings needs to be updated to include the "N" prefix. The following examples show how to create queries with Unicode values.

Examples:

This query will continue to work as expected:

select * from users where id = 'string'

To support Unicode characters, the prefix "N" should be added before the Unicode string:

select * from users where id = N'string'

Popup Client and Notify

While the scripts support Unicode internally, they sometimes interact with components of the system that do not support Unicode. For example, the Popup Client does not support Unicode characters in a print job's Username or Job Name, whether or not those were entered by the user in response to Popup Questions; in such cases, a script will receive a non-Unicode parameter. Similarly, in practice the functions in the Notify namespace support Unicode only to the extent that Pharos Notify itself does so.

Variable names within the script must contain only ASCII alphanumeric characters.