Chapter 7—OW3 Worker Objects

You can build "low-level" Web- and Email-based communications into your Omnis applications using a number of different techniques or commands: this includes support for HTTP, SMTP, POP3, IMAP, and FTP communications and protocols; with the addition of JavaScript (Node.js), CRYPTO, HASH, and OAUTH2 in Studio 10, and LDAP and Python in Studio 11.

IMPORTANT: We recommend you use the OW3 Worker Objects (OW3) for all new development, since the older Web Worker Objects (OWEB) and the External commands are no longer supported.

The technique you choose to implement such support will depend on the breadth of support you require and the version of Omnis Studio you are using. The following techniques are available:

External package Supported protocol Omnis Studio version Implementation
OW3 Worker Objects (OW3) HTTP, SMTP, FTP & SFTP, IMAP, JavaScript (Node.js), POP3, CRYPTO, HASH(1)
OAUTH2(2)
LDAP, Python(3)
(1) Studio 10
(2) Studio 10.2
(3) Studio 11
Objvar.$method
OW3 Worker Objects (OW3) HTTP, SMTP, FTP & SFTP, IMAP, JavaScript (Node.js), POP3, CRYPTO, HASH(1)
OAUTH2(2)
LDAP, Python(3)
Java(4)
(1) Studio 10
(2) Studio 10.2
(3) Studio 11
(4) Studio 11 rev 36370
Objvar.$method
OW3 Worker Objects (OW3) HTTP, SMTP, FTP (not secure), IMAP Studio 8.1 Objvar.$method
Web Worker Objects (OWEB) HTTP, SMTP Studio 6.1.2 Objvar.$method
External Commands
(Note these are obsolete in Studio 10 or above and are no longer available)
HTTP, FTP, SMTP, POP3, and IMAP Studio 1.x (previously called Web Enabler in Omnis 7) External Commands group; name prefixed with protocol name, e.g. HTTPGet

Example Apps

There is an example app for most of the OW3 Worker Objects available in the Samples group under the Hub in the Studio Browser to demonstrate the use of the OW3 Worker Objects; search for "worker" in the search box (in the window title bar/toolbar) under Samples in the Studio Browser. There are examples for: Crypto, FTP, Hash, HTTP, IMAP, POP3, SMTP, JS Worker, and LDAP.

Using the OW3 Workers

Using the OW3 Worker Objects you can execute a potentially long-running task on a background thread, such as running a large mailshot, that reports back to the main thread when the task is complete. Indeed, the OW3 workers allow you to execute multiple tasks simultaneously allowing you to increase the efficiency and workload of your app.

The OW3 worker objects use the open-source CURL library, and native secure connection implementations for Windows and macOS, so they should have fewer deployment issues than the implementations available in previous versions.

The web and email commands in any of the OW3 Workers are accessed via one of the Worker Objects available under the OW3 Worker Objects group in the Object Selection dialog in the Method Editor (do not use the Web Worker Objects group which contains the old OWEB worker objects). To use the web and email commands, you need to create an Object variable and set its subtype to one of the OW3 worker objects, such as HTTPClientWorker or FTPClientWorker, under the OW3 Worker Objects group. Alternatively, you can create an Object class and set its superclass to one of the OW3 worker objects, then create an Object variable or Object reference variable and set its subtype to the object class name. Having created the variable you can call the web or email commands (methods) using OBJECTVAR.$methodname.

All OW3 Worker Objects share the same base functionality, plus they have additional functions specific to their respective web or email protocol.

HTTP/2 support

From Studio 11, the OW3 Workers support HTTP/2 which is more secure than HTTP as it uses binary protocols instead of plaintext, and is generally faster and more efficient for web communication.

The nghttp2 open source library is included to accommodate HTTP/2 support, and various libraries have been updated including: zlib, mbedTLS, libssh2, and libcurl; if your application uses OW3 your product licensing should include the appropriate third-party licensing.

Base Worker Properties

All OW3 worker objects have the following properties:

Property Description
$callprogress If true, and the worker is invoked to execute asynchronously using $start, the worker periodically generates a notification to $progress as it executes. Must be set before calling $start.
The $progress method is described in the Methods section below.
$curloptions Use this property to set internal CURL options not otherwise exposed by the worker. A two-column list, where column 1 is a number (the CURL easy option number) and column 2 is a string. The internal option must use either an integer or string value.
Normally, you would not use this property, but if you do use it, you will need to consult the libcurl header files and documentation to obtain easy option numbers and values. You should use this option with care, as there is a chance you could cause Omnis to crash by passing an incorrect option value.
$errorcode Error code associated with the last action (zero means no error)
$errortext Error text associated with the last action (empty means no error)
$protocollog If non-zero, the worker adds a log of protocol activity as a column named log to its wResults row. The desired value must be set before calling $run or $start. Defaults to kOW3logNone. Otherwise, a sum of kOW3log... constants; see below
$state A kWorkerState... constant that indicates the current state of the worker object, one of the following: kWorkerStateClear, kWorkerStateInit, kWorkerStateCancelled, kWorkerStateRunning, kWorkerStateComplete
$threadcount The number of active background threads for all instances of this type of worker object. In this case, type means the type of the subclass of the common base class e.g. HTTP
$timeout The timeout (in seconds) for requests. Zero means requests do not time out. The desired value must be set before calling $run or $start. Defaults to 10

Request Completion

The $alwaysfinish property allows asynchronous requests to continue to completion after the instance containing the OW3 object destructs; the property only applies to the HTTP, IMAP, SMTP, POP3 and FTP workers.

When the instance containing an OW3 worker closes, and the OW3 worker is executing via a call to $start(), the worker thread continues executing until completion in the background: in this case, no notifications will be generated, as there is not a suitable instance to receive them.

Note that even if $alwaysfinish is true, if you shut down Omnis before the request has completed, OW3 will cancel the request so that shutdown works correctly.

Base Worker Constants

Protocol Logging

OW3 worker objects can all use these constants to control protocol logging. Sum the constants to select the desired logging.

Constant Description
kOW3logNone No protocol logging occurs. Obviously, this value needs to be used on its own
kOW3logBasic Basic protocol information such as headers is logged
kOW3logData Application data sent or received is logged up to a maximum of 16k for each direction. If the data is not consistent with UTF-8 encoding, it is logged as a binary dump format rather than character
kOW3logSecureData Secure connection data is logged
kOW3logHTML The content of the generated log is HTML rather than plain text. This can be written to a file and displayed using OBROWSER on Windows and macOS platforms

Base Worker Methods

All OW3 worker objects have the methods described in this section. There are normal methods that you call, and callback methods that you override to receive a notification.

Normal methods

$run

The $run method runs the worker on the main thread. Returns true if the worker executed successfully. The callback $completed will be called with the results of the request.

$start

The $start method runs the worker on a background thread; can be called multiple times to run different threads simultaneously to perform different tasks at the same time. Returns true if the worker was successfully started. The callback $completed will be called with the results of the request, or alternatively $cancelled will be called if the request is cancelled.

$cancel

The $cancel method cancels execution of worker on a background thread. Will not return until the request has been cancelled.

$getsecureoptions

The $getsecureoptions method gets the options that affect how secure connections are established.

OW3.$getsecureoptions([&bVerifyPeer,&bVerifyHost,&cCertFile,&cPrivKeyFile,&cPrivKeyPassword])

Returns Boolean true for success, or returns false and sets $errorcode and $errortext if an error occurs.

The parameters are:

Parameter Description
bVerifyPeer If true, the worker verifies the server certificate. The default is true, and this results in greater security
bVerifyHost If true, the worker verifies that the server certificate is for the server it is known as. The default is true, and this results in greater security
cCertFile For macOS, the pathname of the .p12 file containing the client certificate and private key, or its keychain name.
For other platforms, the pathname of the client certificate .pem file. Empty if a client certificate is not required
cPrivKeyFile Ignored on macOS.
For other platforms, the pathname of the private key .pem file. Empty if a client certificate is not required
cPrivKeyPassword The private key password. Empty if a client certificate is not required

$setsecureoptions

The $setsecureoptions method sets the options that affect how secure connections are established (call $setsecureoptions before calling $run or $start).

OW3.$setsecureoptions([bVerifyPeer=kTrue,bVerifyHost=kTrue,cCertFile='',cPrivKeyFile='',cPrivKeyPassword=''])

Returns Boolean true for success, or returns false and sets $errorcode and $errortext if an error occurs.

The parameters are:

Parameter Description
bVerifyPeer If true, the worker verifies the server certificate. The default is true, and this results in greater security
bVerifyHost If true, the worker verifies that the server certificate is for the server it is known as. The default is true, and this results in greater security
cCertFile For macOS, the pathname of the .p12 file containing the client certificate and private key, or its keychain name. For other platforms, the pathname of the client certificate .pem file. Empty if a client certificate is not required
cPrivKeyFile Ignored on macOS. For other platforms, the pathname of the private key .pem file.Empty if a client certificate is not required
cPrivKeyPassword The private key password. Empty if a client certificate is not required

$parserfc3339

The $parserfc3339() static method returns an Omnis date-time value from a RFC3339 formatted time.

OW3.$parserfc3339(cRfc3339[,bUTC=kTrue,&iOffset,&cErrorText])

Parses a date and time value conforming to RFC3339 and returns an Omnis date-time value and optionally the time zone offset in minutes.
Returns #NULL if the string cannot be parsed.

The parameters are:

Parameter Description
cRfc3339 a date and time string conforming to RFC3339
bUTC If true, the returned date-time value is in UTC rather than the local time zone of the RFC3339 date-time value
iOffset If the RFC3339 date and time string is parsed successfully this receives the time zone offset in minutes
cErrorText If supplied, receives text describing the error that caused $parserfc3339 to return #NULL

$splitmultipart

The $splitmultipart allows you to split multipart content of a rest call, plus the MIME list returned by the OW3 methods that contain body part headers.

OW3.$splitmultipart(cContentType, xContent, &lMIMEList [,iDefCharSet=kUniTypeUTF8, &cErrorText])

Splits MIME-encoded multi-part xContent into lMIMEList.cContentType must include a boundary parameter. Returns true if successful. The parameters are:

Parameter Description
cContentType The content type header (must contain a boundary parameter)
xContent The binary content to split
lMIMEList Receives the MIME list created by splitting the MIME content. See the documentation for the MailSplit command to see how a MIME list is structured; however note that the charset in the OW3 MIME list is a kUniType... constant
iDefCharSet The default character set used to convert character data when there is no charset specified for a MIME text body part. A kUniType... constant (not Character/Auto/Binary)
&cErrorText If supplied, receives text describing the error that caused $splitmultipart to return false

The MIME list (for this call and for the other OW3 calls that generate a MIME list) now contains an additional column named bodypartheaders. This is a row containing a column for each non-empty header present for the body part. In addition, it has a column named "name" which contains the content-disposition header name parameter. All header names are normalized in the same way as those passed to RESTful services, that is, lower-case with any - characters removed.

Callback methods

$completed

When a worker is started using either $run or $start, it reports its completion by calling $completed. Override the $completed method of the worker object to receive this notification. It is called with a single row variable parameter. The columns of the row are specific to each type of worker object, so they are described in each specific worker object section.

$cancelled

To receive a notification that a request has been cancelled using $cancel, override the $cancelled method of the worker object. It is called with no parameters.

$progress

To receive progress notifications, override the $progress method of the worker object. OW3 worker objects generate notifications to $progress as and when some data has been transferred. Progress notifications will not be generated any more than once a second. Each notification receives a row variable parameter. The row has 4 columns.

Column Description
downloadTotalBytesExpected The total number of bytes expected to be downloaded from the server. This may always be zero, for example when the server is using chunked HTTP transfer encoding
downloadBytesSoFar The number of bytes downloaded from the server so far
uploadTotalBytesExpected The total number of bytes expected to be uploaded to the server
uploadBytesSoFar The number of bytes uploaded so far

For the OW3 FTP worker, $progress can be called for synchronous operations.

OAUTH2 Worker Object

OAUTH2 authorization is supported in the HTTP, IMAP, POP3, and SMTP workers via the OAUTH2 Worker Object in the OW3 Worker object package.

Refer to the HTTP, IMAP, POP3, and SMTP Worker Object examples in the Samples section of the Hub in the Studio Browser to see how to use OAUTH2 for authorization.

Why use OAUTH2

OAUTH 2.0 provides much improved security over and above simple username and password schemes. It is commonly used by many different service providers, such as Google mail, for which its use will become mandatory in 2020 (meaning less secure apps will no longer be supported). You can read about OAUTH 2.0 in RFC 6749 (https://tools.ietf.org/html/rfc6749)

An application wishing to use a service (using HTTP, IMAP, POP3, or SMTP) requires an Access Token of type “bearer”. The application needs to be registered with the service, so it can identify itself to the service, and the registration process provides the application with a Client Id and a Client Secret, that identify the application to the service.

As an initial step, the user of the service must authorize the application to use the service. To do this:

At this point, the application can use the Access Token to make requests to the service. Access Tokens are short-lived, typically being valid for about an hour. If the Token URL server also returned a Refresh Token, the application can use that after the Access Token has expired to obtain a new Access Token, without any further interaction with the user. Refresh Tokens typically have a long lifetime, but may be invalidated for various reasons, depending on the service implementation.

Single Sign-On (SSO)

Omnis does not provide Single Sign-On (SSO), but you can call into SSO services provided by Google or Microsoft, for example, for which Omnis would need to use OAUTH2 to access these services.

In this case, once you obtain the necessary access tokens, as long as you've selected the right scopes for what you intend to do, you can call those SSO services without having to prompt the user to login again and also refresh the tokens if they expire (as long as you are not past the refresh token's expiration time/date).

Obtaining Authorization

The OAUTH2 Worker allows you to obtain an Authorization Code, exchange it for tokens, and refresh tokens, using the $authorize() method on a background thread. The worker also contains methods to save and load the tokens and other related information to and from an encrypted binary block of data, which helps to protect key pieces of information such as the Refresh Token and Client Secret.

Note that you must always use an Object Reference to create the OAUTH2Worker object – this eliminates potential issues with the way Omnis uses the OAUTH2Worker as a property value.

The object reference to an OAUTH2Worker object containing the authorization information can be passed to the $oauth2 property in the HTTP, IMAP, POP3, and SMTP Workers to provide authorization.

The $addclientdetailstotokenrequest boolean allows you to include or remove client credentials from the body of a token request (when Omnis exchanges the authorization code for the access token).

OAUTH2 Properties

These properties are specific to the OAUTH2 Worker Object.

