Visit the Web Crossing Conference to find a wealth of WebX info and a community of WebX experts on the Web!
Global Functions and Properties
Web Crossing's JavaScript environment is specifically designed to build Web pages. Each request from a Web browser can be served by a combination of HTML text and JavaScript functions.
Special objects are provided to access the incoming request, work with input form variables, and produce a response page. You have total control over the response, including the ability to easily forward to another location, set cookies, and so on.
Web Crossing's JavaScript environment is nicely coupled to its built-in database, giving you access to a user directory and to hierarchical, extensible, object-oriented data items. (If you prefer, you can use external services for persistent storage. You are never required to exclusively use the tools built into Web Crossing.)
Pre-loaded JavaScript functions can be used to process Web-Crossing-specific requests, or to define your own dynamic pages.
A file named webx.tpl is used for pre-loaded JavaScript functions. This file can include any number of function definitions and initialization functions.
The syntax for JavaScript functions in the webx.tpl file is
For example, here is the classic "Hello world" application written in JavaScript for Web Crossing:
(Note that this uses command instead of function, so that this JavaScript function can be used directly to process incoming URLs.) You would get to this function by issuing a URL in your Web browser:
where filename is the file to include. You must use this syntax exactly: spaces, capitalization, and all.
It is often convenient to use separate files for each new JavaScript object or set of related functionality.
Any JavaScript statement that starts with a plus sign (+) is evaluated as an expression and then appended to the response page. That is, the statement
In addition, you can use the \ character to suppress the end-of-line characters, so you can break up long HTML lines into smaller pieces for readability. Leading tabs are stripped from text lines, again so you can write readable HTML. For example, the text
This means that you can use an init_ function to pre-build an object class, adding functions and data constants to the constructor's prototype. For example,
A global propery named libraryGlobal is available to reference the global context that is copied to become the intial global object for each incoming request.
In practice, this means that you can use global variables as desired, and each request will have its own set of gobals.
The following table shows a more detailed outline of variable resolution in Web Crossing, compared to client-side usage.
| Resolution steps | Web Crossing usage (server-side) | Browser usage (client-side) |
|---|---|---|
| First | If the variable is defined in a var statement, it is local to the current execution of the function and is read/write. | Same. |
| Second | Lookup the variable as a property of the current function. | Same. |
| Third | Lookup the variable in the current request's global scope. These variables are read-write. | Lookup the variable in the window in which the function was defined. These variables are read-write. |
With JavaScript functions, you can use the same structure:
Functions grouped in this manner are placed into JavaScript container objects that correspond to the macro grouping. In the example above, the full names of the functions would be
JavaScript and WCTL can both set properties of stored objects, and pass data to each other this way. However, WCTL cannot reference any JavaScript types except strings. In other words, if WCTL accesses a path.var that was stored by a JavaScript "node.var = value;" statement, the WCTL program will get the correct value if it is a string, but will get the empty string as the value for any other JavaScript type.
Run-time errors will return the page to the point of the error, followed by the error message and a stack trace. You sometimes need to do a "View as source" in order to see the error messages.
A JavaScript function must be enabled to respond to incoming URLs.
Each incoming request is run in its own private global context. The global properties are:
| request | top-level object, default scope for variables. For example, "request.certificate" is the same as "certificate" |
| top | during initialization, top is the same as libraryGlobal. During request processing, top is the same as request. |
| response | ByteBuffer accumulating the response page to return to the browser |
| cgi | object with a string property for each CGI variable |
| form | object with a string property for each input-form field |
| user | user for current session |
| location | the Node object specified in the location parameter of the URL, or null if none if none |
| locationArray | array of parents for the location object, with location as the last element. |
| site | current global site settings |
| topLevelFolder | top-level folder for the site |
| session | object with read/write property strings for the current user's persistent session information |
| certificate | certificate string for the current user/session |
| error | some methods indicate errors by setting this error message. It is the error from last such command, or null for no error |
| .../webx...? | directs the URL to the Web Crossing server, however this is configured. |
| functionName | is the name of the JavaScript function or method |
| certificate | is the optional certificate for this session (WCTL automatically keeps track of user and per-session variables, see the following discussion of the "session" object.) |
| location | is an optional location in the WCTL object-oriented database (OODB) |
| formName=value | is an optional list of input fields. Each formName and value must be URL quoted. |
If there is no method or function with the right name, then an error message is displayed.
For example, request.certificate is the same as certificate unless there is a local variable named "certificate".
To add HTML text to the response page, just use
You can also append text to the response by putting a plus sign as the first character of a JavaScript statement, as
To embed URLs for Web Crossing functions, see the built-in command makeUrl.
The final response value will direct Web Crossing to take appropriate action:
| response page | action |
|---|---|
| non-empty response, not starting with HTTP/ | This is a normal HTML page, and Web Crossing will automatically generate the HTTP header for the response. (Responses to a Web browser are an HTTP header, a blank line, then the page itself. So if you provide the page, Web Crossing will provide the HTTP header and blank line.) |
| response starting with HTTP/ |
Whenever a response page evaluates to text starting with HTTP/, that page
is returned as is, without adding the standard HTTP response heading.
For example, the following function forwards the incoming request to
<http://mysite.com/test.html>.
%% function forward {
response.append( "HTTP/1.0 302 Redirect" );
response.crlf();
response.append( "Location: http://mysite.com/test.html" );
response.crlf();
response.crlf();
} %%
This is because HTTP/1.0 302 Redirect has a response code
of 302, which asks the browser to temporarily forward the original URL to
a new location.
Note that the forwarding response must end with a final blank line, because this blank line marks the end of the response HTTP header. The page itself, following this blank line, is empty. |
| empty response page | Web Crossing assumes that the user needs to login before this function can run correctly, and will return a login page. After the user successfully logs in, the current function will be reexecuted with the same input-form values. |
You can enumerate the available properties. For example, the following function will show a list of cgi properties:
%% function showCgi {
for( i in cgi )
response.append( i + ": " + cgi[i] + "<br>" );
} %%
Typical cgi properties and their use are:
| cgi property | use |
|---|---|
| query_string | The query string from the incoming URL, the portion following
the first question mark in the URL.
This string is URL-quoted, so the query string from the request "http://test.webcrossing.com/webx?showCgi@@" becomes a cgi.query_string of "showCgi%40%40". To remove the URL-quoting, use cgi.query_string.fromUrl(). |
| script_name | Incoming request, following the server domain and before any
question mark and query string.
For example, the request "http://test.webcrossing.com/webx?showCgi@@" has a cgi.script_name of "/webx". |
| https | Set to "on" if the request is via a secure SSL connection, otherwise is not defined. |
| http_Referer | The URL of the page that contained the link to the current request |
| http_User_Agent | Type of client browser, such as "Mozilla/4.05 (Macintosh; U; PPC, Nav)" |
| http_Connection | Type of connection, such as "Keep-Alive" |
| http_Host | Domain name or IP address of the host serving this request, such as "www.webcrossing.com" |
| http_Accept | The mime-types that the browser will accept, such as "image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, image/png, */*" |
| http_Accept_Language | Languages that the browser will accept, such as "en" for English |
| http_Accept_Charset | Charsets that the browser will accept, such as "iso-8859-1,*,utf-8" |
| request_method | Request type, "GET" or "POST" |
| remote_addr | IP address of the client Web browser, such as "1.2.3.4". |
| server_name | Domain name or IP address of this server, such as "test.webcrossing.com". |
| url_scheme | If you need to know whether a request came in over a secure SSL connection or not, use cgi.url_scheme. In direct web-service mode, this will be "https" for a secure connection, or "http" for a non-secure connection. For FastCGI mode, this will be set per the originating server, so may be missing or null; instead of url_scheme, Apache servers set https if the request was over an SSL connection. In CGI mode, no information is available. |
For example, if the incoming URL is
http://test.webcrossing.com/webx?showForm@@!test=abc&name2=value2then
form.test == "abc" and form.name2 == "value2"You can enumerate the properties of the form to list all of the input fields.
If the same field is input more than once, form.inputField is the last one. Using the last value allows you to set defaults using hidden fields, as in
<input type=hidden name=myCheckBox value=false> <input type=checkbox name=myCheckBox value=true>This usage will always provide a value for form.myCheckBox. If the checkbox is checked, then both myCheckBox=false and myCheckBox=true will be sent by the browser, which will result in a "true" value from form.myCheckBox. If the checkbox is not checked, then only myCheckBox=false is sent by the browser, which will result in a "false" value from form.myCheckBox.
When a post is done in multipart MIME format, you can access the header component of each value through the Mime.formHeader() function.
| locationArray[0] | Same as topLevelFolder |
| locationArray[...] | Intermediate parents |
| locationArray[locationArray.length-1] | Same as location |
The properties of a session can only have string values. You can enumerate over these properties.
In order for an incoming request to have the same session as an earlier request, the certificate component of the URL must be the same as for the earlier request. This means that you should dynamically generate all session-linked URLs as
...?command@certificate@...
Discussions contain Messages, which are accessible as either a chronological conversation or a hierarchy of threaded messages.
At the lowest level, there are primitive Stored objects. These are the same as a JavaScript Object, except that they are stored into the database.
All objects stored in the OODB can be accessed through JavaScript objects. Setting new property values for stored objects stores the values into the OODB and saves them on disk. Fetching values from stored objects loads them from disk automatically.
You can create your own kinds of objects derived from the built-in classes, giving you an extremely powerful tool for extending and customizing Web Crossing.
For example, suppose you wanted to define an "auction item". You decide to derive this from the built-in Node object, because you want auction items to be listed in a folder. So, just define an AuctionItem constructor and its init logic:
Now new AuctionItem objects can use all of the built-in Node and Stored methods and properties, plus all of the default properties and methods that you assign to AuctionItem.prototype.
When a previously created AuctionItem object is referenced, it is automatically loaded from the OODB as necessary, with the correct class.
You can use the same technique to define your own object classes based on any built-in object class: Stored, Node, Folder, Discussion, Message, Chat, Link, or User.
This is an extremely powerful technique for creating new kinds of objects and extending the Web Crossing environment.
A Stored object can hold any primitive JavaScript data-type: null, strings, numbers, booleans, and Dates, and can also hold other stored objects. (Storing any other kind of object will generate a run-time error.) For example,
This code will create a new Stored object, save the current date/time and a "reminder" from the input form, and save this into the current user's record. All of this information is available later:
By default, all non-built-in property values are automatically stored into the OODB. You can specify that some properties are local (not stored at all) or transactional (stored by storedCommit).
| Properties and methods | Usage |
| Stored.lookup( id ) |
Looks up an existing Stored object and returns it.
id is a string which is either a pathname in the OODB folder hierarchy, or the s.storedUniqueId label for some object. This method will return an object with the same type that it was created with, as long as that type is available in your current JavaScript templates. (If the correct type is not available, then the type will be the underlying type of the original object, such as Folder, Node, Stored, etc.) If the object could not be located in the OODB, then returns null and sets error. |
| Stored.newUnattached() | Returns a new unattached Stored object, suitable for deriving new classes from Stored. |
| storedIsAttached | Returns true if the stored object is attached to the OODB |
| storedUniqueId | Returns the uniqueId string for a stored object. This can be used in a later Stored.lookup( id ). |
| storedDetach() | detaches a JavaScript Stored object from the OODB. |
| storedConstructor | (read-only) the name of the constructor for the class (from the OODB, so if this class does not exist in the current run-time, then the default base constructor was used) |
| storedSetConstructor( newType ) | Changes the type of an object in the OODB. newType is a string that is the name of the constructor function for the new class. Detaches the old object, and returns an object of the new type. |
| storedIsLocal( propName ) | Returns true if propName is for a local property (e.g. not stored into the OODB). |
| storedIsTransact( propName ) | Returns true if propName is for a transaction-type property (e.g. stored into the OODB on command). |
| storedIsAuto( propName ) | Returns true if propName is for an auto-stored property (e.g. stored into the OODB). |
| storedMakeLocal( propName ) | Makes the specified property to be local |
| storedMakeTransact( propName ) | Makes the specified property to be transaction-oriented |
| storedMakeAuto( propName ) | Makes the specified property to be auto-stored |
| storedCommit() | Saves all modified transaction-oriented properties into the OODB |
| storedRollback() | Reverts all transaction-oriented properties to the old value from the OODB |
| storedIsFolder | Returns true if the stored object is also a Folder |
| storedIsDiscussion | Returns true if the stored object is also a Discussion |
| storedIsMessage | Returns true if the stored object is also a Message |
| storedIsNode | Returns true if the stored object is also a Node |
| storedIsChat | Returns true if the stored object is also a Chat |
| storedIsLink | Returns true if the stored object is also a Link |
| storedIsUser | Returns true if the stored object is also a User |
| storedIsStoredArray | Returns true if the stored object is also a StoredArray |
| OTHERS | all other property names are user-defined, and are stored in the Web Crossing database (except when specified as local) |
A StoredArray object is an array of any primitive JavaScript data-type: null, strings, numbers, booleans, and Dates, and can also hold other Stored objects. (Storing any other kind of object into a StoredArray will convert it to a string and store the string.) For example,
This code will create a new StoredArray object, save the current date/time and a "reminder" from the input form, and save this into the current user's record.
You can create Node objects and place them into Folders, and you can derive your own classes from the Node class.
| Properties and methods | Usage |
| |
| new Node( parentFolder, title ) | creates a new node with the specified title. parentFolder can be a Folder object or a pathname string. |
| Node.lookup( pathname ) | Returns the object located by the specified pathname. Same as Stored.lookup( id ). |
| Node.lookupArray( pathname ) | Returns an array of parents of the specified pathname, with the specified item the last one in the array. The first item in the returned array is always the top-level folder. |
| Node.newUnattached() | Returns a new unattached Node object, suitable for use as a prototype in a class definition. |
| |
| nodeAuthor | user who posted this location |
| nodeBackground | background for non-message items (if "", then inherited from its parent) |
| nodeChildren | (not implemented) Array of child nodes |
| nodeDateCreated | date this location was created |
| nodeDateModified | date this location was modified |
| nodeFooter | footer for non-message locations (if "", then inherited from its parent) |
| nodeHeader | banner for non-message locations (if "", then inherited from its parent) |
| nodeName | -- note: rarely used, see nodeTitle, nodePathname, and storedUniqueId -- unique name of an item in its parent Folder. This is the same as the nodeTitle for Folders. nodeName is read-only. Successfully setting nodeTitle for a Folder will also change the Folder's nodeName. The nodeName for a non-Folder object is a string with an integer value (e.g. 0, 1, ...) that is unique in the parent folder. |
| nodeOwnerDocument | Top-level folder node |
| nodeParent | parent Folder or null for the top-level Folder object |
| nodePathname | Full pathname for this node. Each component of the pathname is URL-quoted, separated by "/" delimiters. |
| nodeShowAuthor | true to show the author of this location |
| nodeTemplate | template envelope for this location |
| nodeTitle | title of the item. The title is the same as nodeName for Folders. Because a Folder's title must be unique, setting nodeTitle for a folder may not work. For all other Node objects, setting nodeTitle will always work. |
| nodeUrl | URL for this location, using current session certificate, etc |
| nodeValue | data for folder/discussion heading, or message body |
| OTHERS | all other property names are user-defined, and are stored in the Web Crossing database (except when specified as local) |
| |
| nodeDestroy() | destroys an open folder, discussion, message, chat, link, or container |
| nodeDisplay() | constructs the display page for a node. Only used for actual Node objects and user-defined objects derived from Node. The built-in method just calls this.nodeDisplayHeader, this.nodeDisplayContent, and this.nodeDisplayFooter |
| nodeDisplayHeader() | constructs the header for a display page for a node. Only used for actual Node objects and user-defined objects derived from Node. The built-in method puts up the initial <HTML> tag and heading, a <BODY> tag, and the standard banner for the page, the title and backpath. |
| nodeDisplayContent() | constructs the content area for a display page for a node. Only used for actual Node objects and user-defined objects derived from Node. The built-in method doesn't display anything. |
| nodeDisplayFooter( showToolbar ) | constructs the footer for a display page for a node. Only
used for actual Node objects and user-defined objects derived from Node.
The built-in method displays <p> followed by the standard footing and closing BODY and
HTML tags.
showToolbar is optional and defaults to true. If set to false, then the default toolbar is not added by nodeDisplayFooter. |
| nodeIcon( extra ) | <img...> tag for the default icon for
this location. An optional parameter can be specified which is
additional stuff to add to the |
| |
| nodeMoveTo( toFolder ) | moves any non-Message object to a new Folder. Returns null if no error, or an error message string. |
| nodeInsertBefore( newChild, refSibling ) | (not implemented) |
| nodeReplaceChild( newChild, oldChild ) | (not implemented) |
| nodeRemoveChild( child ) | (not implemented) |
| nodeAppendChild( newChild ) | (not implemented) |
| nodeHasChildren() | (not implemented) |
| nodeFirstChild() | (not implemented) |
| nodeLastChild() | (not implemented) |
| nodePreviousSibling() | (not implemented) |
| nodeNextSibling() | (not implemented) |
| nodeAddAttachment( a ) |
Add an attachment to a node object.
The attachment must be formatted as MIME container, using CRLF line delimiters.
It starts with a partial heading that must Content-Type and Content-Transfer-Encoding,
and may include other header lines.
The heading is followed by a blank line, followed by the data. For example, the following is a short text file attachement:
|
| |
| nodeHasAccessList | returns true if the node has its own access list. Set this property to true to create an access list if there isn't one already, or to false to remove any existing access list. |
| nodeUserAccess( user ) | returns the user access to a node. The returned access is "host", "participant", "moderated", "readOnly", or "none". If the node does not have its own access list, then the parent's access list is used. |
| nodeSetUserAccess( user, mode ) | sets the user access to a node. The access mode can be "host", "participant", "moderated", "readOnly", or "none". If the node does not have its own access list, one is added automatically. |
| nodeUserCanView( user ) | returns true if the user can view this location. |
| nodeUserCanPost( user ) | returns true if the user can post to this location (this will return true even if the user posts are moderated). |
| nodeUserIsModerated( user ) | returns true if the user posts are moderated at this location. |
| nodeUserIsHost( user ) | returns true if the user is a host for this location. |
| Properties and methods | Usage |
| new Folder( parentFolder, title ) | creates a new folder with the specified title. parentFolder can be a Folder object or a pathname string. |
| folderChild( ix ) | returns folder nested objects by index (ix is [0..folderChildCount-1]). Returns null if there is no such child or ix is >= folderChildCount. |
| folderChildCount | the number of children in the folder (read only) |
| folderNewsgroup | newgroup name, also used as email username for email posts |
| Properties and methods | Usage |
| new Discussion( parentFolder, title ) | creates a new discussion |
| discussionChildCount | the number of message slots in the discussion, including any deleted or moved messages (read only) |
| discussionChild( ix ) | returns nested messages by index (ix is [0..discussionChildCount-1]). Returns null if there is no such child or ix is >= discussionChildCount. |
| messageIx | always returns -1 for a discussion (read only) |
| treeIx | always returns -1 for a discussion (read only) |
| treeChildCount | the number of messages in the discussion, not counting deleted or moved messages (read only) |
| treeChild( treeIx ) | returns nested messages in threaded-message order by index (ix is [0..treeChildCount-1]). Returns null if there is no such child or ix is >= treeChildCount. |
| treeParentIx | always returns -1 for a discussion (read only) |
| treeNextSibIx | always returns -1 for a discussion (read only) |
| treePrevSibIx | always returns -1 for a discussion (read only) |
| treeDepth | always returns -1 for a discussion (read only) |
| Properties and methods | Usage |
| new Message( parentDiscussion[, title] ) | appends a new message to parentDiscussion |
| new Message( parentMessage[, title] ) | makes a new hierarchical message under parentMessage |
| messageIx | returns the message index in conversational order, 0 origin (read only) |
| treeIx | the message index in threaded-message order, 0 origin (read only) |
| treeChildCount | the total number of nested messages in threaded-message order, not including any deleted or moved messages (read only) |
| treeChild( treeIx ) | returns nested messages in threaded-message order by tree-index in the discussion (ix is [0..discussion.treeChildCount-1]). Returns null if there is no such child or ix is >= discussion.treeChildCount. |
| treeParentIx | the tree-index of the parent message in threaded-message order, 0 origin (read only) |
| treeNextSibIx | the tree-index of the next sibling in threaded-message order, 0 origin, or -1 if no next sibling (read only) |
| treePrevSibIx | the tree-index of the previous sibling in threaded-message order, 0 origin, or -1 if no next sibling (read only) |
| treeDepth | the nesting depth of this message in threaded-message order, 0 for top-level messages (read only) |
| messageExists | tells whether a message exists or not (deleted or moved message return false). Setting this property to false will delete a message. Once deleted, the message cannot be "undeleted". |
| Properties and methods | Usage |
| new Message( parentDiscussion[, title] ) | appends a new message to parentDiscussion |
| new Message( parentMessage[, title] ) | makes a new hierarchical message under parentMessage |
| Properties and methods | Usage |
| new Chat( parentFolder, title ) | creates a new chat room |
| chatIsAnonymous | true if the chat room allows anonymous users |
| chatTables | list of tables in a room (includes self) |
| Properties and methods | Usage |
| new Link( parentFolder, title ) | creates a new link |
| linkShowDescription | true if the link description (nodeValue) is show in the folder listing |
| linkUrl | location in the current site or URL to another site |
| Properties and methods | Usage |
| new User( name ) | creates a new user with the specified name.
If there is an error, null is returned, and error is set to an error message. |
| User.setUser( user ) | Changes the current logged-in user as specified. Also installs a new certificate for the user, or switches to the previously assigned one if present and current. Sets error to indicate results of the switch. |
| User.open( userId ) | Returns the User object for the user with the specified id.
Opens the user from either its u.userId string, which is the same as a WCTL user-id, or from its u.storedUniqueId string. If there is an error, null is returned, and error is set to the error message. Note that the WCTL/u.userId userId values are different from the u.storedUniqueId strings. |
| User.lookup( username ) | Returns the User object for the user with the specified name.
If there is an error, null is returned, and error is set to the error message. |
| User.loggedIn( only, exclude, sort, max, getRemoteAddr ) |
Get information about currently logged-in usrs.
Returns an object containing a property "users". This property is an
array object that is a list of logged in User objects.
only : an optional user, or an array of users, or a string of userIds,
that are the only ones to return. Default is all logged in users.
|
| User.guest | Returns the user ID for a guest user. You can use this ID for setting and checking user access to a particular location. |
| User.other | Returns the user ID for "other registered users". You can use this ID for setting and checking user access to a particular location. |
| storedXxx | all of the Stored properties and methods are available for User objects |
| user2ndLine | second line of info |
| userApop | user APOP password (stored as clear text) |
| userAuthenticate( passwd ) | returns true if passwd is the correct clear-text password for a user |
| userBio | user bio |
| userEmail | email address for user |
| userEmailCode | email code for user validation |
| userForwardTo | email address to foward mail to, or "" for no forwarding |
| userHomepage | user's home page URL |
| userIsRegistered | (read-only) true if the user is registered (i.e. is not a special user ID such as User.other, and is not a guest user) |
| userIsSysop | (read-only) true if the user has sysop priviledges |
| userName | user's name, as First Last |
| userPassword | user's password. Set in clear text, read as MD5 hash |
| userId | unique WCTL user-id string to use in a WebX URL or as a parameter to User.openWctl. (This is because the original WCTL unique-id-space for users is different than the Stored.storedUniqueId. So Stored.lookup( user.storedUniqueId ) will return the user object, just as User.openWctl( user.userId ) will return the same user. But user.storedUniqueId is not the same as user.userId.) |
| userDestroy() | destroys the user, removing it from the member directory and all user groups. Existing messages created by this user will still reference the deleted user record. |
| OTHERS | all other property names are user-defined, and are stored in the Web Crossing database (except when specified as local) |
| Properties and methods | Usage |
| siteImages | base URL for image graphics, such as "http://your.site/Images". Does not include a final slash (/). |
| sitePictSizeButton | width and height for standard-sized buttons, such as "WIDTH=68 HEIGHT=30" |
| siteUsePop3 | true if POP3 service is enabled |
| siteUrlBase | URL base for Web Crossing commands |
| OTHERS | all other property names are user-defined, and are stored in the Web Crossing database (except when specified as local) |
| Global Functions and Properties | Usage | ||||||
| libraryGlobal | this is the "library" object copied to become the initial global object for each request. | ||||||
| top | during initialization, top is the same as libraryGlobal. During request processing, top is the same as request. | ||||||
| wctlVar( varname ) | returns a WCTL variable value, either as a string or an integer depending on the type of the variable. For example, wctlVar( "myVar" ). | ||||||
| setWctlVar( varname, value ) | set a WCTL variable. If the value is an integer-valued number, then the WCTL variable is set to an integer, otherwise it is set to a string. For example, setWctlVar( "myVar", 100 ). | ||||||
| makeUrl( command, parameter ) |
returns a Web Crossing URL for command. This command is a shorthand for
| ||||||
| email( rcptList, message, return ) |
sends an email message to a recipients list.
Note that the email sent does not go though the EmailHandler filters; if this email is for a local user, it will be delivered regardless of any EmailHandlers. rcptList is a list of <username@domain>,.... message is a fully-composed email message with a header, body, and CR-LF linebreaks. The To header in the message is totally independent of the rcptList of destinations -- To: can be anything, it is not actually used to deliver the message. return is the email return address, the address that undeliverable mail is sent to (the MAIL FROM: SMTP parameter). If this is not specified, then it is taken from the message From: header field. Messages must have a return address; if you don't specify it in the email call, and there is no From: field in the message header, then the email will not be sent. Specifying the return address allows you to use Email functions to automate handing of bounced messages. | ||||||
| EmailHandler |
Allows SSJS functions to handle incoming email. SSJS functions are email-enabled by storing them into the global EmailHandler object. For example,
EmailHandler.support = MySupportEmailHandler;
// Handles all email sent to "support" and "support.xxxx"
Basically, you can attach a SSJS function to an email address prefix, so that incoming email with a matching address is handled by calling this function. For example, you could email-enable a function named "support" and have all incoming email addressed to "support" or "support.otherstuff" be processed by your email handler.
Mail is delivered in the following manner:
(1) Incoming email is first handled by checking for an email filter. The EmailHandler properties are checked for an all-lower-case property matching the incoming name. The longest match up to but not including a period in the incoming name is used. Note that you have to use EmailHandler["support.abc"] = function; // Due to period in mailbox nameFor example: incoming matches
--------- -----------------
Support@ support (but not supportx or support_abc)
support.abc@ support or support.abc (but not support.abcd)
If both support and support.abc are present, it
matches support.abc
(2)If there is an EmailHandler.All, this function is called unconditionally to handle all other email. (3) The user database is checked. If there is a match, then that user receives the mail. (4) If there is an EmailHandler.Unknown property (with upper-case "U"), then it is used to process the mail. (5) Otherwise, the mail is rejected as being undeliverable. Email handler functions An email handler is called as
| ||||||
| fileAppend( filename, data ) | appends data to a file. If the file does not exist it is created. | ||||||
| queueWctl( macro, msecs-or-date, param0, param1, user ) |
queues a WCTL macro for later execution.
Returns a string ID for this queued entry, that can be used
to kill the queued function.
For example,
macro is the name of a WCTL macro. msecs-or-date is either a delay in milliseconds or an absolute Date() object that specifies when to run the queued macro. If ommitted, the queued macro is run as soon as possible. Note that the millisecond delays are not extremely accurate, so it is a good idea to delay for shorter periods, perhaps every hour, then delay one last time for the remaining period (less than 60 minutes) before an event trigger, or to use an exact Date() specification. param0, param1 are optional parameters. These values are converted to strings and are available as queueWctlParam( 0 ) and queueWctlParam( 1 ). user if specified, the queued macro will be run for this user. Otherwise, the queued function will be run with no user installed. You can call a JavaScript function from WCTL. For example,
| ||||||
| queueWctlParam( ix ) | returns queued function parameter strings, 0/1 for param0/param1. | ||||||
| queueWctlKill( ID ) | kills the queued function, no effect if this function is no longer queued (either because it has run or has been killed previously). | ||||||
| wctlEval( str ) | returns result of evaluating "str" as an expression in WCTL | ||||||
| wctlEvalTemplate( str ) | returns result of evaluating "str" as a template in WCTL | ||||||
| allowDeny( ip, allowDenySpec, maxMsecs ) | returns boolean,
true if the ip is allowed.
ip may be either a domain name or an absolute IP in dotted format, such as 123.4.5.6. Note that actual IP addresses are used, so if the incoming domain name cannot be resolved, this function will return false even though the input domain-name-string would appear to match the allowDeny spec. allowDenySpec is a list of patterns separated by commas or white space. Each entry in the list has the format a=allowPattern -or- d=denyPatternwhere pattern is an IP address with optional "*" wildcards. For example, "a=*" will allow all IP addresses; "d=*" will deny all addresses, and "a=127.22.33.*" will allow all address with the specified first three bytes. The allow-deny list is processed in order, attempting to match the calling IP address. The first entry matching the calling IP is used to either accept or deny the connection. Denied connections are shut down without any notice. If the last entry in the allow-deny list is an allow, then there is an implicit d=* added to the end; if the last entry is a deny, then there is an implicit a=* added. If the list is empty, it is the same as "a=*" If any allow-deny entries include alphabetic characters, and the reverse-DNS lookup of the IP address is available, then the reverse-DNS will be checked against the patterns as well. maxMsecs is the maximum time to delay while doing domain-name and/or reverse-domain-name lookups, it defaults to 2 seconds. |
There are also some extensions to standard JavaScript objects to assist with server-side operations.
A ByteBuffer is used for the output response buffer, but these objects can also be created and used for other purposes.
| Properties and methods | Usage |
|---|---|
| |
| new ByteBuffer() | Creates a new empty ByteBuffer |
| new ByteBuffer( initialValue ) | Creates a new ByteBuffer whose initial value is as specified. |
| |
| length | (read/write) the current length of the ByteBuffer |
| |
| eqNc( obj ) | returns true if the obj string of ByteBuffer is equal |
| ltNc( obj ) | returns true if the obj string of ByteBuffer is less-than obj |
| leNc( obj ) | returns true if the obj string of ByteBuffer is less-than-or-equal obj |
| gtNc( obj ) | returns true if the obj string of ByteBuffer is greater-than obj |
| geNc( obj ) | returns true if the obj string of ByteBuffer is greater-than-or-equal obj |
| neNc( obj ) | returns true if the obj string of ByteBuffer is not-equal obj |
| |
| eq( obj ) | returns true if the obj string of ByteBuffer is equal |
| lt( obj ) | returns true if the obj string of ByteBuffer is less-than obj |
| le( obj ) | returns true if the obj string of ByteBuffer is less-than-or-equal obj |
| gt( obj ) | returns true if the obj string of ByteBuffer is greater-than obj |
| ge( obj ) | returns true if the obj string of ByteBuffer is greater-than-or-equal obj |
| ne( obj ) | returns true if the obj string of ByteBuffer is not-equal obj |
| |
| byteAt( ix ) | number |
| charAt( ix ) | string |
| substring( ix [, count] ) | string |
| subString( ix [, count] ) | same as substring |
| subBuffer( ix [, count] ) | ByteBuffer |
| duplicate() | returns a copy of the ByteBuffer |
| |
| newValue( obj ) | sets the ByteBuffer to a new value, and returns the modified ByteBuffer |
| append( obj ) | appends a string to the ByteBuffer, and returns the modified ByteBuffer |
| appendByte( number ) | appends a character where "number" is the numeric value of the character, and returns the modified ByteBuffer |
| set( ix, obj ) | sets the character at "ix", and returns the modified ByteBuffer. Uses first character of obj.toString(), or is a no-op if obj is a 0-length string |
| setByte( ix, number ) | sets the character at "ix" where "number" is the numeric value of the character to store, and returns the modified ByteBuffer |
| insert( ix, obj ) | inserts obj.toString() at "ix", sliding the character at "ix" and all following characters down to make room, and returns the modified ByteBuffer |
| insertByte( ix, number ) | insterts a single character at "ix", and returns the modified ByteBuffer, slides down following bytes |
| remove( ix [, count] ) | removes characters from ix through ix+count-1, and slides the following characters up. Returns the modified ByteBuffer |
| head( [delimiter] ) | returns ByteBuffer to left of delim (default is space), removes the head and delimiter from the buffer |
| tail( [delimiter] ) | returns ByteBuffer to right of delim (default is space), removes the tail and delimiter from the buffer |
| toLowerCase() | converts ByteBuffer to all lower-case, returns the modified buffer |
| toUpperCase() | converts ByteBuffeer to all upper-case, returns the modified buffer |
| translate( mapByteBuffer ) | remaps ByteBuffer, each char in ByteBuffer is replaced by mapByteBuffer( byteAt[ix] ) |
| none() | returns NULL (used to have a series of appends, etc evalutate to NULL |
| |
| toUrl() | converts the ByteBuffer to be URL-quoted and returns the modified buffer |
| fromUrl() | converts the ByteBuffer to be URL-dequoted and returns the modified buffer |
| toSgml() | converts the ByteBuffer to be SGML-quoted and returns the modified buffer |
| fromUrl() | converts the ByteBuffer to be SGML-dequoted and returns the modified buffer |
| |
| toMD5() | calculates the MD5 hash of the ByteBuffer and returns the modified buffer |
| |
| crlf() | append carriage return, line-freed characters (CR/LF are the standard Internet end-of-line) |
| cr() | append a CR character |
| lf() | append a LF |
| |
| indexOfNc( obj [, ix [, count]] ) | not case sensitive, returns start index or -1 |
| indexOf( obj [, ix [, count]] ) | case sensitive, returns start index or -1 |
| lastIndexOfNc( obj[, ix [, count]] ) | not case sensitive, returns last start index or -1 |
| lastIndexOf( obj[, ix [, count]] ) | case sensitive, returns last start index or -1 |
| Properties and methods | Usage |
| format( formatSpec ) | formats the JS Date per a WCTL time/date format string (as local time). See below for formatSpec syntax. |
| formatUtc( formatSpec ) | same as format() except as UTC/GMT |
For example,
The date "formatSpec" is as follows. (Characters which are not format specifiers are copied into the output as literals.)
| Format specifier | Usage |
|---|---|
| Y2 | 2 character year |
| Y4 | 4 character year |
| M1 | 1 or 2 digit month |
| M2 | 2 digit month |
| M3 | 2 digit month, leading blank instead of 0 |
| MMM | 3 character month, all caps |
| Mmm | 3 character month, leading cap |
| M | full month name, leading cap |
| D1 | 1 or 2 digit day of month |
| D2 | 2 digit day of month |
| D3 | 1st, 2nd, 3rd, 4th... |
| D4 | 2 digit day of month, leading blank instead of 0 |
| WWW | 3 character day of week, all caps |
| Www | 3 character day of week, leading cap |
| W | full day of week, leading cap |
| H1 | 1 or 2 digit hour, 12 hour clock |
| H2 | 2 digit hour, 12 hour clock |
| H3 | 1 or 2 digit hour, 24 hour clock |
| H4 | 2 digit hour, 24 hour clock |
| H5 | 2 digit hour, 24 hour clock, leading blank instead of 0 |
| I1 | 1 or 2 digit minutes |
| I2 | 2 digit minutes |
| S1 | 1 or 2 digit seconds |
| S2 | 2 digit seconds |
| L1 | 1, 2, or 3 digit milliseconds |
| L2 | 3 digit milliseconds |
| A | AM/PM, upper case |
| a | am/pm, lower case |
| toutc | delta from local time to GMT/UTC, as +HHMM or -HHMM |
| $c | escape to embed any character "c" into the output string |
| Properties and methods | Usage |
| toSgml() | returns string converted to SGML quotes |
| fromSgml() | returns string converted from SGML quotes |
| toUrl() | returns string converted to URL quotes |
| fromUrl() | returns string converted from URL quotes |
| Mime.formHeader( "name" ) | returns the header for a form variable from a POST in multi-part MIME format, the same as the WCTL function formHeader. If the post was not in MIME format, or there is no form variable by this name, then returns null. |
| Mime.getHeader( string ) | returns the header portion of a message in a MIME envelope (e.g. from a header, blank line, and body envelope) |
| Mime.getBody( string ) | returns the body portion of a message in a MIME envelope |
| Mime.unpackBody( string, boundary ) | unpacks a multi-part MIME body into an array of objects. The [0] element of the array is the data before the first boundary. |
| Mime.getHeaderValue( string, name ) | Gets the value of a single header keyword |
| Mime.unpackHeader( string ) | unpackes a MIME header, and returns an object with one property for each header keyword:value pair; the keyword is converted to lower case, and its value is the unfolded value from the header. Also, minus and underscore in the header names are exchanged, so that "Content-Type: text/html" becomes "content_type" with a value of "text/html". |
| Mime.unpackValue( string ) | unpacks a MIME value (from a keyword:value header entry), and returns an object with one property for each value attribute. Attribute names are converted to lower case. The main value is stored into a property named "Value", with an upper-case "V". Also, minus and underscore in attribute names are exchanged, so that "x-application=abc" becomes the property name "x_application" with a value of "abc". |
| Mime.packValue( obj ) | packs a header value-object back up. |
| Mime.packHeader( obj ) | packs a header-object back up |
| Mime.makeBoundary( obj ) | returns a unique boundary string for the body parts in the input array object |
| Mime.packBody( obj, boundary ) | packs a multi-part MIME body back up from an array of part-messages and a boundary string |
| Mime.packMessage( header, body ) | packs a header and body into a message |
Note: in order to support XML-RPC, Web Crossing must be providing direct Web service. You can not pass XML-RPC calls through CGI or FastCGI interfaces.
Remote procedure calls (RPCs) allow client programs to make calls to your Web Crossing server, with your server using the appropriate JavaScript functions to process these calls.
You can also make remote procedure calls from Web Crossing's server-side JavaScript to any RPC-based server.
This remote-procedure-call mechanism uses normal HTTP requests and responses, with special XML-based formatting of the body of the message to pass parameters and receive the returned value. All of the XML-RPC machinery is handled by Web Crossing, so you don't need to know the format of these calls to use it in Web Crossing.
where:
| url | is the URL of the server that is going to process the procedure call.
This can be a server address only (e.g. webcrossing.com), or it can be a full URL,
including the remote pathname (e.g. http://webcrossing.com/RPC2).
If the remote pathname is omitted, then /RPC2 is used, so specifying just a server address is the same as http://serveraddress/RPC2. To use SSL for the RCP connection, you must be running an SSL-enabled Web Crossing server, and specify https in the URL. For example, https://webcrossing.com/RPC2 would use HTTPS instead of HTTP. The default port for HTTPS is 443 and the default port for HTTP is 80. |
| function | is the name of the remote function, such as mainResponder.discuss.newMessage. |
| p1, p2... | are optional parameters. Primitive values (strings, numbers, Dates) are passed exactly, except that
null is passed as an empty string. ByteBuffers are passed as strings. Arrays are passed
as arrays of values.
All other objects are passed as primitive Objects, with all their enumerable properties passed to the remote procedure. |
| returns | the object passed back from the remote procedure.
Returned values use the same rules as for sending parameters to the remote procedure.
So returned values can be primitive values, or can be JavaScript Arrays or Objects.
Any error in the call, or in the remote processing, will return a Fault object. This object has properties faultCode, a numeric error code, and faultString, a descriptive error message. |
To enable a function for RPC processing, just set
The rpcEnable property can be either a boolean or a function. If this property is a function, then this rpcEnable function is called prior to executing the XML-RPC function, with the first parameter the function name and the following parameters the same as the XML-RPC function. The rpcEnable function can return one of the following:
| true | then the normal XML-RPC processing is done |
| false | a "not enabled" fault is returned |
| other | returned to the caller instead of calling the normal XML-RPC function (e.g. "short-circuits" the normal XML-RPC call) |
You can return a Fault object if you detect some error in the request or during processing. To return a fault, just use
where errCode is a numeric error code (there is no standard, you just make them up for your usage), and errMsg is a descriptive error message.
To invoke the test function, copy this to your standard.tpl file, reset the webx.tpl cache, and use the URL