Table of Contents

JavaScript

Synchronet uses Mozilla's JavaScript engine (a.k.a. JavaScript-C or “SpiderMonkey”) for its preferred local scripting environment.

Versions

About

You can learn about the core JavaScript language and object model from the following documents:

JavaScript is an established, mature scripting language syntactically similar to C++ and Java.

JavaScript is not Java.

The ECMA and ISO standards organizations have standardized the core JavaScript language in ECMA-262 (ECMAScript) and ISO-16262.

Baja and JavaScript

Baja is the original scripting language of Synchronet (introduced in v2.0, 1994), used to create Synchronet-specific modules and command shells. Baja was originally designed as a simple BASIC-like language for controlling the display of menus and command prompts, accepting commands from the user and passing on control to high-level BBS functions. Over the years, Baja has been extended and enhanced to allow a high-level of functionality, but it was never going to reach the power and flexibility of JavaScript.

For example Baja modules and command shells, see the .src files in your Synchronet exec directory.

For the foreseeable future Baja modules and command-shells will continue to be supported in Synchronet, but sysops and developers are encouraged to use JavaScript instead of Baja moving forward. With very few exceptions, everything that can be done in a Baja module can be done in a JavaScript module, and much much more.

Eventually, all the stock command-shells and external modules will be converted to JavaScript.

JavaScript Files

JavaScript files are just ASCII text files. They are normally named with a .js file extension and located in your Synchronet exec directory or with a .ssjs file extension and located in your Synchronet web hierarchy. JavaScript files do not need to be compiled. JavaScript files are loaded into memory at the time of execution, so a change to a JavaScript file will take effect the next time that file is executed (no recycling of servers is normally required).

For example JavaScript modules and services, see the .js files in your Synchronet exec directory.

Modified stock .js files should be placed in your Synchronet mods directory to prevent over-writing by future upgrades.

Invocation

JavaScript files can be executed / invoked from:

as a timed event, external program (door), login/logon/newuser module, via the EXEC sysop command 1)