Property Description
$accesstoken The access token to be used with HTTP, IMAP, POP3 and SMTP connections
$accesstokenexpiry The expiry date and time of the access token (in UTC time). #NULL means no access expiry date and time is available
$addclientdetailstotokenrequest If kTrue (default), the client id and client secret are added to the body of the request to get the token. If kFalse, the client id and client secret are not added to the token request
$authorizeurl The URL of the OAUTH2 authorization endpoint
$clientid The Client Id used in conjunction with the client secret to identify the application to the OAUTH2 authorization server
$clientsecret The Client Secret used in conjunction with the Client Id to identify the application to the OAUTH2 authorization server
$redirecturiserveraddress If not empty (the default value), this property overrides localhost in the redirect URI server address, replacing localhost with the value of this property. The default is localhost rather than 127.0.0.1 when generating redirect URIs when running in a thick client remote task. If using the default redirect URI, Omnis will pass localhost[:$serverport]/api/__oauth2/omnis to the service
$refreshtoken The Refresh Token to be used to request a new access token after the access token has expired
$scope A string identifying the type of access required. Used as part of the URL used to open the Web Browser at the authorization endpoint. For example, when using Google to access GMAIL, specify the scope as "https://mail.google.com/"
$tokenurl The URL of the OAUTH2 token endpoint
$oauth2state Custom content to be appended to the 32-character UUID in the state query string parameter
$tokentype A string with the value 'Bearer' which is used as a fallback token type if the OAUTH2 worker object does not return token_type in its response. This should only be used when you're sure it's needed and as a workaround for a bad or missing OAUTH2 endpoint

HTTP and General Properties

In addition to the OAUTH2 properties, the OAUTH2Worker also has various HTTP and general OW3 properties, that for example affect how the HTTP requests it makes are executed: the OAUTH2Worker makes two different HTTP requests: a request to exchange an Authorization Code for an Access Token, and a request to obtain a new Access Token using the Refresh Token.

Property Description
$errorcode Error code associated with the last action (zero means no error)
$errortext Error text associated with the last action (empty means no error)
$followredirects If true, the HTTP request will follow a server redirect in order to complete the request. Defaults to false
$proxyserver The URI of the proxy server to use for all requests from this object e.g. http://www.myproxy.com:8080. Must be set before executing $run or $start. Defaults to empty (no proxy server)
$proxytunnel If true, and $proxyserver is not empty, requests are tunnelled through the HTTP proxy
$proxyauthtype The type of HTTP authentication to use when connecting to $proxyserver. A kOW3httpAuthType... constant (see below)
$proxyauthusername The username used to authenticate the user when connecting to $proxyserver using $proxyauthtype
$proxyauthpassword The password used to authenticate the user when connecting to $proxyserver using $proxyauthtype
$state A kWorkerState... constant that indicates the current state of the worker object
$threadcount The number of active background threads for all instances of this type of worker object
$timeout The timeout (in seconds) for requests. Defaults to 60 with a minimum value of 10
$protocollog If non-zero, the worker adds a log of protocol activity as a column named log to its wResults row. The desired value must be set before calling $run or $start. Defaults to kOW3logNone. Otherwise, a sum of kOW3log... constants

OAUTH2 Standard Methods

$authorize

$authorize([iAuthFlow=kOW3OAUTH2authFlowCodeWithPKCE])

Starts the OAUTH2 authorization flow iAuthFlow on a background thread. Returns true if the thread was successfully started. Properties of the object cannot be assigned while $authorize() is running.

$authorize() opens a Web Browser at the authorization URL, passing the URL various parameters in the query string, such as the Client Id using the value of the $clientid property.

How the Web Browser is opened depends on the context in which $authorize() is called.

When executed within the context of a thick client (non-remote) task, $authorize() uses the $webbrowser property to control which browser it opens (note that you cannot use $authorize() with a thick client task when running in the headless server). It should be noted that when running in the thick client, $authorize() always uses a web browser rather than an embedded obrowser control due to best practice considerations documented in RFC 8252: https://www.rfc-editor.org/rfc/rfc8252.txt

To use $authorize() in the Runtime version of Omnis, you must set the disableInRuntime item in the ‘server’ section of the config.json file to false.

When executed within the context of a remote task, $authorize() will only work if the remote task is a JavaScript Client remote task. In this case, it uses the $showurl() mechanism of the JavaScript Client to open a browser window or tab. Note that in this case, you cannot execute both $authorize() and $showurl() in response to the same JavaScript client event.

When using the authorization flows that redirect the browser to a URI, $authorize() determines the redirect URI as follows.

For the thick client, it uses a loopback URI, to 127.0.0.1. Note that if the version of Omnis is not a server version, Omnis will still open a server port with limited support for OAUTH2 only, to allow the Authorization Code to be received via the redirect URI.

For the JavaScript client, $authorize() uses the RESTful URI determined from the Omnis server configuration. Note that this means that if you are using a Web Server to handle requests for your Omnis server, you need to set up the Omnis Web Server plugin for both the JavaScript client and RESTful requests.

$authorize() takes a single parameter, iAuthFlow, which can have one of the following constant values (kOW3OAUTH2authFlowCodeWithPKCE is the default):

Constant Description
kOW3OAUTH2authFlowCode The normal OAUTH2 authorization flow, where the authorization code will be received by redirecting the browser to a URI served by Omnis
kOW3OAUTH2authFlow
CodeWithPKCE
Identical to kOW3OAUTH2authFlowCode, except that the worker uses PKCE to further secure its requests for an authorization code; the default iAuthFlow (see https://tools.ietf.org/html/rfc7636)
kOW3OAUTH2authFlow
ManualCode
Like kOW3OAUTH2authFlowCode, except that the redirect URI is urn:ietf:wg:oauth:2.0:oob. This means that instead of the authorization code arriving at Omnis via the redirect URI, the user must copy the authorization code to the clipboard from the browser window, and paste it into Omnis or the JavaScript client; after pasting, the Omnis application must call the method $setauthcode() (described below)
kOW3OAUTH2authFlow
ManualCodeWithPKCE
Like kOW3OAUTH2authFlowManualCode, but also uses PKCE

Note that you would normally use PKCE unless the service does not support it.

Manual code support, via the clipboard, is provided in case you do not want to open up a port for the redirect URI when running in the thick client; however, note that not all services support the redirect URI urn:ietf:wg:oauth:2.0:oob.

When $authorize() completes (which if successful means that is has opened the browser, received the Authorization Code, and exchanged it for an Access Token etc) it generates a call to the callback method $completed().

$setauthcode

$setauthcode(cAuthCode)

Returns Boolean true for success.

Only applicable to kOW3OAUTH2authFlowManualCode and kOW3OAUTH2authFlowManualCodeWithPKCE, when the $authorize() thread is waiting for the Authorization Code. Called from the application to supply the pasted Authorization Code using the cAuthCode parameter.

$save

$save(&xOAUTH2[,xKey])

Saves the properties ($clientid, $clientsecret, $authorizeurl, $tokenurl, $scope, $accesstoken, $refreshtoken and $accesstokenexpiry) to the encrypted binary buffer xOAUTH2.

xKey is a 256 bit AES encryption key. If you omit xKey, OW3 uses a hard-coded default key.

Returns Boolean true for success.

$save provides a convenient way to save all of the OAUTH2 parameters required for communicating with a service. In particular, it lets you safely store the Refresh Token, so you can minimise the number of occasions on which a user needs to authorize access using $authorize().

You can further protect your client secret, by including the encrypted buffer generated by $save in your release tree.

$load

$load(xOAUTH2[,xKey])

Loads the properties ($clientid, $clientsecret, $authorizeurl, $tokenurl, $scope, $accesstoken, $refreshtoken and $accesstokenexpiry) from the encrypted binary buffer xOAUTH2 previously generated using $save().

xKey is a 256 bit AES encryption key. If you omit xKey, OW3 uses a hard-coded default key. You must use the same key as that used when calling $save().

Returns Boolean true for success.

Grant Types

From Studio 11, the OAUTH2 Worker supports multiple grant types: authorization_code, password, and client_credentials (as per RFC 6749 sections 4.1, 4.3 and 4.4).

The $granttype property takes one of the following grant types:

The $granttype property is set to kOW3OAUTH2grantAuthorizationCode by default which corresponds to behavior versions prior to Studio 11, so existing code should run as before.

When $granttype is set to kOW3OAUTH2grantPassword, the $password and $username properties can be used to retrieve an authorization token. However, this is deemed to be insecure, when compared to more secure methods, and should not be used (unless a legacy system requires it).

When $granttype is set to kOW3OAUTH2grantClientCredentials, the properties $clientid and $clientsecret are used to obtain the authorization token. Note that when using this grant type, the OAUTH2 server may not return a refresh token (as per RFC 6749 section 4.4.3).

Adding custom content to OAUTH2 state parameter

The $oauth2state property can contain custom content to be appended to the 32-character UUID in the state query string parameter of the request, allowing you to identify requests sent from multiple instances of Omnis.

If you are handling this on a reverse proxy, you will have to URL-decode and look for your value after the first 32 characters, but it is important when proxying off the request to keep the UUID in the state, otherwise Omnis will not be able to match the callback to the initiated request.

OAUTH2 Callback Methods

$tokensrefreshed

The OAUTH2Worker has one non-standard callback method, $tokensrefreshed. The OAUTH2Worker generates a call to this method after it has successfully refreshed the tokens while it is being used in conjunction with the HTTP/IMAP/POP3/SMTP worker.

$tokensrefreshed() is called with no parameters; at this point, the worker has been updated with the new Access Token, Access Token Expiry and Refresh Token. A typical implementation of $tokensrefreshed() would use $save() to save the current tokens etc and then write the encrypted buffer to disk. It should be noted that calling the server to refresh tokens can result in a different updated Refresh Token - this needs to be used to refresh tokens the next time a refresh is required.

HTTP and General Methods

The OAUTH2Worker supports the normal methods $cancel(), $getsecureoptions() and $setsecureoptions(). The latter two relate to how secure connections to the Token URL are established.

HTTP Callback Methods

The OAUTH2Worker generates calls to the standard callback methods $cancelled() and $completed(). These correspond to a call to $authorize() to start the authorization code flow. The completion row passed as a parameter to $completed() has columns as follows:

Column Description
errorCode An integer error code indicating if the request was successful. Zero means success. If successful, $accesstoken, $accesstokenexpiry and $refreshtoken have been updated using the content received from the server; if no Access Token Expiry was received, $accesstokenexpiry is #NULL; if no Refresh Token was received, $refreshtoken is empty
errorInfo A text string providing information about the error if any
scope The scope returned from the server when requesting the Access Token, if different to the requested scope
log If you used $protocollog to generate a log, this column contains the log data, either as character data, or UTF-8 HTML. Otherwise, the log column is empty
state contains the value you set up in the $oauth2state property. This helps you to identify which user the callback belongs to. In the case where multiple OAuth2 workers are used to authenticate multiple mobile devices, you could for example set a UUID in the $oauth2state property and keep a list of username:uuid until the $completed callback, where you can match up the token received

HTTP, IMAP, POP3, and SMTP Workers

Once you have used $authorize() to obtain an Access Token, you need to make the Access Token available to the worker with which OAUTH2 authorization is required. You do this by assigning a new $oauth2 property of the HTTP, IMAP, POP3, or SMTP worker:

The supported workers use $oauth2 to obtain the Access Token for the request. To do this, it uses the following logic:

You should note that there is a chance the request will fail when it is made near to the 5 second window before the Access Token expires. You should be prepared to handle this type of error in $completed, possibly retrying the request.

HTTP

After assigning $oauth2, the parameters iAuthType, cUserName, and cPassword passed to $init() are ignored in favour of using the Access Token stored in $oauth2.

IMAP, POP3, SMTP

After assigning $oauth2, the cPassword parameter passed to $init() is ignored in favour of using the Access Token stored in $oauth2. Note that cUserName is still required.

OAUTH2 Example

The following code extracts are taken from the SMTP Worker Object in the Samples section of the Hub in the Studio Browser, which uses the OAUTH2 object for authorization.

# create the OAUTH2 object
Do $extobjects.OW3.$objects.OAUTH2Worker.$newref() Returns iOAUTH2

# setup the SMTP object
Do $objects.oSMTPWorker.$newref() Returns iSmtp
Do iSmtp.$setCallingInst($cinst)

# set iOAUTH2 properties from settings contained in a form
Calculate iOAUTH2.$callbackinst as $cinst
  
Calculate iOAUTH2.$clientid as iOAUTH2ClientID
Calculate iOAUTH2.$clientsecret as iOAUTH2ClientSecret
Calculate iOAUTH2.$authorizeurl as iOAUTH2CodeURL
Calculate iOAUTH2.$tokenurl as iOAUTH2TokenURL
Calculate iOAUTH2.$scope as iOAUTH2Scope
  
Calculate iOAUTH2.$followredirects as iOAUTH2FollowRedirects
Calculate iOAUTH2.$timeout as iOAUTH2Timeout
Calculate iOAUTH2.$proxyserver as iOAUTH2ProxyServer
Calculate iOAUTH2.$proxytunnel as iOAUTH2ProxyTunnel
Calculate iOAUTH2.$proxyauthtype as iOAuth2ProxyAuthList.iAuthType
Calculate iOAUTH2.$proxyauthusername as iOAUTH2ProxyUser
Calculate iOAUTH2.$proxyauthpassword as iOAUTH2ProxyPassword
  
Calculate iOAUTH2.$protocollog as iOAUTH2LogTypeList.C2
  
Calculate iAuthorizing as kTrue
Do iOAUTH2.$authorize(iOAUTH2AuthorizationFlowList.iOAUTH2FlowTypeReturns lOK
If not(lOK)
  OK message {[iOAUTH2.$errortext]}
End If
Calculate iAuthorizing as kFalse

# $start method
If iAuthorizing
  OK message {Cannot execute while authorizing}
  Quit method
End If

If iUseOAUTH2   ## option on form to use OAUTH2
  Do iSmtp.$oauth2.$assign(iOAUTH2)
Else
  Do iSmtp.$oauth2.$assign(#NULL)
End If

HTTP Worker Object

The HTTPClientWorker provides client HTTP support. For example, you can POST data to a server, execute a RESTful request, or download a file from a server.

The HTTP Worker supports the following externals:

There is an HTTP OW3 Worker Object example in the Samples section of the Hub in the Studio Browser.

Properties

The HTTPClientWorker has the following properties in addition to the base worker properties described earlier:

Property Description
$followredirects If true, the HTTP request will follow a server redirect in order to complete the request. The desired value must be set before calling $run or $start. Defaults to false
$proxyserver The URI of the proxy server to use for all requests from this object e.g. http://www.myproxy.com:8080. Must be set before executing $run or $start. Defaults to empty (no proxy server)
$proxytunnel If true, and $proxyserver is not empty, requests are tunnelled through the HTTP proxy
$proxyauthtype The type of HTTP authentication to use when connecting to $proxyserver. A kOW3httpAuthType... constant. kOW3httpAuthType constants are described in the Constants section below
$proxyauthusername The user name used to authenticate the user when connecting to $proxyserver using $proxyauthtype
$proxyauthpassword The password used to authenticate the user when connecting to $proxyserver using $proxyauthtype
$responsepath If not empty, the worker writes response content to the file with this path rather then adding it to the wResults row. The file must not already exist. The desired value must be set before calling $run or $start. Defaults to empty
$oauth2 An object reference to an OAUTH2Worker object containing the authorization information required to make requests to the server: see OAUTH2 Worker Object

Constants

The HTTPClientWorker uses the following constants for the iMethod parameter in the $init method (in addition to the base worker constants described earlier):

Constant Description
kOW3httpMethodDelete Sends a DELETE method
kOW3httpMethodGet Sends a GET method
kOW3httpMethodHead Sends a HEAD method
kOW3httpMethodOptions Sends a OPTIONS method
kOW3httpMethodPatch Sends a PATCH method
kOW3httpMethodPost Sends a POST method
kOW3httpMethodPut Sends a PUT method
kOW3httpMethodTrace Sends a TRACE method

The following constants are for the iAuthType parameter in the $init method:

Constant Description
kOW3httpAuthTypeNone Indicates that no HTTP authentication is required, the default (in this case a user name and password do not need to be supplied)
kOW3httpAuthTypeBasic Indicates that basic HTTP authentication is required
kOW3httpAuthTypeDigest Indicates that digest HTTP authentication is required
kOW3httpAuthTypeAWSv4 Indicates that AWS Signature V4 authentication is required
kOW3httpAuthTypeNTLM Indicates that NTLM authentication is required

The following constants are for the vContent parameter in the $init method:

Constant Description
kOW3httpMultiPartFormData Indicates that HTTP multipart/form-data content is to be sent (see the $multipart... methods described below)

Methods

HTTPClientWorker has the methods described in this section in addition to the base worker methods described earlier.

Normal methods

$init

$init(cURI [,iMethod=kOW3httpMethodGetlHeaders=#NULL, vContent='', iAuthType=kOW3httpAuthTypeNonecUserName='',cPassword=''])

Called to prepare the object to execute a request, before calling $run or $start; the URI is the only required parameter.

Returns Boolean true for success, or returns false and sets $errorcode and $errortext if an error occurs.

The parameters are:

Parameter Description
cURI The URI of the resource, optionally including the URI scheme (http or https) e.g. http://www.myserver.com/myresource. If you omit the URI scheme e.g. www.myserver.com/myresource,the URI scheme defaults to http. You can also include query string parameters if desired e.g. http://www.myserver.com/myresource?param1=test&param2=test
iMethod A kOW3httpMethod... constant that identifies the HTTP method to perform
lHeaders A two-column list where each row is an HTTP header to add to the HTTP request Column 1 is the HTTP header name e.g. 'content-type' and column 2 is the HTTP header value e.g. ‘application/json'. If you do not supply the header “accept-encoding” the worker automatically decompresses content compressed using gzip or deflate; however, if you supply this header, the worker does not perform automatic decompression
vContent kOW3httpMultiPartFormData or a binary, character or row variable containing content to send with the request. kOW3httpMultiPartFormData means send the content built using the $multipart… methods described below. The worker sends binary data as it is. The worker converts character data to UTF-8 and sends the UTF-8. A row must have a single column containing the path of the file containing the content to send. If you do not specify a content-type header in lHeaders, the worker will generate a suitable type if it recognises the file extension when using a row, or when using a character value it will use text/plain;charset=utf-8. Otherwise, it will use application/octet-stream. In addition, the worker will automatically add a content-length header, so there is no need to pass this in lHeaders.From Studio 11, you can pass a raw List or Row which the worker will subsequently transform into JSON before executing the request. If a row is passed and it contains only one column, which is a path to a file that exists, the contents of the file will be used. If the file does not exist, the contents of the row will be converted to JSON and sent with the request. Code which passes JSON in a binary variable is not affected. The lists can contain sub-lists as the worker supports both JSON arrays of arrays, and arrays of objects
iAuthType A kOW3httpAuthType... constant that specifies the type of authentication required for this request. If you omit this and the remaining parameters, authentication defaults to kOW3httpAuthTypeNone
cUserName The user name to use with authentication types kOW3httpAuthTypeBasic and kOW3httpAuthTypeDigest
cPassword The password to use with authentication types kOW3httpAuthTypeBasic and kOW3httpAuthTypeDigest

NOTE: If you call $init when a request is already running on a background thread, the object will cancel the running request, and wait for the request to abort before continuing with $init.

AWS Signature V4 authentication

You can use AWS Signature V4 authentication using the kOW3httpAuthTypeAWSv4 constant with the $init() method. In this case, the username parameter must be formatted in accessKey/region/service format and the password must be set to the secret key, for example:

Calculate accessKey as 'AKIA...'
Calculate region as 'us-east-1'
Calculate service as 's3'
Do iHttp.$init(iURI,iMethodList.iMethod,iHeaderList,,kOW3httpAuthTypeAWSv4,con(accessKey,'/',region,'/',service),'jYN/BU...') Returns lOk

When the request is executed, the HTTP worker will attempt AWS Signature V4 authentication and set up the required headers automatically.

NTLM authentication

You can use NTLM (Windows) authentication using the kOW3httpAuthTypeNTLM constant with the $init() method. In this case, you need to specify the username and password parameters as usual.

When talking to IIS on Linux and attempting NTLM authentication, you need to specify http2 using $curloptions, for example:

Do iHttp.$curloptions.$assign(list(row(84,3)))

To enable Authentication in your Windows installation, go the Default Web Site 'Authentication' option, enable Windows Authentication and disable anonymous authentication. Note, when installing IIS, you might have to look through various extras to get Windows Authentication.

Example

The following code could be used to prepare an HTTPClientworker object using $init, and then $run can be used to execute the HTTP method. The method returns the content of the web page stored in iURI, e.g. ww.omnis.net.

# $execute method
Do method checkHttpObject ## sets up the HTTP object ref var
Do method setupLogging ## sets up logging based on user choice
If len(iTempContent)
    Do iHttp.$init(iURI,iMethodList.iMethod,iHeaderList,iTempContent,iAuthList.iAuthType,iUser,iPasswordReturns lOk
Else
    If iSendContentMode=1
        Do iHttp.$init(iURI,iMethodList.iMethod,iHeaderList,row(iContentPath),iAuthList.iAuthType,iUser,iPasswordReturns lOk
    Else If iSendContentMode=2
        Do iHttp.$buildmultipart(iContentPath)
        Do iHttp.$init(iURI,iMethodList.iMethod,iHeaderList,kOW3httpMultiPartFormData,iAuthList.iAuthType,iUser,iPasswordReturns lOk
    Else If iSendContentMode=0
        Do iHttp.$init(iURI,iMethodList.iMethod,iHeaderList,iContent,iAuthList.iAuthType,iUser,iPasswordReturns lOk
    End If
End If
If not(lOk)
    OK message {Error [iHttp.$errorcode]: [iHttp.$errortext]}
    Quit method kFalse
End If
If pRun
    Do iHttp.$run() Returns lOk
Else
    Do iHttp.$start() Returns lOk
    If lOk
        Calculate $cinst.$objs.ScrollBox.$objs.cancel.$enabled as kTrue
        Calculate $cinst.$objs.ScrollBox.$objs.execute.$enabled as kFalse
        Calculate $cinst.$objs.ScrollBox.$objs.executethencancel.$enabled as kFalse
    End If
End If
If not(lOk)
    OK message {Error [iHttp.$errorcode]: [iHttp.$errortext]}
    Quit method kFalse
End If
Quit method kTrue

$multipartclear

$multipartclear()

Frees any previously generated multipart/form-data content. Note that calling $run or $start with kOW3httpMultiPartFormData results in the multipart/form-data content being automatically freed after use.

Returns Boolean true for success, or returns false and sets $errorcode and $errortext if an error occurs.

$multipartaddfield

$multipartaddfield(cNamecFieldData [,lPartHeaders])

Adds a field part to the multipart/form-data content stored in the worker object. To send this content specify kOW3httpMultiPartFormData as the vContent parameter to $init().

Returns Boolean true for success, or returns false and sets $errorcode and $errortext if an error occurs.

The parameters are:

Parameter Description
cName The name of the multipart/form-data field part
cFieldData The value of the multipart/form-data field
lPartHeaders A two-column list where each row is a header to add to the part. Column 1 is the header name and column 2 is the header value

$multipartaddfile

$multipartaddfile(cName, vFileData [,cFileName='', lPartHeaders])

Adds a file part to the multipart/form-data content stored in the worker object. A file part indicates to the server that a file is being uploaded. To send this content specify kOW3httpMultiPartFormData as the vContent parameter to $init().

Returns Boolean true for success, or returns false and sets $errorcode and $errortext if an error occurs.

The parameters are:

Parameter Description
cName The name of the multipart/form-data file part
vFileData A binary, character or row variable containing the file data for the part. The worker sends binary data as it is. The worker converts character data to UTF-8 and sends the UTF-8. A row must have a single column containing the path of the file containing the content to send. If you do not specify a content-type header in lPartHeaders, the worker will generate a suitable type if it recognises the file extension when using a row, or when using a character value it will use text/plain;charset=utf-8. Otherwise, it will use application/octet-stream
cFileName The filename of the part. Must be specified if vFileData is binary or character. If vFileData is a row (identifying a file) then this overrides the default filename (the name of the file)
lPartHeaders A two-column list where each row is a header to add to the part. Column 1 is the header name and column 2 is the header value

Callback methods

$completed

The standard $completed callback is passed a row variable parameter with the following columns:

Column Description
errorCode An integer error code indicating if the request was successful. Zero means success i.e. the HTTP request was issued and a response received - you also need to check the httpStatusCode to know if the HTTP request itself worked
errorInfo A text string providing information about the error if any
httpStatusCode A standard HTTP status code that indicates the result received from the HTTP server
httpStatusText The HTTP status text received from the HTTP server
responseHeaders A row containing the headers received in the response from the HTTP server.
The header values are stored in columns of the row.
The column name is the header name converted to lower case with any - characters removed, so for example the Content-Length header would have the column name contentlength.
If the client receives multiple headers with the same name, it combines them into a single header with a comma separated list of the received header values. This is consistent with the HTTP specification
responseContent If you have not used $responsepath to write the received content directly to a file, this is a binary column containing the content received from the server
log If you used $protocollog to generate a log, this column contains the log data, either as character data, or UTF-8 HTML. Otherwise, the log column is empty

WebSocket Client Support

$init

To initialise the OW3 HTTP worker object so that it is ready to create a WebSocket client connection, call $init with parameters as follows:

Parameter Description
cURI The URI of the WebSocket server, which must include the URI scheme (ws or wss) e.g. wss://demos.kaazing.com/echo
You cannot omit the URI scheme, because the HTTP worker defaults to using http
iMethod Must be kOW3httpMethodGet
lHeaders A two column list where each row is an HTTP header to add to the HTTP request.
The worker automatically adds these headers when connecting to a WebSocket server, so do not add these headers:
connection: upgrade upgrade: websocket
sec-websocket-version: 13
sec-websocket-key:
vContent Not used
iAuthType A kOW3httpAuthType... constant that specifies the type of authentication required for this request. If you omit this and the remaining parameters, authentication defaults to kOW3httpAuthTypeNone
cUserName The user name to use with authentication types kOW3httpAuthTypeBasic and kOW3httpAuthTypeDigest
cPassword The password to use with authentication types kOW3httpAuthTypeBasic and kOW3httpAuthTypeDigest

The standard OW3 properties $state, $errortext, $errorcode, $threadcount, $protocollog, $timeout, $callprogress and $curloptions all apply when connecting to a WebSocket server.

The standard OW3 methods $getsecureoptions and $setsecureoptions apply when connecting to a WebSocket server.

$run and $start

You cannot use $run to establish a WebSocket connection, since multiple threads are required to make it usable. So if you try to use $run, the worker returns kFalse and sets $errorcode and $errortext.

To establish a WebSocket connection, call $start. If $start succeeds, then the worker attempts to establish the connection to the WebSocket server in another thread.

If the connection cannot be established, the worker generates a notification to $completed, with a non-zero value in the errorCode member of the notification row parameter.

If the connection is established successfully (and is therefore open and ready for data transfer), the worker generates a notification to the new method $ws_onconnect. Override this method to receive this notification. $ws_onconnect receives a single row variable as its parameter. This row variable has a single column, responseHeaders, which is a row with a single column for each response header received from the server in the final HTTP protocol exchange resulting in the 101 (web socket protocol handshake) HTTP status code.

As soon as you have received the $ws_onconnect notification, the WebSocket is ready to send and receive data.

$wssend

After you have received the $ws_onconnect notification, you can send data using the method $wssend:

$wssend(vMessage)

Sends the supplied message on a connected web socket. Returns true if successful, which means the message has been queued for sending.

If vMessage is a character value, the worker converts it to UTF-8 before sending it as a text message; otherwise the value is treated as binary and sent as a binary message.

Receiving Data

Each message received from the WebSocket server generates a $ws_onmessage notification. Override this method to receive these notifications. $ws_onmessage receives a single row variable parameter, with 2 columns (named data and utf8). Column data is the binary data and column utf8 is boolean true if the data is UTF-8.

$wsclose

The client can close the WebSocket connection by calling the method $wsclose:

$wsclose([bDiscardUnsentMessages=kFalse,iStatusCode=1000,cReason=''])

Closes the connection to the web socket server. $completed() will be notified when the connection has closed. The row passed to $completed has closeStatus and closeReason columns that receive the values sent in the close frame to the server.

Pass bDiscardUnsentMessages as kTrue, to discard any completely unsent queued messages before sending the close frame to the server.

iStatusCode is an integer status code that indicates the reason for closure (one of the values in section 7.4 of RFC6455).

cReason is some optional text that indicates the reason for closure.

Server close

The server can send a close frame to the client, telling the client it is closing the connection. The client responds with a close frame, before the connection closes. Again, $completed is notified to tell the object that the connection has closed.

The row passed to $completed has closeStatus and closeReason columns that receive the values sent in the close frame from the server.

$cancel

You can use $cancel to terminate the connection in a non-graceful manner.

Ping-pong

If the client receives a Ping from the server, it automatically responds with a Pong. You can also set up the client to automatically Ping the server, and generate an error (closing the connection) if a Pong is not received. To do this, use these two properties:

$wspinginterval: If non-zero, and the connection is to a web socket server, the HTTP worker sends a Ping frame to the server every $wspinginterval seconds of inactivity, and closes the connection if a Pong frame is not received after $wspongtimeout seconds. Defaults to zero.

$wspongtimeout: The number of seconds (1-60, default 5) the client waits to receive a Pong frame after sending a Ping frame as a result of the $wspinginterval timeout expiring.

Timeout

The object restarts the $timeout timer each time it sends or receives some data.

SMTP Worker Object

The SMTPClientWorker provides client SMTP support, allowing you to use the worker to send emails, including bulk emails via a mailshot. The following sections describe the SMTP worker properties, constants and methods.

There is an SMTP OW3 Worker Object example in the Samples section of the Hub in the Studio Browser.

Properties

The SMTPClientWorker has the following properties in addition to the base worker properties described earlier:

Property Description
$requiresecureconnection If true, and the URI is not a secure URI, the connection starts as a non-secure connection which must be upgraded to a secure connection (using the STARTTLS command). If it cannot be upgraded then the request fails. Defaults to false
$keepconnectionopen If true, the worker can leave the connection to the server open when it completes its request. Defaults to false. Note that even when this property is set to true, a protocol error may cause the connection to close. Use true if you are likely to send more emails using the same server fairly soon
$callmailshotprogress If true, and the worker is sending a mailshot asynchronously via $start, the worker generates notifications to $mailshotprogress as it executes. $callmailshotprogress must be set before calling $start. Defaults to false
$oauth2 An object reference to an OAUTH2Worker object containing the authorization information required to make requests to the server: see OAUTH2 Worker Object
$allowpathinuri If true, the SMTP Worker will accept paths in the URI used in the $init method, e.g. smtp://my.smtp.server:587/my.helo.address. Defaults to false

Constants

The SMTPClientWorker uses the following constants in addition to the base worker constants described earlier:

Constant Description
kOW3msgPriorityLowest The message has the lowest priority
kOW3msgPriorityLow The message has low priority
kOW3msgPriorityNormal The message has normal priority
kOW3msgPriorityHigh The message has high priority
kOW3msgPriorityHighest The message has the highest priority

Methods

SMTPClientWorker has the methods described in this section in addition to the base worker methods described earlier.

Normal methods

$init

$init(cURIcUsercPassword, vFrom, lTolCclBcccSubjectcPrioritylHeaders, vContent [,bMailshot=kFalse])

Called to prepare the object to execute a request, before calling $run or $start.

Returns Boolean true for success, or returns false and sets $errorcode and $errortext if an error occurs.

The parameters are:

Parameter Description
cURI The URI of the server, optionally including the URI scheme (smtp or smtps), e.g. smtp://test.com. If you omit the URI scheme e.g. smtp.myserver.com the URI scheme defaults to smtp. If the server uses a non-standard port, you can include it in the URI like this example smtp://smtp.myserver.com:2525
cUser The user name to be used to log on to the SMTP server
cPassword The password to be used to log on to the SMTP server
vFrom The email address of the message sender. Either a character value e.g. user@test.com or a row with 2 columns where column 1 is the email address e.g. user@test.com and column 2 is descriptive text for the sender, typically their name
lTo A one or two column list where each row identifies a primary recipient of the message. Column 1 contains the email address e.g. user@test.com and column 2 if present contains descriptive text for the recipient, typically their name
lCc Empty if there are no CC recipients, or a one or two column list where each row identifies a carbon copied recipient of the message. Column 1 contains the email address e.g. user@test.com and column 2 if present contains descriptive text for the recipient, typically their name
lBcc Empty if there are no BCC recipients, or a single column list where each row contains the email address of a blind carbon copied recipient of the message e.g. user@test.com. Unlike lTo and lCc, lBcc does not allow more than 1 column, as blind carbon copied recipients are not added to the message header and therefore the descriptive text is not required
cSubject The subject of the message
iPriority A kOW3msgPriority... constant that specifies the priority of the message
lHeaders A two-column list where each row is an additional SMTP header to send with the message. Column 1 is the header name e.g. 'X-OriginalArrivalTime' and column 2 is the header value e.g. ’23:02'
vContent Message content. Either binary raw content (which the worker sends exactly as it is), or a list to be sent as MIME. See the documentation for the MailSplit command to see how a MIME list is structured; however, note that the charset in the worker MIME list is a kUniType... constant rather than a character string
bMailshot Allows a mailshot to be sent (default is kFalse). If true, the worker sends a separate copy of the message to each recipient in the lTo list (so that each recipient cannot see the addresses of the others); only lTo is used, and lCc and lBcc must be empty

NOTE: If you call $init when a request is already running on a background thread, the object will cancel the running request, and wait for the request to abort before continuing with $init.

Example

The $init method can be used to prepare the SMTPClientWorker object to be executed using the $run or $start method. In this case, iSmtp is an object reference variable with its subtype set to an object class, which has its $superclass set to the SMTPClientWorker in the OW3 worker objects group.

# $start method
Do method setupLogging ## set up logging
Calculate iSmtp.$timeout as iTimeout ## set properties via window fields
Calculate iSmtp.$callprogress as iCallProgress
Calculate iSmtp.$keepconnectionopen as iKeepConnectionOpen
Calculate iSmtp.$requiresecureconnection as iRequireSecureConnection
Calculate iSmtp.$callmailshotprogress as iCallMailshotProgress
Do method $splitaddressentry (iFrom,lFromAddress,lFromDescriptionReturns lOk
If not(lOk)
    OK message {From "[iFrom]" is invalid}
    Quit method kFalse
End If
Calculate lOk as $cinst.$makerecipientlist(lToList,iTo)
If not(lOk)
    OK message {From "[iTo]" is invalid}
    Quit method kFalse
End If
Calculate lOk as $cinst.$makerecipientlist(lCcList,iCc)
If not(lOk)
    OK message {From "[iCc]" is invalid}
    Quit method kFalse
End If
Calculate lOk as $cinst.$makerecipientlist(lBccList,iBcc)
If not(lOk)
    OK message {From "[iBcc]" is invalid}
    Quit method kFalse
End If
If iCallMailshotProgress
    Set reference lMailshotProgressItem to $clib.$windows.wMailshotProgress.$openmodal("*",kWindowCenterRelative,$cinst,lToList.$linecount,$cinst)
End If
Do iSmtp.$setMailshotProgressInst(lMailshotProgressItem)
If iNoMIME
    If len(lFromDescription)
        Do iSmtp.$init(iServerURI,iUser,iPassword,row(lFromAddress,lFromDescription),lToList,lCcList,lBccList,iSubject,iPriorityList.iPriorityValue,iExtraHeaderList,lBinContent,iMailshotReturns lOk
    Else
        Do iSmtp.$init(iServerURI,iUser,iPassword,lFromAddress,lToList,lCcList,lBccList,iSubject,iPriorityList.iPriorityValue,iExtraHeaderList,lBinContent,iMailshotReturns lOk
    End If
Else
    If len(lFromDescription)
        Do iSmtp.$init(iServerURI,iUser,iPassword,row(lFromAddress,lFromDescription),lToList,lCcList,lBccList,iSubject,iPriorityList.iPriorityValue,iExtraHeaderList,lMIMElist,iMailshotReturns lOk
    Else
        Do iSmtp.$init(iServerURI,iUser,iPassword,lFromAddress,lToList,lCcList,lBccList,iSubject,iPriorityList.iPriorityValue,iExtraHeaderList,lMIMElist,iMailshotReturns lOk
    End If
End If
If not(lOk)
    OK message {$init error [iSmtp.$errorcode]: [iSmtp.$errortext]}
    Quit method kFalse
End If
If pRun
    Do iSmtp.$run() Returns lOk
Else
    Do iSmtp.$start() Returns lOk
End If
If not(lOk)
    OK message {$run error [iSmtp.$errorcode]: [iSmtp.$errortext]}
    Quit method kFalse
Else If not(pRun)
    Calculate $cinst.$objs.scrollbox.$objs.cancel.$enabled as kTrue
    Calculate $cinst.$objs.scrollbox.$objs.start.$enabled as kFalse
    Calculate $cinst.$objs.scrollbox.$objs.startthencancel.$enabled as kFalse
End If
Quit method kTrue

Callback methods

$completed

The standard $completed callback is passed a row variable parameter with the following columns:

Column Description
errorCode An integer error code indicating if the request was successful. Zero means success i.e. the message was successfully sent
errorInfo A text string providing information about the error if any
log If you used $protocollog to generate a log, this column contains the log data, either as character data, or UTF-8 HTML. Otherwise, the log column is empty

$mailshotprogress

If the request is a mailshot, and $callmailshotprogress is kTrue, the worker generates a notification to $mailshotprogress each time it sends (or fails to send) the message to a recipient. $mailshotprogress is passed a row variable parameter with the following columns:

Column Description
address The email address of the recipient.
sent Boolean, true if the message was successfully sent to this recipient

FTP Worker Object

The FTPClientWorker provides client FTP support, allowing you to transfer files. The following sections describe the FTP worker properties, constants and methods.

There is an FTP OW3 Worker Object example in the Samples section of the Hub in the Studio Browser.

Properties

The FTPClientWorker has the following properties in addition to the base worker properties described earlier:

Property Description
$requiresecureconnection If true, and the URI is not a secure URI, the connection starts as a non-secure connection which must be upgraded to a secure connection (using the STARTTLS command). If it cannot be upgraded then the request fails. Defaults to false
$keepconnectionopen If true, the worker can leave the connection to the server open when it completes its request. Defaults to false. Note that even when this property is set to true, a protocol error may cause the connection to close. Use true if you are likely to use the same server quite soon
$servercharset The character set used by the server to encode file names in commands and file lists. Default kUniTypeAuto (meaning UTF-8 if the server supports it or kUniTypeNativeCharacters if not). Otherwise a kUniType... constant for 8-bit character sets
$responsepath If not empty, the worker writes response content to the file with this path rather then adding it to the wResults row. The file must not already exist. The desired value must be set before calling $run or $start. Defaults to empty

Constants

The FTPClientWorker uses the following constants in addition to the base worker constants described earlier. These constants are all actions specified in the iAction parameter used with the $init method to indicate the action to perform, so this section should be read in conjunction with the section describing the $init method:

Constant Description
kOW3ftpActionPutFile Upload file data to file cServerPath on FTP server.
vParam is file data (binary, character or row).
Worker converts character to server character set.
Row must have one column (path of file containing data to upload).
Note that all file transfers use FTP binary mode
kOW3ftpActionPutFileMulti Upload multiple files to the FTP server. vParam is a 2 column list (col1: full local pathname, col2: full server pathname). cServerPath must be empty; see below
kOW3ftpActionAppendFile Identical to kOW3ftpActionPutFile except the action appends the file data to an existing file on the FTP server, or creates a new file containing the supplied data if the file does not exist on the FTP server
kOW3ftpActionGetFile Download file cServerPath from FTP server. Downloaded file data is either written to $responsepath (if not empty) or returned in the wResults row. vParam is not required.
Note that all file transfers use FTP binary mode
kOW3ftpActionGetFileMulti Download multiple files from the FTP server. vParam is a 2 column list (col1: full local pathname, col2: full server pathname). cServerPath must be empty; see below
kOW3ftpActionDelete Delete directory or file cServerPath from the FTP server. vParam is Boolean true if cServerPath is a directory, false if it is a file
kOW3ftpActionCreateDirectory Create directory cServerPath on the FTP server. vParam is not required
kOW3ftpActionListDirectory List the contents of directory cServerPath on the FTP server returned to wResults.resultList. vParam is Boolean true to list file names only (single column list), or false to get a detailed list with 8 columns: see below
kOW3ftpActionSetPermissions Set the permissions of file or directory cServerPath on the FTP server. vParam is a character string specifying the new permissions of the file or directory.
Note that not all servers support the SITE CHMOD command used by this
kOW3ftpActionExecute If cServerPath is not empty, CWD cServerPath.
Then execute FTP control connection commands in vParam.
vParam is either a character string or a single column list of commands. E.g. to rename a file, you could use:
RNFR oldname.txt
RNTO newname.txt
as two lines in the command list.
wResults.resultList has a row for each command response
kOW3ftpActionMove (Studio 11) Moves or renames a file on the FTP server. In this case, cServerPath in $init is the pathname of the file or directory to be moved. vParam is the new server path name. The action works with FTP, FTPS and SFTP (the latter uses a different command), and can be used to rename a file, or move it to a new location

Directory list for kOW3ftpActionListDirectory

FTP does not have a standard syntax for the data returned by the LIST command, so the FTP worker attempts to parse the results of the ListDirectory action, based on some typical syntaxes supported by many servers. The detailed list has 8 columns, as follows:

Uploading or downloading multiple files

When using kOW3ftpActionGetFileMulti or kOW3ftpActionPutFileMulti, to upload or download multiple files, the row passed to $progress has an extra column (requestNumber) which corresponds to the line number in the vParam list currently being transferred.

The $completed method is called with a successful status if all transfers are completed successfully. If at least one failed, the error code is 10312 (at least one transfer during a kOW3ftpActionGetFileMulti or kOW3ftpActionPutFileMulti action failed). In addition, the resultList column contains a list with a line for each transfer, containing error code, error info and FTP status code.

Methods

FTPClientWorker has the methods described in this section in addition to the base worker methods described earlier. $progress can be called for synchronous (as well as asynchronous) operations for the FTP worker.

Normal methods

$init

$init(cURIcUsercPasswordiActioncServerPath, vParam)

Called to prepare the object to execute a request, before calling $run or $start.

Returns Boolean true for success, or returns false and sets $errorcode and $errortext if an error occurs.

The parameters are:

Parameter Description
cURI The URI of the server, optionally including the URI scheme (ftp or ftps) e.g.
ftp://ftp.myserver.com.
If you omit the URI scheme
e.g. ftp.myserver.com
the URI scheme defaults to ftp
cUser The user name to be used to log on to the FTP server
cPassword The password to be used to log on to the FTP server
iAction A kOW3ftpAction… constant that specifies the action to perform
cServerPath A pathname on the FTP server. Paths are relative to the current working directory on the FTP server. The worker only changes directory if you supply a non-empty cServerPath parameter to kOW3ftpActionExecute, so unless you do this, paths are relative to the root.
After changing working directory, if you supply cServerPath prefixed with // then the path is relative to the root, e.g.
/myfile or
myfile
is a path relative to the current working directory, whereas
//myfile
is a path relative to the root.
vParam A parameter specific to the action. See the constant descriptions for details of vParam for each action

NOTE: If you call $init when a request is already running on a background thread, the object will cancel the running request, and wait for the request to abort before continuing with $init.

Example

You could create an FTP client window with various fields for FTP host name, username, password, timeout setting, server character set, and a list of FTP commands or actions as they are defined in the $init() method. A button could initiate the FTP command, executing the appropriate action depending on the one chosen by the end user, using the following code:

# start() method
# iFtp is an Object reference variable with the FTPClientWorker as Subtype
# iActionList (List) variable assigned to list of actions on the window
Do method setupLogging
Calculate iFtp.$timeout as iTimeout ## fields on the FTP window
Calculate iFtp.$callprogress as iCallProgress
Calculate iFtp.$keepconnectionopen as iKeepConnectionOpen
Calculate iFtp.$requiresecureconnection as iRequireSecureConnection
Calculate iFtp.$servercharset as iServerCharsetList.C2
Calculate iFtp.$responsepath as iResponsePath
If iActionList.C2=kOW3ftpActionPutFile.C2=kOW3ftpActionAppendFile
    If iSendContentMode=0
        ReadBinFile (iContentPath,iContent)
        Do iFtp.$init(iServerURI,iUser,iPassword,iActionList.C2,iServerPath,iContentReturns lOk
    Else
        Do iFtp.$init(iServerURI,iUser,iPassword,iActionList.C2,iServerPath,row(iContentPath)) Returns lOk
    End If
Else If iActionList.C2=kOW3ftpActionSetPermissions
    Do iFtp.$init(iServerURI,iUser,iPassword,iActionList.C2,iServerPath,iPermissionsReturns lOk
Else If iActionList.C2=kOW3ftpActionExecute
    Do iFtp.$init(iServerURI,iUser,iPassword,iActionList.C2,iServerPath,iCommandListReturns lOk
Else If iActionList.C2=kOW3ftpActionListDirectory
    Do iFtp.$init(iServerURI,iUser,iPassword,iActionList.C2,iServerPath,iNamesOnlyReturns lOk
Else If iActionList.C2=kOW3ftpActionDelete
    Do iFtp.$init(iServerURI,iUser,iPassword,iActionList.C2,iServerPath,iPathIsDirectoryReturns lOk
Else
    Do iFtp.$init(iServerURI,iUser,iPassword,iActionList.C2,iServerPathReturns lOk
End If
# then $run or $start is called
If not(lOk)
    OK message {$init error [iFtp.$errorcode]: [iFtp.$errortext]}
    Quit method kFalse
End If
If pRun
    Do iFtp.$run() Returns lOk
Else
    Do iFtp.$start() Returns lOk
End If
If not(lOk)
    OK message {$run error [iFtp.$errorcode]: [iFtp.$errortext]}
    Quit method kFalse
Else If not(pRun)
    Calculate $cinst.$objs.scrollbox.$objs.cancel.$enabled as kTrue
    Calculate $cinst.$objs.scrollbox.$objs.start.$enabled as kFalse
    Calculate $cinst.$objs.scrollbox.$objs.startthencancel.$enabled as kFalse
End If
Quit method kTrue

Callback methods

$completed

The standard $completed callback is passed a row variable parameter with the following columns:

Column Description
errorCode An integer error code indicating if the request was successful. Zero means success i.e. the message was successfully sent
errorInfo A text string providing information about the error if any
ftpResponseCode The FTP response code from the last FTP command executed when performing the action. An integer
fileData Used for kOW3ftpActionGetFile only. If you have not used $responsepath to write the file data directly to a file, this is a binary column containing the file data received from the server
resultList For kOW3ftpActionList:
A single character column list, containing the list entries received from the server.
For kOW3ftpActionExecute:
A 2 column list, containing an entry for each command supplied in vParam that was successfully executed. Command execution stops as soon as a command fails; the status of the failed command becomes the main error information in the row passed to $completed.
Each row of the list contains the ftpResponseCode for the command, and the response text that was received from the server
log If you used $protocollog to generate a log, this column contains the log data, either as character data, or UTF-8 HTML. Otherwise, the log column is empty
Example

Following on from the $init example above, you could create code in the $completed method to handle the response from the FTP server returned in the pResults parameter: the code writes the log to an HTML file and displays it in the oBrowser object.

# $completed method
Calculate iResponse as pResults
Calculate iErrorCode as pResults.errorCode
Calculate iErrorText as pResults.errorInfo
If iUsingLogBrowser
    Do FileOps.$deletefile(iLogHTMLPath)
    WriteBinFile (iLogHTMLPath,iResponse.log)
    Calculate iLogBrowser.$urlorcontrolname as con("file://",replaceall(iLogHTMLPath," ","%20"))
Else
    Calculate iLog as iResponse.log
End If
Do $cinst.$redraw()
Calculate $cinst.$objs.tabpane.$currenttab as 3

Secure FTP (SFTP)

The FTP Worker Object supports Secure FTP (SFTP). There are some differences in functionality when using SFTP:

In addition, there are some properties and methods, primarily related to how a connection is authenticated. SFTP does not use TLS, so the secure options related to that only affect FTPS and FTP connections to be upgraded to TLS.

The FTP worker object has the properties:

The FTP worker object has the methods:

Some or all of the SSH options may be optional, depending on the authentication type chosen.

Keys

When using SFTP, the public and private keys need to be in OpenSSH format. If you have a differently formatted key, such as SSH2 from RFC4716, perhaps generated with PuTTY, you can convert the key using a terminal.

For example, converting a public key with ssh-keygen:

ssh-keygen -i -f [path to .pub key]

will print out the OpenSSH-format public key which can be copied into its own new .pub file.

Converting a private .ppk key:

puttygen [path to .ppk key] -O private-openssh -o [path to new .pem file]

will convert the .ppk key generated from PuTTY to a private OpenSSH-format private key.

IMAP Worker Object

The IMAPClientWorker provides client IMAP support, allowing you to use the worker to manage emails stored on an IMAP server. The following sections describe the IMAP worker properties, constants and methods.

There is an IMAP OW3 Worker Object example in the Samples section of the Hub in the Studio Browser.

Properties

The IMAPClientWorker has the following properties in addition to the base worker properties described earlier:

Property Description
$requiresecureconnection If true, and the URI is not a secure URI, the connection starts as a non-secure connection which must be upgraded to a secure connection (using the STARTTLS command). If it cannot be upgraded then the request fails. Defaults to false
$keepconnectionopen If true, the worker can leave the connection to the server open when it completes its request. Defaults to false.
Note that even when this property is set to true, a protocol error may cause the connection to close. Use true if you are likely to use the same server fairly soon
$splitfetchedmessage If true, the worker splits the fetched message into headers and a MIME list for any content. Defaults to true. If false, the worker simply returns the raw fetched message data
$defaultcharset Used when kOW3imapActionFetchMessage splits the message, and no character set is specified for a MIME text body part. The character set used to convert to character. Default kUniTypeUTF8. A kUniType... constant (not Character/Auto/Binary)
$removemessageid If true, the worker removes the Message-id header from the message when performing the action kOW3imapActionAppendMessage. Defaults to true.
Duplicating message ids may cause the IMAP server to discard messages with duplicate ids, hence this property
$oauth2 An object reference to an OAUTH2Worker object containing the authorization information required to make requests to the server: see OAUTH2 Worker Object
$ignoreflags When set to true, any errors generated by failure of parsing the FLAGS from an IMAP FETCH server message will be ignored. This means you could still retrieve all your emails if the only issue with your IMAP server was that IMAP adds FLAGS after the headers rather than being part of the FETCH response; however you will of course be missing the flags, if they couldn't be parsed.
$ignoreflags defaults to false which means the FLAGS in the IMAP FETCH RESPONSE are only accepted when within initial header.

Constants

The IMAPClientWorker uses the following constants in addition to the base worker constants described earlier. These constants are all actions used with the $init method to indicate the action to perform, so this section should be read in conjunction with the section describing the $init method:

Constant Description
kOW3imapActionListMailboxes List mailboxes in reference name cMailboxName.
vParam1 specifies the names to list. This becomes the “mailbox name with possible wildcards” parameter of the IMAP LIST or LSUB command (see RFC 3501).
vParam2 (optional, default false) is Boolean true to list subscribed mailboxes only
kOW3imapActionListMessages Selects mailbox cMailboxName and lists the messages it contains.
vParam1 (optional), if present, it is a single column list of additional mail header names to retrieve in addition to the standard mailbox list information e.g. the list could have 2 rows, “Subject” and “X-Priority” to retrieve the message subject and priority for each message.
vParam2 (optional) is an IMAP search query selecting messages to list, e.g. UNSEEN to fetch the unread messages
kOW3imapActionFetchMessage Selects mailbox cMailboxName and fetches the message with UID vParam1.
vParam2 (optional, default false) is Boolean true to fetch message headers only
kOW3imapActionSetMessageFlags Selects mailbox cMailboxName and sets flags for message with UID vParam1.
vParam2 is a row of flags with values kFalse, kTrue or kUnknown (leave flag unchanged):
row(answered, deleted, draft, flagged, seen)
kOW3imapActionAppendMessage Selects mailbox cMailboxName and appends a message to the mailbox.
You can either:
Supply the entire message as binary data in vParam1 or
Supply a 2 character column list in vParam1 (columns are header name and header value) with binary raw content in vParam2
or
Supply a 2 character column list in vParam1 (columns are header name and header value) with the content specified by a MIME list in vParam2. See the documentation for the MailSplit command to see how a MIME list is structured; however note that the charset in the worker MIME list is a kUniType... constant rather than a character string
kOW3imapActionExecute If cMailboxName is not empty select mailbox cMailboxName.
Then execute IMAP commands in vParam1. vParam1 is either a binary value or a single column list of binary values. wResults.resultList has a row for each command response.
Each binary value is an IMAP command to execute, e.g. EXAMINE. You can generate binary values using the correct character set required by the IMAP protocol using the $chartoutf7 method of the IMAPClientWorker.
The sequence of actions will stop as soon as an error occurs
kOW3imapActionSelect (Studio 11) Executes an IMAP SELECT on the mailbox given to $init. As part of the SELECT, IMAP returns the number of emails in the mailbox, which are returned to the $completed method in resultList in column EXISTS. Note that an IMAP SELECT will cause the current mailbox to be changed, so you may prefer to execute this action on a different connection

Methods

IMAPClientWorker has the methods described in this section in addition to the base worker methods described earlier.

Normal methods

$init

$init(cURIcUsercPasswordiActioncMailboxName, vParam1, vParam2)

Called to prepare the object to execute a request, before calling $run or $start.
Returns Boolean true for success, or returns false and sets $errorcode and $errortext if an error occurs.

The parameters are:

Parameter Description
cURI The URI of the server, optionally including the URI scheme (imap or imaps), e.g. imap://ftp.myserver.com. If you omit the URI scheme, e.g. imap.myserver.com, the URI scheme defaults to map
cUser The user name to be used to log on to the FTP server
cPassword The password to be used to log on to the FTP server
iAction A kOW3imapAction… constant that specifies the action to perform
cMailboxName The IMAP mailbox name (ignored for kOWEimapActionListMailboxes). If you are using non-ASCII characters in mailbox names, you may need to normalise the name using the Omnis nfd() or nfc() function before passing it to $init()
vParam1 A parameter specific to the action. See the constant descriptions for details of vParam1 for each action
vParam2 A parameter specific to the action. See the constant descriptions for details of vParam2 for each action

NOTE: If you call $init when a request is already running on a background thread, the object will cancel the running request, and wait for the request to abort before continuing with $init.

$chartoutf7

$chartoutf7(cChar)

Returns a binary value (containing 7 bit characters) that is the IMAP UTF-7 representation of cChar (note that IMAP uses a special variant of UTF-7, and this method generates that variant).

The parameters are:

Parameter Description
cChar A character string to be converted to IMAP UTF-7

$utf7tochar

$utf7tochar(xUtf7[,bAllowCRLF=kTrue])

Converts IMAP UTF-7 xUtf7 to character and returns the result. Optionally allows CRLF sequences in the data and replaces them with CR in the result (note that IMAP uses a special variant of UTF-7, and this method expects that variant in xUtf7).

The parameters are:

Parameter Description
xUtf7 A binary value containing IMAP UTF-7 to be converted to character.
bAllowCRLF If true, CRLF sequences are to be expected in the UTF-7 stream - they are replaced with CR.

Callback methods

$completed

The standard $completed callback is passed a row variable parameter with the following columns:

Column Description
errorCode An integer error code indicating if the request was successful. Zero means success i.e. the message was successfully sent
errorInfo A text string providing information about the error if any
resultList This column receives a list, the content of which depends on the action. The action-specific lists returned here are described below (actions kOW3imapActionSetMessageFlags and kOW3imapActionAppendMessage do not return any data in this column)
log If you used $protocollog to generate a log, this column contains the log data, either as character data, or UTF-8 HTML. Otherwise, the log column is empty
<action-specific> Column 5 is present for certain actions, and contains action- specific data. The action-specific data is described below

kOW3imapActionListMailboxes:

Column Description
resultList The list of mailboxes that match the criteria pass to $init(). A 7 column list, with columns as follows (see RFC 3501 for more details - the data in these columns is populated using the LIST or LSUB response):
hasChildren: Boolean true if the mailbox has child mailboxes.
noInferiors: Boolean true if it is not possible for any child levels of hierarchy to exist under this name; no child levels exist now and none can be created in the future.
noSelect: Boolean true if it is not possible to use this name as a selectable mailbox.
marked: Boolean true if the mailbox has been marked "interesting" by the server; the mailbox probably contains messages that have been added since the last time the mailbox was selected.
unMarked: Boolean true if the mailbox does not contain any additional messages since the last time the mailbox was selected.
separator: The mailbox hierarchy delimiter.
mailboxName: The name of the mailbox
<action‑specific> No action specific column

kOW3imapActionListMessages:

Column Description
resultList The list of messages in the mailbox. This is a list with 9 standard columns, followed by a column for each header specified in vParam2 when calling $init() to prepare for this action. The additional header columns are named by removing - characters from the header name, and converting the result to lower case.

The 9 standard columns in the message list are:
UID: The unsigned integer UID of the message
size: The size of the message in bytes
internalDate: The internal date of the message.
answered: The Boolean answered flag for the message.
deleted: The Boolean deleted flag for the message.
draft: The Boolean draft flag for the message.
flagged: The Boolean flagged flag for the message.
recent: The Boolean recent flag for the message.
seen: The Boolean seen flag for the message.
<action‑specific> No action specific column

kOW3imapActionFetchMessage:

Column Description
resultList If $splitfetchedmessage is kFalse, this column is not populated. Otherwise, this column is a 2 character column list of mail headers:Column 1 is the header name.
Column 2 is the header value
<action‑specific> If the action fetches the message content as well as the headers, this column receives the content. It is either:
rawData: A binary column that receives the un-split fetched message data
or
mimeList: A MIME list containing the content. See the documentation for the MailSplit command to see how a MIME list is structured; however note that the charset in the worker MIME list is a kUniType... constant rather than a character string

kOW3imapActionSetMessageFlags:

Column Description
resultList Not populated.
<action‑specific> No action specific column.

kOW3imapActionAppendMessage:

Column Description
resultList Not populated
<action‑specific> If possible, the action extracts the UID of the appended message from the IMAP server response. The UID is returned to this column (named UID) and is non-zero if the UID could be extracted. (Note that not all servers return the UID of an appended message)

kOW3imapActionExecute:

Column Description
resultList A single column list of binary values. Each row of the list contains the sequence of responses returned from the server when executing the corresponding command in the list (or single binary value) passed to $init(). You would typically decode this using $utf7tochar, using the option to expect CRLF and replace with CR
<action‑specific> No action specific column

JavaScript Worker Object

The JavaScript Worker Object allows you to execute JavaScript methods inside node.js by making the request in Omnis code by calling a Worker Object method, and receiving the results via a worker callback. The node.js framework is embedded into Omnis Studio, and contains many open source third-party modules that can be used from inside your Omnis code. All traffic sent between the Omnis and node.js processes is encrypted. For example, the library ‘xml2js’ is included in Omnis Studio, which converts XML to JSON: in addition, support for ZIP can be added using the node.js jszip module, which is described at the end of this section.

There is a JS Worker example in the Samples section of the Hub in the Studio Browser.

NPM

Npm is provided alongside Node.js in Omnis Studio. Npm (Node Package Manager) is a free registry and library for JavaScript packages, and is the standard package manager for node.js. Npm provides command-line tools to help you install packages and manage their dependencies. To launch npm you can run index.js inside the npm folder, e.g.

./node npm/index.js

NPM

Npm (Node Package Manager) is a free registry and library for JavaScript packages, and is the standard package manager for node.js. Npm provides command-line tools to help you install packages and manage their dependencies. Npm is provided alongside Node.js in Omnis Studio.

On Windows and Linux the nodejs folder is installed within clientserver\server. On macOS the nodejs folder is installed within Resources and the node executable is installed in Helpers.

To launch npm on Windows and Linux, you can run index.js inside the npm folder, e.g.

./node npm/index.js

On macOS, if inside the npm folder, use the relative path to the node binary, e.g.

../../Helpers/node npm/index.js

Enabling JavaScript Methods

There is a JS file, ow3javascript.js, located in the clientserver/server/remotedebug program folder, that is the entry point for all method calls: on macOS, the remotedebug folder is in the Resources folder in the Omnis.app bundle.

There is a JS file, ow3javascript.mjs, located in the jsworker/_system data folder, that is the entry point for all method calls.

Method calls arrive as an HTTP request from Omnis, and respond with their results as HTTP content. The worker executes methods sequentially, but in a separate process.

Omnis has a simple structure where you can write a JavaScript module containing one or more methods, and then call methods via their module and method name.

In the Omnis data folder, there is a folder called ‘jsworker’, where modules required by ow3javascript.js are located. You can install additional node.js modules in this folder using the npm -i command when running in the folder - these might be modules for which you want to provide an interface from Omnis.

There are two key files in this folder, which must always be present:

There are also two example module files, omnis_test and omnis_zip. These provide Omnis modules named 'test' and 'omnis_zip'. Each module file must have an entry in omnis_modules.js (or be automatically loaded). Each module file provides a table of methods that can be called from Omnis.

Note that ‘jsworker’ in the data folder may not be considered suitable for deployment, since the data folder is writeable. The worker provides the ability for you to structure things differently when you deploy your application, but is fine for development.

Auto Loading modules

From Studio 11, the JS Worker will pick up any modules you have added automatically if they are placed in the jsworker folder. Any modules that you have added in their own folder, with a package.json or index.js, are picked up automatically by the JS Worker. (This is in addition to using the hard-coded moduleMap method, as described below.)

Modules may also be automatically loaded from any of the module load paths passed to the worker's $init method.

Creating Modules

Modules must be created in CommonJS format.

Modules may be created in either CommonJS or ES Module formats. Note that ES Modules should use the .mjs extension on their main file to identify themselves as an ES Module.

It is recommended that you use the more modern ES Module format.

The only requirement of a module is that it exports a default object containing a function named "call", which receives parameters: (method, param, response).

This function should handle the calling of your module's method(s), and sending a response to Omnis, using the methods available in the omnis_calls module.

You can use a default implementation of this, which should cover most use cases, and allow you to use async functions:

export default omnis_calls.omnisModuleDefaultExport(methodMap);

You just need to return your result value from your methods in this case.

See the omnis_test example module for the recommended way of implementing this.

Creating the worker

The sub-type of the external object is OW3 Worker Objects\JAVASCRIPTWorker. You can use either an Object variable or an Object Reference variable, either directly if you set $callbackinst to receive results, or by subclassing the external object with an Omnis object.

Properties

The JavaScript worker only has the standard worker properties: $state, $threadcount, $errorcode and $errortext.

Methods

Called Methods

$init()

$init([cPath, bDebugNodeJs=kFalse])

Initialize the object so it is ready to execute JavaScript method calls. Returns true if successful. You must call $init() before any other methods.

$start()

$start()

Runs the JavaScript worker in a background thread. Returns true if the worker was successfully started.

After you call $start(), the background thread starts up a node.js process which will process JavaScript method calls. You can make multiple method calls to the same process, so there is no need to call $start() frequently, which means the overhead of starting the node.js process is minimal.

$cancel()

$cancel()

Use this to terminate the node.js process. Any in-progress method calls may not complete.

$callmethod()

$callmethod(cModulecMethod, vListOrRow [,bWait=kFalse, &cErrorText, vTag])

Call the method passing it a single parameter which is the JavaScript object representation of vListOrRow. Optionally wait for the method to complete. Returns true if successful.

Callback Methods

$cancelled

Override this to receive a notification that the request to cancel the worker has succeeded.

$workererror

$workererror(wError)

Override this method to receive reports of errors from the worker that are not related to calling a method, e.g. failure to start node.js. The worker thread exits after generating this notification.

$methoderror

$methoderror(wError)

Override this method to receive reports of the failure of an attempt to call a method with $callmethod.

If an unhandled exception occurs causing node.js to exit, Omnis adds the stack traceback of the exception to the errorInfo column.

$methodreturn

$methodreturn(wReturn)

Method called with the results of a call to $callmethod.

If the JavaScript method returns an object, this is the Omnis equivalent of the object, created by converting the JSON to a row. If the JavaScript method returns some other data, e.g. a picture, this is a row with a single column named content, which contains the data returned by the method.

The content column for non-JSON content returned from a worker method is of type character when the content type is text/.

Example: Adding ZIP support

You could add support for ZIP files. To do this, install the node.js jszip module by running the npm command in the jsworker folder (the npm command is installed with node.js):

npm i jszip

Edit omnis_modules.js by adding an entry to the 'moduleMap' object for the zip module (or from Studio 11 it should be loaded automatically since it is in its own folder ‘omnis_zip’):

const moduleMap = {
  zip: require('./omnis_zip.js'),
  ... // Other modules
};

You can then make calls from Omnis code as follows:

Do lRow.$cols.$add("path",kCharacter,kSimplechar)
Calculate lRow.path as iZipPath
Do iJS.$callmethod("zip","loadZip",lRow,kTrue,lErrorTextReturns lOK

POP3 Worker Object

The POP3 OW3 Worker Object allows you to manage and retrieve emails stored on a POP3 Server using a background thread asynchronously, thereby giving the user full use of your app whilst carrying out the task.

The POP3 worker is similar to other OW3 workers, in that you pass an action to $init and action specific parameters, and use $run or $start to execute the request.

There is a POP3 OW3 Worker Object example in the Samples section of the Hub in the Studio Browser.

Methods

$init()

$init(cURIcUsercPasswordiAction [,iMessageNumbercPostCommand])

Initialises the object so it is ready to perform the specified action using POP3. Returns true if successful

The $init parameters are:

Parameter Description
cURI The URI of the server, optionally including the URI scheme (pop3 or pop3s) e.g. pop3://pop3.myserver.com. If you omit the URI scheme, e.g. pop3.myserver.com, the URI scheme defaults to pop3
cUser The username to be used to log on to the POP3 server
cPassword The password to be used to log on to the POP3 server
iAction A kOW3pop3Action... constant that specifies the action to perform; see below
iMessageNumber The message number to get (applies to actions kOW3pop3ActionGetMessage, kOW3pop3ActionGetHeaders and kOW3pop3ActionDeleteMessage)
cPostCommand Only applies to action kOW3pop3ActionGetMessage. If not empty, a command to send to the server after getting the message. This would typically be RSET to undelete messages or QUIT to delete messages

The Actions are:

Properties

The OW3 POP3 worker has the following properties in addition to those supported by all OW3 worker objects:

Property Description
$splitfetchedmessage If true, worker splits fetched message into headers and MIME list for any content. Defaults to true. If false, the worker simply returns the raw fetched message data (Applies to kOW3imapActionFetchMessage and kOW3pop3ActionGetMessage)
$defaultcharset Used by kOW3imapActionFetchMessage and kOW3pop3ActionGetMessage when there is no charset for a MIME text body part. The charset used to convert to character. Default kUniTypeUTF8.A kUniType... constant (not Character/Auto/Binary)
$keepconnectionopen If true, the worker can leave the connection to the server open when it completes its request. Defaults to false. Note that even when this property is set to true, a protocol error may cause the connection to close.
$requiresecureconnection If true, and the URI is not a secure URI, the connection starts as a non-secure connection which must be upgraded to a secure connection (using STARTTLS or STLS). If it cannot be upgraded, then the request fails. Defaults to false
$oauth2 An object reference to an OAUTH2Worker object containing the authorization information required to make requests to the server: see OAUTH2 Worker Object

CRYPTO Worker Object

The CRYPTO Worker Object allows you to perform encryption and decryption of data. The encryption types you can use include AES, Camellia, DES, and Blowfish.

The CRYPTO worker is similar to other OW3 workers, in that you pass an action to $init and action specific parameters, and use $run or $start to execute the request.

There is a CRYPTO OW3 Worker Object example in the Samples section of the Hub in the Studio Browser.

To use the worker object, create a variable with its subtype set to the CRYPTOWorker object which is contained in the OW3 Worker Objects group in the Select Object dialog, or subclass the external object. For encryption of data over 2GB you are advised to write the encrypted data to a file, rather than memory.

Methods

The CRYPTO worker has the following methods:

As with the other worker objects you can use the $init method with various input parameters to initialize the object, while the action can be to Encrypt or Decrypt:

iAction can be either:

iEncryptionType can be one of:

iCipherMode can be one of:

iPadding can be one of:

Note that PKCS7 is the most common and allows binary data to be correctly decrypted, for example, kOW3cryptoPaddingZeros can lead to extra bytes being stripped from decrypted binary data.

xKey is a binary containing the key. See the encryption types for details of supported key lengths.

xIV is a binary containing the Initialization Vector (IV) (random data that can be used to make the same encrypted data different when using the same key). This must be 8 bytes long for DES and Blowfish, and 16 bytes long for AES and Camellia.

vInputData is the data to be encrypted. Either a character value which is the pathname of the file containing the data to encrypt or decrypt, or a binary variable containing the data to encrypt or decrypt.

cOutputPath is:

The results row passed to $completed has 3 columns: errorCode, errorInfo and data. The error columns behave in the same way as the other OW3 workers: note that a negative error code is a code returned by the mbedTLS library. The data column is only used when cOutputPath was omitted when calling $init.

Properties

The CRYPTO Worker has properties as follows:

HASH Worker Object

The HASH Worker Object allows you to hash data using SHA1, SHA2, SHA3, MD5, and RIPEMD hash types, which are primarily for signature purposes, while PBKDF2 is available for password hashing.

There is a Hash OW3 Worker Object example in the Samples section of the Hub in the Studio Browser.

You use the $inithash() method to initialise the object, passing the binary or character data to be hashed, and the hash type represented by a constant, as follows:

Constant Hash type
kOW3hashSHA1 SHA1
kOW3hashSHA2_256 SHA2 including hash output 256
kOW3hashSHA2_384 SHA2 including hash output 384
kOW3hashSHA2_512 SHA2 including hash output 512
kOW3hashSHA3_256 SHA3 including hash output 256
kOW3hashSHA3_384 SHA3 including hash output 384
kOW3hashSHA3_512 SHA3 including hash output 512
kOW3hashMD5 MD5
kOW3hashRIPEMD_160 RIPEMD_160
kOW3hashPBKDF2 PBKDF2

You can use $initverifyhash to verify or compare some data against previously hashed data generated using $inithash. Having called the $init… methods, you can use $run or $start to execute the request.

To use the worker object, create a variable with its subtype set to the HASHWorker object which is contained in the OW3 Worker Objects group in the Select Object dialog, or subclass the external object.

The HASH worker object has the following methods:

HMACs

HMACs can be generated for all hash types, except PBKDF2 and the SHA3 hashes, instead of a hash. The key length for an HMAC is unrestricted (in versions prior to Studio 10.22 key length was restricted to 64 characters).

To generate an HMAC rather than a hash, supply the binary key as the hash parameters parameter of $inithash() – an empty row as this parameter generates a hash rather than HMAC. To verify an HMAC rather than a hash, supply the binary key as a new binary last parameter to $initverifyhash() – this is optional and its presence indicates HMAC.

Results

After calling one of the $init… methods, you call $run or $start. The results row passed to $completed has 3 columns: errorCode, errorInfo and data. The error columns behave in the same way as the other OW3 workers - note that a negative error code is a code returned by the mbedTLS library. The data column is only used for $inithash() and it contains the generated binary hash, provided that no error occurred – you may want to convert this to base64 before storing it, but note that if you do this you will need to convert it back to binary before using it to verify data. For $initverifyhash(), the errorCode is zero if and only if the hash was successfully verified.

The worker has properties as follows:

 

LDAP Worker Object

Lightweight Directory Access Protocol (LDAP) allows “the sharing of information about users, systems, networks, services, and applications throughout the network” (Wikipedia). The LDAP Worker is available in the OW3 group of worker objects, and is named LDAPClientWorker.

To use the LDAP Worker, you should create an Object variable or an Object Reference variable and set its subtype to the LDAPClientWorker object in the Select Object dialog; or you can create an Object class, set its superclass to the LDAPClientWorker object, create an Object variable or an Object Reference variable and set its subtype to the object class.

There is an example library which you can request from your local Support office.

There is an example app called LDAP Client Worker Object in the Samples section in the Hub in the Studio Browser.

Properties

The LDAP Worker has all the base worker properties plus $callbackinst and $keepconnectionopen.

Methods

The LDAP Worker has all the base worker methods.

You can use the $init method to initialize the worker object to specify what information is to be returned from the LDAP server; $init for the LDAP Worker has the following definition:

$init(cURI,cUser,cPassword

Initializes the object so it is ready to access the specified URI using LDAP, and returns true if successful. It has the following parameters:

To structure the URI of the LDAP server, you will need to find out what parameters are required by the server; you may find the RFC4516 standard useful which defines the syntax of LDAP URLs: https://docs.ldap.com/specs/rfc4516.txt.

As $init() is called, the details of what is to be retrieved from the server are passed in the URL. You can then call $run() or $start() to run the request on the main thread or a background thread.

When the query completes, the worker calls the $completed method in the usual way for OW3 workers. The row passed to $completed has four columns:

errorCode: Zero for success, otherwise an error code

errorInfo: The description of the error

log: If you enabled logging for the OW3 worker, this contains the log

rawData: If successful, the result of the LDAP query. The developer is currently responsible for parsing this.

Python Worker Object

The Python Worker Object works exactly like the JavaScript worker, including support for HTTP/2, with a few exceptions, as follows.

The $init method has only one parameter instead of two, since Omnis does not support the remote debugger capabilities in Python.

The $init method of the Python worker accepts a second optional parameter, cExecutable, which is a character variable containing the path to the Python executable to use, overriding the default location of the Python executable. Without the parameter the Python worker looks in /usr/bin/python3 for the Python executable.

When passing rows to the Python worker, a dictionary object is created in your Python module. When passing lists, a list object is created.

There is an example library which you can request from your local Support office.

There is an example library for the Python Worker under the Samples section in the Hub in the Studio Browser.

Installation

The Python executable is not provided with Omnis Studio, so you will have to install it manually alongside pip (the package manager) on your chosen platform. The Python worker will work with python3 only and ideally you should use at least Python 3.6. Get the latest download and installation notes for different platforms from: https://www.python.org/

On Linux and macOS, Omnis expects the binary to be in /usr/bin/python3 as well as on the PATH. On Windows, Omnis expects the installation to also be in the PATH as it relies on loading the python3.dll to get the directory where Python is installed and use the python.exe within. Currently, you cannot specify a path to a different python executable to use.

In addition, flask, psutils and requests are required; these are listed in a file called requirements.txt which is in the pyworker folder in the Omnis read/write directory. You can either install them manually or by doing:

/usr/bin/python3 -m pip install -r path/to/file/requirements.txt

Setting up a Python worker

Navigate to the writable directory of your Omnis Studio installation, typically located inside the AppData folder on Windows or the Application Support folder on macOS. On Linux, the writable and read-only directories are the same. Look for a folder named pyworker. This is where all the modules that can be used with the Python Worker will be installed.

Create a new folder inside pyworker and name it after your module. The folder's name will be used to identify your module when calling its methods through the Python Worker from Omnis Studio. For example, if your module is named test_module, create a folder named test_module inside the pyworker directory.

Inside your module's folder, you need to set up a main.py file which will be loaded by the Python Worker. The main.py file is where you can define your functions and import other packages - the Python Worker will automatically load this file and you can call the methods from Omnis Studio. For example, you can create a test function in main.py in the following way:

from omnis_calls import sendResponse, sendError

def test(param):
    return sendResponse({'unicode': 'Fingerspitzengef\xFChl is a German term.\nIt\u2019s pronounced as follows: [\u02C8f\u026A\u014B\u0250\u02CC\u0283p\u026Ats\u0259n\u0261\u0259\u02CCfy\u02D0l]'})

Calling Python methods

Create a new object variable and inherit from the Python Worker, grouped under the OW3 Worker Objects in the Select Object dialog. For more control, you might prefer to create a new object class in your library and inherit from the Python worker through the $superclass property.

Once you have an object or an object reference to the Python Worker, you need initialize and then start the worker:

Do pyWorker.$init(,'/path/to/python3')
Do pyWorker.$start() Returns #F

A new thread will be launched upon calling $start where the Python process will wait until you give it methods to execute. Furthermore, you only need to call $start as you can make multiple method calls to the same worker.

The first parameter to $init takes the search path, which is usually best to leave as the default. The second parameter however is very useful: you can use it to specify the exact Python executable you wish to use. Please note whichever Python executable you try to use, it will need to have the packages from the requirements file installed, otherwise it will fail to start.

If the second parameter to $init is omitted, the default will be /usr/bin/python3 on Linux and macOS. On Windows, Omnis attempts to load the python3.dll which works if it's available in the PATH, then will try loading the python3.exe in the same directory as the python3.dll.

To avoid failures when starting the Python Worker, you are advised to point the Worker to your python3 executable through the second parameter to $init.

If your Python worker has started successfully, you can use $callmethod(cModule, cMethod) where cModule is the name of the module you wish to use and cMethod is the name of the method inside your module you want to execute:

Do pyWorker.$callmethod('omnis_test', 'test') Returns #F

Parameters passed to the Python worker are in the form of a list or row. You can pass the list or row in the $callmethod:

Do lRow.$cols.$add('message',kCharacter,kSimplechar)
Do lRow.$assigncols('hello world')
Do pyWorker.$callmethod("omnis_test","test",lRowReturns #F

In order to access parameters on the Python module side, use the param parameter of your method (in main.py):

from omnis_calls import sendResponse, sendError

def test(param):
    return sendResponse(param['value'])

Note Omnis rows will create a Python dictionary param and Omnis lists will create a Python list param.

When the Python Worker returns, the $methodreturn callback is called with a row parameter. Inside the row parameter, you can find the returned data from your method as well as any tags supplied to $callmethod. For example, calling the test method in the omnis_test module will result in Unicode characters to be returned inside the unicode column in the first row parameter of $methodreturn.

If you have called a Python method but wish to cancel it, use the $cancel method on the Python worker:

Do pyWorker.$cancel()

Cancelling a call might be useful if you think it has been running for too long and wish to stop it.

The $callmethod is asynchronous by default, but there might be times where you wish to block the main thread until the Python Worker finishes its job, in which case you can pass kTrue to the bWait parameter of $callmethod (4th parameter):

Do pyWorker.$callmethod('omnis_test','test',,kTrueReturns #F

The same Python Worker instance can be used for multiple method calls since Python methods can be made asynchronous, as such it may be useful to tag each call with an identifiable number. The 6th parameter of $callmethod can accept a tag which will be returned in the $methodreturn:

Do pyWorker.$callmethod('omnis_test','test',,,,lTagIDReturns #F

A __tag column is added to the row parameter of $methodreturn if a tag was given to $callmethod, allowing you to identify the results.

Error handling

If your Python method throws errors when executing, the $methoderror callback is called with a row parameter which contains two columns which you can use to debug your Python method:

If the Python Worker has failed to start, the $workererror callback is called with a row parameter which contains two columns:

These errors are unlikely to be caused by the method called, but more likely issues with Python itself, e.g. quitting due to missing packages.

If you inherited your Python Worker, you can simply override callbacks in your new object. Otherwise, if you created a new variable with the object type of OW3 Python Worker, you will need to register the instance that will receive the callbacks such as $methoderror, $workererror, and $methodreturn. You can do this by assigning the instance to the $callbackinst property, for example:

Do pyWorker.$callbackinst.$assign($cinst)

This will assign the callback instance to $cinst (current instance). If $cinst is a window, then that window class must implement the methods $methoderror, $workererror, and $methodreturn.

Java Worker Object

The Java Worker allows you to invoke methods inside Java modules. There is a Java Worker example in the Samples section in the Hub in the Studio Browser.

Installation

Java is not installed with Omnis Studio, therefore you will have to install it separately. Java version 17 was used to implement the Java Worker, more specifically the Adoptium implementation, but any Java implementation (including Oracle's) should work with the Omnis Java Worker.

Methods

The $init method initializes the Java Worker and is the only method that differs from the other existing worker base methods.

$init([cPath,cExecutable,bDebugWorker,cJvmOptions])

Initializes the Java Worker and returns kTrue if successful, otherwise kFalse is returned.

Properties

The Java Worker has the same base properties as the existing workers.

Main module file structure

The javaworker folder in the clientserver/server folder in the Omnis read/write location (Application Support on macOS or AppData on Windows) contains the Java Worker files:

<read/write location>/clientserver/server/javaworker

which contains:

User module file structure

The javaworker folder in the root of the Omnis read/write location (Application Support on macOS or AppData on Windows) contains:

Each new module needs to be placed inside its own folder, inside the javaworker folder, at the root of the read/write location. If your module has dependencies that are not shared with other modules, you should also create a lib folder inside your module's folder and place the dependencies there.

You can place common module dependencies in the lib folder at the root of the javaworker folder.

When Omnis starts the Java process, each module folder and its lib subfolder are added to the CLASSPATH, alongside the main lib folder. This means that your module's lib subfolder contents will be visible to other modules, therefore the separation is purely for maintaining a clean file structure.

Building Java Modules

When creating a new Java module to use with the Java Worker, you will need to first create a Java project. Visual Studio has an extension that assists with this, see more here:

https://code.visualstudio.com/docs/java/java-tutorial

The Maven build tool was used to create the Java Worker. More specifically, the Maven wrapper (https://maven.apache.org/wrapper/) which provides a mvnw executable.

Once your project is set up, you will need to add OmnisCalls as a dependency. In the Maven project, OmnisCalls was added to the pom.xml in the section:

...
   <dependencies>
      <dependency>
         <groupId>net.omnis</groupId>
         <artifactId>OmnisCalls</artifactId>
         <version>0.1</version>
         <scope>system</scope>
         <systemPath>path/to/OmnisCalls.jar</systemPath>
      </dependency>
   </dependencies>
...

The dependency is needed only at build time since Omnis comes with OmnisCalls.jar in the CLASSPATH at runtime. Whilst editing the pom.xml, if using Maven, you could also setup the Maven plugin to build your dependencies out in a lib folder inside your project, which you could then copy out into your module's lib subfolder:

...
   <build>
      <plugins>
         <!-- Get dependencies in lib folder -->
         <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-dependency-plugin</artifactId>
            <version>3.2.0</version>
            <executions>
               <execution>
                  <id>copy-dependencies</id>
                  <phase>package</phase>
                  <goals>
                     <goal>copy-dependencies</goal>
                  </goals>
                  <configuration>
                     <outputDirectory>
                        ${project.build.directory}/lib
                     </outputDirectory>
                  </configuration>
               </execution>
            </executions>
         </plugin>
      </plugins>
   </build>
...

Once the dependency is available to your Java project, you can create the Java class you wish to expose to Omnis by extending OModule, for example:

   package net.omnis.OmnisTest; import net.omnis.OmnisCalls.*;
   public class Test extends OModule {
      // Implement your methods here
   }

In the above example a package net.omnis.OmnisTest was created with a class Test. When using $callmethod from Omnis Studio, the module name parameter would be net.omnis.OmnisTest.Test.

Note that if you do not inherit from the OModule class, the Java Worker will not be able to call your methods; the OModule class does not do anything at present, but is reserved for future use.

To implement a method in your module, you must make it return a Response object (provided by OmnisCalls) and take in a Map:

   public Response test(Map<String, Object> pParams) {

      Map<String, Object> data = new HashMap<>(); data.put("unicode",
         "Fingerspitzengef\u00FChl is a German term.\nIt\u2019s pronounced as follows:       [\u02C8f\u026A\u014B\u0250\u02CC\u0283p\u026Ats\u0259n\u0261\u0259\u02CCfy
\u02D0l]");

      return new SendResponse(data);
   }

In the above example a test method was created which returns a new SendResponse object (provided by OmnisCalls) with a Map parameter (i.e. a key-value store) containing one key: 'unicode' with a UTF-8 formatted string value.

The Java Worker automatically converts the Map from SendResponse into JSON, which when received in Omnis Studio will be a row variable in your $methodreturn.

Similarly, if you wish to send back an error, you can return a new SendError (provided by OmnisCalls). If you wish to send a list as part of the data, you can add an ArrayList to the Map, which can be summarized with the OmnisTest example, as follows:

   package net.omnis.OmnisTest; 
   import net.omnis.OmnisCalls.*; 

   import java.util.Map;
   import java.util.HashMap; 
   import java.util.ArrayList;

   public class Test extends OModule {

      public Response test(Map<String, Object> pParams) {

         Map<String, Object> data = new HashMap<>(); data.put("unicode","Fingerspitzengef\u00FChl is a German term.\nIt\u2019s 
         pronounced as follows: [\u02C8f\u026A\u014B\u0250\u02CC\u0283p\u026Ats\u0259n\u0261\u0259\u02CCfy\u02D0l]");

         ArrayList<String> listData = new ArrayList<>(); 
         listData.add("Python"); 
         listData.add("JavaScript"); 
         listData.add("Java");
         listData.add(".NET Core"); 

         data.put("OW3 Workers", listData);

         return new SendResponse(data);
      }
   }

To summarize, if you used the above module, you would call it from Omnis Studio through the Java Worker with $callmethod and use net.omnis.OmnisTest.Test as the module parameter and test as the method name.

Web Worker Objects

The following section refers to the Web Worker Objects (OWEB) available in Omnis Studio prior to Studio 8.1 (introduced in Studio 6.1.2): note they require Java to be installed and are therefore no longer supported in Studio 10.x or above: you should use the OW3 Workers for all new development.

SMTP Client Workers

The SMTP worker object allows you to submit email(s) to an SMTP server in a background thread, working in a similar way to the existing “worker objects” for DAMs, HTTP and Timers. In addition, it provides support for authentication methods not supported by the existing SMTPSend command including DIGEST-MD5, NTLM and OAUTH2.

In addition to the SMTP worker object, there is an object called EMAILMessage, which you use to build the message to be sent by the worker.

Software Requirements

The SMTP worker object relies on Java, and therefore relies on some Java files located in the ‘java/axis/lib’ folder in the main Omnis Studio folder: see the Java Objects chapter for details about running Java in Omnis.

EMAILMessage Object

The EMAILMessage object is used to construct the message to be sent to the SMTP Client worker. The EMAILMessage object has methods to manipulate the MIME body parts of the message. Each body part has a non-zero integer identifier that uniquely identifies the body part within the context of the object instance. EMAILmessage needs to remain in scope until the worker $completed or $cancelled message is called.

Note: If you specify a charset of kUniTypeAuto for binary or file body parts, the object will inspect the data, and set its charset according to the presence of a BOM (Byte Order Marker) to kUniTypeUTF8, kUniTypeUTF16BE, kUniTypeUTF16LE, kUniTypeUTF32BE or kUniTypeUTF32LE. If there is no BOM, the charset will be kUniTypeNativeCharacters, resulting in iso-8859-1 for Linux, macintosh for macOS or windows-1252 for Windows.

Methods

$createbodypartfromfile

$createbodypartfromfile(cPath[,cMIMEType,iCharset,cEncoding,cDisposition,cFilename])

Creates a MIME file body part. Returns non-zero integer body part id (unique for this EMAILMessage object) or zero if an error occurs.

Parameter Description
cPath The pathname of the file containing the body part data.The name of the file will also be used to set the filename for the attachment if you do not also pass the cFilename parameter
cMIMEType The MIME type of the body part,in the standard syntax of type/subtype. If you omit this, the object will use a mapping table built into oweb.jar to generate the MIME type from the file extension; if this mapping fails, the type defaults to application/octet-stream
iCharset A kUniType... constant (default kUniTypeAuto) indicating the charset of MIME type text/... (cannot be kUniTypeBinary or kUniTypeCharacter). If this body part needs a charset,it is assumed to be already encoded using this charset
cEncoding The encoding to be used to transfer the body part data e.g. ‘BASE64’. If omitted,the mail client chooses a default
cDisposition The content disposition value to be used for the body part e.g. ‘inline’ or ‘attachment’. If omitted, the mail client will use the default disposition
cFilename The name sent as the filename of the body part.Defaults to the file name component of cPath if omitted

$createbodypartfromchar

$createbodypartfromchar(cData[,cMIMEType,iCharset,cEncoding,cDisposition,cFilename])

Creates a MIME body part from character data. Returns non-zero integer body part id (unique for this EMAILMessage object) or zero if an error occurs.

Parameter Description
cData The character data to be used as the content of the body part
cMIMEType The MIME type of the body part,in the standard syntax of type/subtype. If you omit this, the type defaults to text/plain
iCharset A kUniType... constant(default kUniTypeUTF8) indicating the charset to be used for the character data (cannot be kUniTypeAuto, kUniTypeBinary or kUniTypeCharacter)
cEncoding The encoding to be used to transfer the body part data e.g. ‘BASE64’. If omitted,the mail client chooses a default
cDisposition The content disposition value to be used for the body part e.g. ‘inline’ or ‘attachment’. If omitted, the mail client will use the default disposition
cFilename The name sent as the filename of the body part. If omitted, no filename will be used

$createbodypartfrombin

$createbodypartfrombin(xBin[,cMIMEType,iCharset,cEncoding,cDisposition,cFilename])

Creates a MIME body part from binary data. Returns non-zero integer body part id (unique for this EMAILMessage object) or zero if an error occurs.

Parameter Description
xBin The binary data to be used as the content of the body part
cMIMEType The MIME type of the body part,in the standard syntax of type/subtype. If you omit this, the type defaults to application/octet-stream
iCharset A kUniType... constant (default kUniTypeAuto) indicating the charset of MIME type text/... (cannot be kUniTypeBinary or kUniTypeCharacter). If this body part needs a charset,it is assumed to be already encoded using this charset
cEncoding The encoding to be used to transfer the body part data e.g. ‘BASE64’. If omitted, the mail client chooses a default
cDisposition The content disposition value to be used for the body part e.g. ‘inline’ or ‘attachment’. If omitted, the mail client will use the default disposition
cFilename The name sent as the filename of the body part. If omitted, no filename will be used

$createbodypartfromparts

$createbodypartfromparts(cMultiType,vPart[,iPart2,...])

Creates a MIME multi-part body part containing specified body parts. Returns non-zero integer body part id (unique for this EMAILMessage object) or zero if an error occurs.

Parameter Description
cMultiType The type of multi-part body part being created e.g. mixed
vPart Either an integer body part id for a previously created body part in the EMAILMessage object or a single column list of integer body part ids for previously created body parts
iPart2 An integer body part id for a previously created body part in the EMAILMessage
Further parameters can be integer body part ids for previously created body parts

Note that each body part can only be used once in a multi-part body.

$deleteaallbodyparts

$deleteaallbodyparts()

Deletes all body parts that have been created using a $createbodypart... method. Also sets property $contentid to zero.

Properties

The EMAILMessage object has the following properties:

Property Description
$errorcode Error code associated with the last action (method call or property assignment) (zero means no error)
$errortext Error text associated with the last action (method call or property assignment) (empty means no error)
$from The email address of the sender
$subject The subject of the message
$to A space separated list of email addresses of the primary recipients of the message
$cc A space separated list of email addresses of the carbon copied recipients of the message
$bcc A space separated list of email addresses of the blind carbon copied recipients of the message
$priority A kOWEBmsgPriority... constant that specifies the priority of the message. Defaults to kOWEBmsgPriorityNormal
$extraheaders A list with 2 character columns (name and value). Each row in the list is an additional SMTP header to be sent to the server when submitting the message
$contentid The id of the content to be sent with this email message. An integer body part id (returned by one of the $createbodypart... methods)

Constants

The EMAILMessage object has the following constants:

Constant Description
kOWEBmsgPriorityLowest The message has the lowest priority.
kOWEBmsgPriorityLow The message has low priority.
kOWEBmsgPriorityNormal The message has normal priority.
kOWEBmsgPriorityHigh The message has high priority.
kOWEBmsgPriorityHighest The message has the highest priority.

SMTPClientWorker Object

The SMTPClientWorker object uses the standard worker mechanism, with methods $init, $start, $run and $cancel, and callbacks $completed and $cancelled. In addition, there are some properties which further control the behavior of the object.

Methods

$init

$init(zMessage,cServer[,iSecure=kOWEBsmtpSecureNotSecure,iAuthType=kOWEBsmtpAuthTypeNone,cUser,cPassword,cOAUTH2,cRealm,cNTLMDomain,lProps, bMailShot=kFalse ])

Initialize the worker object so it is ready to send message oMessage. Returns true if successful.

Parameter Description
zMessage An object reference to the EMAILMessage to send
cServer The SMTP server that will send the message.Either a domain name or IP address.You can optionally specify the server port by appending ':
iSecure A kOWEBsmtpSecure... constant that indicates if and how the connection is to be made secure
iAuthType A sum of kOWEBsmtpAuthType... constants that specify the allowed authentication types
cUser The user name that will be used to log on to the SMTP server
cPassword The password that will be used to log on to the SMTP server
OAUTH2 The SMTPClientWorker can manage OAUTH2 authentication for you. If you want it to do this, then this parameter is the name of the authority responsible for OAUTH2 authentication. This name is the name of a folder (which must exist) in secure/oauth2/smtp in the Omnis folder (the authority folder contains configuration and assets for this authority). In this case, cPassword is not used if OAUTH2 is the authentication mechanism chosen by the mail client. If you want to manage OAUTH2 yourself, then OAUTH2 must be empty or omitted, and the password must be the OAUTH2 access token. See the section on OAUTH2 for more details
cRealm The realm used for DIGEST-MD5 authentication
cNTLMDomain The domain used for NTLM authentication
lProps A list with 2 character columns (name and value). A list of properties to be set for the JavaMail SMTP session object (see docs for package com.sun.mail.smtp at https://javamail.java.net/nonav/docs/api/). The SMTPClientWorker sets these properties as a final step, meaning that this can be used to override properties set by the worker, or to set other properties
bMailShot If bMailShot is true (the default is false), the worker sends a separate copy of the message to each recipient (each recipient cannot see the email address of the other recipients). In this case, only 'to' recipients can be specified

$run

$run([cOAUTH2authCode])

Runs the worker on current thread. Returns true if the worker executed successfully. The cOAUTH2authCode parameter is discussed in the section on OAUTH2. It is not required in the initial call to $run to send an email.

$start

$start([cOAUTH2authCode])

Runs the worker on background thread. Returns true if the worker was successfully started. The cOAUTH2authCode parameter is discussed in the section on OAUTH2. It is not required in the initial call to $start to send an email.

$cancel

$cancel()

If required,cancels execution of worker on background thread. Will not return until the request has been cancelled.

$completed

$completed(wResults)

Callback method called when the request completes. Typically, you would subclass the SMTPClientWorker, and override $completed in order to receive the results. wResults is a row containing the results of executing the request. It has columns as follows:

Column name Description
errorCode An integer indicating the error that has occurred. Zero means no error occurred, and the email was successfully sent
errorInfo Error text that describes the error. Empty if no error occurred
log If the property $debuglog was set to kTrue before calling $init, this character column contains debugging information, including a log of the interaction with the SMTP server
oauth2_authcodeurl Only applies when using OAUTH2 authentication managed by the SMTPClientWorker, and when errorCode is kOWEBsmtpErrorOAUTH2authCodeRequired. The URL to which the user needs to navigate in order to obtain an OAUTH2 authorisation code. See the section on OAUTH2 for more details

$cancelled

$cancelled()

Callback method called when the request has been cancelled by a call to $cancel(). Typically, you would subclass the SMTPClientWorker, and override $cancelled.

Properties

The SMTPClientWorker object has the following properties:

Property Description
$state A kWorkerState... constant that indicates the current state of the worker object
$errorcode Error code associated with the last action (zero means no error)
$errortext Error text associated with the last action (empty means no error)
$threadcount The number of active background threads for all instances of this type of worker object
$debuglog If true,when the worker executes it generates a log of the interaction with the SMTP server.Must be set before executing $init for this object.The log is supplied as a column of the row variable parameter passed to $completed
$timeout The timeout (in seconds) for SMTP requests (default is 30). Zero means infinite. Must be set before executing $init for this object
$clientsecret The OAUTH2 client secret to be used to obtain tokens for OAUTH2. Must be set before executing $init for this object. Overrides the clientSecret (if any) in the OAUTH2 authority file. See the section on OAUTH2 for more details. This property is only relevant if the SMTPClientWorker is managing OAUTH2 authentication using an OAUTH2 authority

Constants

Authentication Types

These constants can be added together in order to form a bit mask of allowed authentication types:

Constant Description
kOWEBsmtpAuthTypeNone This has value zero, as a convenient way to indicate that no SMTP authentication is required.
kOWEBsmtpAuthTypeLOGIN SMTP LOGIN authentication is allowed if the server supports it.
kOWEBsmtpAuthTypePLAIN SMTP PLAIN authentication is allowed if the server supports it.
kOWEBsmtpAuthTypeDIGESTMD5 SMTP DIGEST-MD5 authentication is allowed if the server supports it.
kOWEBsmtpAuthTypeNTLM SMTP NTLM authentication is allowed if the server supports it.
kOWEBsmtpAuthTypeCRAMMD5 SMTP CRAM-MD5 authentication is allowed if the server supports it.
kOWEBsmtpAuthTypeOAUTH2 SMTP OAUTH2 authentication is allowed if the server supports it

Secure Connection Type

These constants indicate how the connection is to be made secure:

Constant Description
kOWEBsmtpSecureNotSecure The connection between client and server is not secure.
kOWEBsmtpSecureSSL The connection between client and server uses SSL.
kOWEBsmtpSecureSTARTTLS The connection between client and server is to be made secure by using the STARTTLS command.

OAUTH2

This section provides an overview of OAUTH2, including some key terms.

OAUTH2 provides a way for applications to perform actions on behalf of a user, provided that they have the permission of the user. So in the case of the SMTPClientWorker, when using OAUTH2 authentication, the Omnis Studio client needs to be given permission to send the email.

This all occurs in the context of an OAUTH2 authority, so for example if you are using GMAIL, the OAUTH2 authority is Google, or if you are using Windows mail, the OAUTH2 authority is Microsoft. he client application (Omnis Studio or more typically your application) needs to be registered as an application with the OAUTH2 authority; this gives it two key pieces of information:

that authenticates the application. This needs to be kept as private as possible.

How you register your application with the OAUTH2 authority depends on the particular authority. For example:

The user interfaces for these developer consoles allow you to obtain the client ID and client secret.

In order to use OAUTH2 authentication, the application needs to supply an OAUTH2 access token as the password. An access token is a short-lived password that is typically valid for an hour. The first time the application needs an access token, there has to be some interaction at the user interface:

As part of the process described above, the application stores the access token, expiry information, and refresh token in permanent storage. The next time the application needs to log on, the application reads this information. If the access token is probably still valid, based on the expiry information, the application uses it. If not, the application uses the refresh token to make a slightly different request to the token URL, in order to get a new access token, which it then stores and uses to log on. Note:

OAUTH2 for SMTPClientWorker

This section describes how the OAUTH2 support for the SMTPClientWorker works.

Authority Configuration

Each authority has a folder with the authority name in the folder secure/oauth2/smtp, in the Omnis data folder. In the installed tree, there are folders for two authorities, and each folder includes a file called config.json; this is a JSON file that configures the authority for use with the SMTPClientWorker. The installed authorities, and their JSON files, are:

gmail:
{
  "authURL": "https://accounts.google.com/o/oauth2/auth",
  "tokenURL": "https://www.googleapis.com/oauth2/v3/token",
  "proxyServer": "",
  "scope": "http://mail.google.com/",
  "redirectURI": "urn:ietf:wg:oauth:2.0:oob",
  "clientID": "",
  "clientSecret": ""
}
outlook:
{
  "authURL": "https://login.live.com/oauth20_authorize.srf",
  "tokenURL": "https://login.live.com/oauth20_token.srf",
  "proxyServer": "",
  "scope": "wl.imap,wl.offline_access",
  "redirectURI": "https://login.live.com/oauth20_desktop.srf",
  "clientID": "",
  "clientSecret": ""
}

When using these authorities, you need to supply your client ID. You can optionally store your client secret here, or if you want to keep it in another more secure location, you can store it how you like, and then supply it to the SMTPClientWorker using the $clientsecret property.

The proxyServer only requires a value if your client system is using a proxy server; the SMTPClientWorker uses this when making HTTP requests to the token URL.

User Storage

The SMTPClientWorker stores the access token, expiry information, and refresh token for a user in the file <user>.info in the authority folder, where <user> is typically the email address of the authorising user. This file is a JSON file, that is automatically handled by the SMTPClientWorker, so you should not need to edit this file.

Application Logic

After you have configured the authority, to use OAUTH2 in your application with the SMTPClientWorker, there is only one additional step you need to code in your application. Essentially, this comprises:

For example, in $completed:

If pResults.errorCode=kOWEBsmtpErrorOAUTH2authCodeRequired

  OK message {A browser window will open so that you can authorize sending email.//Please follow the instructions and then paste the authorization code into the following dialog...}

  Launch program ,[pResults.oauth2_authcodeurl]

  While len(lAuthCode)=0
    Prompt for input Authorization code Returns lAuthCode (Cancel button)
    If flag false
      Yes/No message {Are you sure you want to cancel?}
      If flag true
        Quit method
      End If
    End If
  End While
  Do $cinst.$start(lAuthCode)
End If

External Commands

Note the Web and Email external commands are obsolete and are no longer supported in Studio 10.x or above: you should use the OW3 Workers for all new development.

The following protocols were supported: HTTP, FTP, SMTP, POP3, and IMAP. The external commands are prefixed with the respective protocol name, e.g. HTTPSend, FTPConnect, etc.

The Web and Email external commands are not displayed in the Code Editor since the Exclude Old Commands filter is selected in the Code Editor (if you select No Filter from the Modify menu they will be available); these commands are described in the Command Reference in the External commands group and in the Omnis Help (press F1) under the External commands group.

Multi-threading

The Web and Email external commands are multi-threaded, when running on a multi-threaded Omnis Server. The Web commands allow another thread to execute in the multi-threaded server while the current command runs. Note that the same socket cannot safely be used concurrently by more than one thread. See also the ‘SMTP Client Workers’ section for using email in multi-threaded environment.

MailSplit

If the encoding cannot be determined from the MIME, MailSplit uses $importencoding as the default encoding rather than UTF-8, provided that $importencoding is an 8 bit encoding, that is, anything except kUniTypeUTF16, kUniTypeUTF16BE and kUniTypeUTF16LE.

Email Headers

The SMTPSend and MailSplit commands support international characters in email headers (using RFC2047). The character limit of 76 for RFC2047 encoded words for mail headers has been removed in the MailSplit command.

SSL Security

The Web and Email external commands allow support for secure connections using Secure Sockets Layer (SSL) technology. However, Transport Layer Security (TLS) supersedes SSL and should be used in new development. Applications that require a high level of interoperability should support SSL 3.0 and TLS.

The HTTP, FTP, SMTP, POP3, and IMAP client commands that establish a connection to a server allow you to control if and how a secure connection is used. The commands which allow secure connections are:

FTPConnect IMAPConnect
HTTPGet POP3Connect
HTTPOpen POP3Recv
HTTPPost POP3Stat
HTTPSetProxyServer SMTPSend

The parameters Secure and Verify allow you to enable support for secure connections. The parameters behave as follows:

For example, the FTPConnect command allows you to establish a secure connection to the specified FTP server; the full syntax of the command is:

FTPConnect (serveraddr, username, password [,port, errorprotocoltext, secure {Default zero insecure;1 secure;2 use AUTH TLS}, verify {Default kTrue}]) Returns socket

where Secure is an optional Boolean parameter which indicates if a secure connection is required to the server. Pass kTrue for a secure connection. If you pass secure with the value 2, the connection is initially not secure, but after the initial exchange with the server, FTPConnect issues an AUTH TLS FTP command to make the connection secure if the server supports it (see RFC 4217 for details), followed by further commands necessary to set up the secure connection. Authentication occurs after a successful AUTH TLS command. Note that if you use either of the secure options, all data connections are also secure, and all data transfer uses passive FTP.

When set to true (the default), the "ftpsresumesession" item in the "web" section of the config.json file ensures that the FTP commands attempt to resume the control connection session when establishing a secure data connection.

HTTPPage

The HTTPPage command has an additional parameter to allow you to ignore SSL. The full syntax of the command is:

HTTPPage (url[,Service|Port,pVerify]) Returns html-text

When passed as false, the pVerify argument prevents SSL verification when using a secure URL, so you can use:

HTTPPage (url,,kFalse)

SSL Packages

In order to use SSL or TLS in the Web and Email external commands the Secure Channel (Schannel) package on Windows, or Secure Transport on macOS must be installed on your development computer or a client’s computer: these are present by default on their respective platforms.

OpenSSL

Existing Users should note: The Web and Email external commands relied on OpenSSL in previous versions to provide secure communications. Support for OpenSSL has been removed for these commands and support for SSL and TLS relies on the built-in security for each platform.

If you have used OpenSSL to provide secure comms for these commands in existing applications, you will need to switch to using either Schannel or Secure Transport depending on what platform your app is running on.

Certificate Authority Certificates

In order to perform the verification (when the Verify parameter is kTrue), the SSL package uses the Certificate Authority Certificates in the cacerts sub-folder of the secure folder in the Omnis folder. If you use your own Certificate Authority to self-sign certificates, you can place its certificate in the cacerts folder, and the SSL package will use it after you restart Omnis.

Web Command Error Codes

Error codes for the Web Commands are listed in the Commands Reference.