dynamically generates HTTP responses (e.g. HTML/CSS content), see web/root/*.ssjs

dynamically generates HTML index files, see exec/ftp-html.js and exec/ftp-web-html.js

all services at this time (both static and dynamic) are written in JavaScript, see exec/*service.js and ctrl/services.ini

inbound mail processors may be written in JavaScript, see exec/mailproc_example.js and ctrl/mailproc.ini

some script files may be executed outside of Synchronet (e.g. as a CGI script or daemon) using JSexec, examples: ircd.js, newslink.js

From the Terminal Server, a JavaScript file is executed on a native command-line by placing a question mark (?) or asterisk (*) at the beginning of the command-line before the JavaScript file name (in SCFG). It is not necessary to specify the .js portion of the file name on the command-line. For example, the command-line to execute the file exec/newslink.js would be “?newslink” or “*newslink”.

From within a Baja module, a JavaScript file may be executed using the following Baja code:

exec "?modname" # where modname is the JavaScript filename or base filename.

or:

exec "*modname" # where modname is the JavaScript filename or base filename.

or:

exec_bin "modname" # where modname is the JavaScript filename or base filename.

Object Model

Synchronet has its own constantly evolving JavaScript object model (containing classes, objects, methods, and properties), not to be confused with the Document Object Model (DOM) used in web browsers. In order to fully understand the capabilities of JavaScript modules in Synchronet, you must familiarize yourself with Core JavaScript as well as the Synchronet JavaScript Object Model.

load

The Synchronet JavaScript object model includes a global method: load() (a closely-related require() method was added in v3.17).

The load method is used to compile and execute an external script from within a parent script. It is most often used to load numeric constants and object definitions from files in the exec/load directory as these definitions (e.g. sbbsdefs.js) and object libraries (e.g. graphic.js) enable code re-use and sharing among modules, saving us JS programmers and lot of typing and redundancy.

There are 3 primary ways to use the load method:

1. This example just runs the referenced script name (myscript.js) and passes the argument values (1, 2, 3) to the script, saving the result (the last expression evaluated in myscript.js) in the result variable:

var result = load('myscript.js', 1, 2, 3);

2. This example runs the referenced script in a background/child thread, passing the argument values (1, 2, 3) and saving the bi-directional queue that may be used to communicate with the child thread in the queue variable:

var queue = load(true, 'myscript.js', 1, 2, 3);
var value = queue.read(1000);
writeln(value);

3. This example runs the referenced script in the scope of the specified object (passing no arguments, though that is supported):

var obj = new Object;
load(obj, 'myscript.js');

And a short-hand, preferred, syntax (same result):

var lib = load({}, 'myscript.js');

JavaScript files in the load directory that end in (last line is) a this; statement are intended to be loaded / used in this fashion.

Once a file is loaded in this fashion, any methods, variables, constants or objects defined within may be referenced from the parent script like so:

var lib = load({}, 'mylib.js');
lib.do_thing();
if(lib.status_good == true)
    writeln('good');
else
    alert('bad');

This usage expressly places all items created by the loaded script into the scope of the passed variable (in this case, a newly created empty Object, just for this purpose). This means there should be no naming conflicts between the parent script and the loaded script (e.g. they may have methods or variables defined with the same name and there will be no confrict).

Output

There are many different text output methods supported by the Synchronet JavaScript Object Model and knowing which method (function) to use in what situation can be confusing. The following table should help:

Method BBS2) JSexec Newline Xlat 3) Expands/Decodes Multiple Values4) Notes
write() Yes Yes No Yes Telnet-IAC, Ctrl-A Yes If user not online, same as log(LOG_INFO, ...)
write_raw() Yes No No No Telnet-IAC Yes Value may contain NULs, no charset translation
writeln() Yes Yes Yes Yes Telnet-IAC, Ctrl-A Yes aka print()
printf() Yes Yes No Yes Telnet-IAC, Ctrl-A Yes5) ala C printf()
alert() Yes Yes Yes Yes Telnet-IAC, Ctrl-A No If user not online, same as log(LOG_WARNING, ...)
log() Yes Yes N/A N/A Yes6) Displayed/logged on the server only
console.print() Yes No No Yes Telnet-IAC, Ctrl-A Yes
console.write() Yes No No Yes Telnet-IAC Yes No line-counting/auto-pause
console.writeln() Yes No Yes Yes Telnet-IAC Yes No line-counting/auto-pause
console.putmsg() Yes No No Yes Telnet-IAC, Ctrl-A, @-Codes, Extra Attributes No Typically used for displaying text/menu files
console.center() Yes No Yes Yes Telnet-IAC, Ctrl-A No Text centered on screen
console.mnemonics() Yes No No Yes Telnet-IAC, Ctrl-A, @-Codes, ~ No Hotkey highlights
console.putbyte() Yes No No No Telnet-IAC No No charset translation
client.socket.send() Yes No No No No Avoid using

Carriage Returns

If you wish to send a traditional “carriage return” character to the client terminal (i.e. move the cursor to the far left column without advancing to the next line) it is recommended that you use an output method/function that supports Ctrl-A codes and you send the Ctrl-A [ sequences instead of an ASCII 13 (\r) character. This is required for PETSCII terminal compatibility, where an ASCII 13 character performs a complete “newline” sequence (the equivalent of \r\n) on the client terminal.

Input

Method BBS7) JSexec Notes
read() Yes Yes Read up to maxlen (default 128) characters of input
readln() Yes Yes Read a string (line of input) from user, up to maxlen chars (default: 128)
console.inkey() Yes No Wait for a key-press or an elapsed timeout duration
console.getstr() Yes No Get a string of characters from user
console.getkey() Yes No Get a single key-press
console.getbyte() Yes No Get an unprocessed input byte from remote terminal as a number
console.getnum() Yes No Get a number (between 1 and maxnum) from user
console.getkeys() Yes No Get a key from a list of valid keys, or a number
console.gettemplate() Yes No Get a string conforming to a provided input template

Prompt

Often you'll want your script to prompt the user for some input (e.g. a string of text or a single key). A prompt involves both output (first, from the BBS) and input (from the user):

Method BBS8) JSexec Notes
prompt() Yes Yes
confirm() Yes Yes
deny() Yes Yes
console.yesno() Yes No
console.noyes() Yes No
console.mnemonics() Yes No

See Also

1)
basically anywhere a Baja module or native or MS-DOS executable can be launched
2) , 7) , 8)
Terminal Server
3)
Character set translation
4)
as function arguments
5)
using C printf format syntax
6)
following the log-level argument