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:
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:
$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.
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:
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:
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:
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:
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.
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:
The application opens a Web browser at the Authorization Endpoint (a URL) of the service.
The authenticated user agrees that the application can access the service.
The server hosting the Authorization URL redirects the browser to a URL supplied when opening the Web browser. This request contains an Authorization Code.
The application makes a request to the Token Endpoint (a URL) sending it the Authorization Code.
The server hosting the Token URL returns various pieces of information to the application, including: Access Token, Expiry of Access Token (recommended but not mandatory), Refresh Token (optional).
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.
$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.
$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):
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:
kOW3OAUTH2grantAuthorizationCode (the default)
the Authorization Code grant type (behaves as previous versions)
kOW3OAUTH2grantPassword
the Password grant type requires the new $username and $password properties to be specified
kOW3OAUTH2grantClientCredentials
the Client Credentials grant type requires $clientid and $clientsecret
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:
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:
- $oauth2
Property that is an object reference to an OAUTH2Worker object containing the authorization information required to make requests to the server. Clear this property by assigning #NULL to it. $authorize() cannot run while the OAUTH2Worker is assigned to $oauth2
The supported workers use $oauth2 to obtain the Access Token for the request. To do this, it uses the following logic:
If there is no Refresh Token ($refreshtoken is empty), it uses $accesstoken.
If the $accesstokenexpiry is #NULL (there is no expiry date and time), it uses $accesstoken.
If the expiry date time is more than 5 seconds away, it uses $accesstoken
Finally, it uses $refreshtoken to refresh the token(s). If successful, it generates a call to $tokensrefreshed() in the OAUTH2Worker and it uses the new $accesstoken
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.
Do $extobjects.OW3.$objects.OAUTH2Worker.$newref() Returns iOAUTH2
Do $objects.oSMTPWorker.$newref() Returns iSmtp
Do iSmtp.$setCallingInst($cinst)
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.iOAUTH2FlowType) Returns lOK
If not(lOK)
OK message {[iOAUTH2.$errortext]}
End If
Calculate iAuthorizing as kFalse
If iAuthorizing
OK message {Cannot execute while authorizing}
Quit method
End If
If iUseOAUTH2
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:
curl version 7.84.0
libssh2 version 1.9.0
mbedTLS version 2.16.2
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:
$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):
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:
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:
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=kOW3httpMethodGet, lHeaders=#NULL, vContent='', iAuthType=kOW3httpAuthTypeNone, cUserName='',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:
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¶m2=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.
Do method checkHttpObject
Do method setupLogging
If len(iTempContent)
Do iHttp.$init(iURI,iMethodList.iMethod,iHeaderList,iTempContent,iAuthList.iAuthType,iUser,iPassword) Returns lOk
Else
If iSendContentMode=1
Do iHttp.$init(iURI,iMethodList.iMethod,iHeaderList,row(iContentPath),iAuthList.iAuthType,iUser,iPassword) Returns lOk
Else If iSendContentMode=2
Do iHttp.$buildmultipart(iContentPath)
Do iHttp.$init(iURI,iMethodList.iMethod,iHeaderList,kOW3httpMultiPartFormData,iAuthList.iAuthType,iUser,iPassword) Returns lOk
Else If iSendContentMode=0
Do iHttp.$init(iURI,iMethodList.iMethod,iHeaderList,iContent,iAuthList.iAuthType,iUser,iPassword) Returns 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(cName, cFieldData [,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:
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:
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:
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:
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:
$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:
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(cURI, cUser, cPassword, vFrom, lTo, lCc, lBcc, cSubject, cPriority, lHeaders, 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:
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.
Do method setupLogging
Calculate iSmtp.$timeout as iTimeout
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,lFromDescription) Returns 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,iMailshot) Returns lOk
Else
Do iSmtp.$init(iServerURI,iUser,iPassword,lFromAddress,lToList,lCcList,lBccList,iSubject,iPriorityList.iPriorityValue,iExtraHeaderList,lBinContent,iMailshot) Returns lOk
End If
Else
If len(lFromDescription)
Do iSmtp.$init(iServerURI,iUser,iPassword,row(lFromAddress,lFromDescription),lToList,lCcList,lBccList,iSubject,iPriorityList.iPriorityValue,iExtraHeaderList,lMIMElist,iMailshot) Returns lOk
Else
Do iSmtp.$init(iServerURI,iUser,iPassword,lFromAddress,lToList,lCcList,lBccList,iSubject,iPriorityList.iPriorityValue,iExtraHeaderList,lMIMElist,iMailshot) Returns 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:
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:
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:
$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:
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:
The full text returned by the server. This maintains compatibility with previous versions of the OW3 FTP worker, and may contain additional information not extracted by the parser.
The file name.
Boolean. True if the entry is probably a directory.
Boolean. True if the entry is probably a file.
File size in bytes.
Modification date of the file.
Boolean. True if the modification date is in the local time zone of the client. False means the time zone of the modification date is unknown.
If not empty, the server id of the file or directory. A character string.
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(cURI, cUser, cPassword, iAction, cServerPath, 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:
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:
Do method setupLogging
Calculate iFtp.$timeout as iTimeout
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,iContent) Returns 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,iPermissions) Returns lOk
Else If iActionList.C2=kOW3ftpActionExecute
Do iFtp.$init(iServerURI,iUser,iPassword,iActionList.C2,iServerPath,iCommandList) Returns lOk
Else If iActionList.C2=kOW3ftpActionListDirectory
Do iFtp.$init(iServerURI,iUser,iPassword,iActionList.C2,iServerPath,iNamesOnly) Returns lOk
Else If iActionList.C2=kOW3ftpActionDelete
Do iFtp.$init(iServerURI,iUser,iPassword,iActionList.C2,iServerPath,iPathIsDirectory) Returns lOk
Else
Do iFtp.$init(iServerURI,iUser,iPassword,iActionList.C2,iServerPath) Returns lOk
End If
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:
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.
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:
You use URLs of the form SFTP:// to request an SFTP connection.
You must explicitly select a server character set - kUniTypeAuto will cause the worker to return an error.
The append file action is not supported.
If you have written code that uses the execute action, be aware that SFTP servers support different commands to FTP servers.
The remaining actions work as expected.
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:
$sshenablecompression
If true, SSH compression is enabled for SFTP connections, resulting in a request to the server to enable compression; the server may ignore the request. Defaults to false
$sshknownhostsfile
The full pathname of the SSH known hosts file used for SFTP. Defaults to the path of clientserver/client/ow3_sftp_known_hosts in the Studio tree. Set this to empty to allow connections (insecurely) to any host
$sshknownhostsaction
A sum of kOW3sshKHAction... constants (default kOW3sshKHActionReject) specifying what occurs if $sshknownhostsfile is present, and a connection is to be made to a server not in the file, or a server in the file with a host key mismatch
$sshauthtypes
A sum of kOW3sshAuthType... constants specifying the allowed authentication types when establishing a connection to the server; the default is kOW3sshAuthTypePublicKey + kOW3sshAuthTypePassword + kOW3sshAuthTypeHost + kOW3sshAuthTypeAgent
The FTP worker object has the methods:
$getsshoptions()
$getsshoptions([&cServerPublicKeyMD5,&cClientPublicKeyFile,&cPrivKeyFile,&cPrivKeyPassword)]) gets the options that affect how SSH connections are established for SFTP
$setsshoptions()
$setsshoptions([cServerPublicKeyMD5='',cClientPublicKeyFile='',cPrivKeyFile='',cPrivKeyPassword='']) sets the options that affect how SSH connections are established for SFTP. The parameters are:
cServerPublicKeyMD5:The 128 bit MD5 checksum of the server's public key (supplied as a 32 character ASCII hex string).If not empty,the SFTP client will reject the connection to the server unless the MD5 checksums match
cClientPublicKeyFile:The pathname of the client's public key. If empty,the client will try to compute the public key from the private key
cPrivKeyFile:The pathname of the client's private key file
cPrivKeyPassword:The private key file password
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:
$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:
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(cURI, cUser, cPassword, iAction, cMailboxName, 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:
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:
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:
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:
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:
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:
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:
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:
resultList |
Not populated. |
<action‑specific> |
No action specific column. |
kOW3imapActionAppendMessage:
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:
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:
- omnis_calls.js - a module which provides an interface for methods to return their results to Omnis.
- omnis_modules.js - a module which provides a table of modules that can be called from Omnis.
- omnis_modules.mjs - a module which provides a table of modules that can be called from Omnis.
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.
cPath
allows you to override the default NODE_PATH module search path set by the worker. The default path is <Omnis data folder>/jsworker. If you override this path, the various JavaScript modules that are mandatory for the worker to operate must still be able to be located.
bDebugNodeJs
is a Boolean that indicates if you want to be able to debug node.js, for example using Chrome. It is possible that you may not be able to start the worker if you set this for more than one active JavaScript worker, as node.js requires a debug port to be available. To debug the JavaScript in Chrome, navigate to chrome://inspect, and then open the dedicated debug tools for node.js via the link.
$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(cModule, cMethod, 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.
cModule and cMethod (Character)
identify a module, and a method within the module, to call, as described above.
vListOrRow (Variant)
will be converted to JSON and passed to the method as its parameter. This means that you should be aware of data that will not map to JSON, and avoid trying to pass that to $callmethod.
bWait (Boolean)
indicates if the caller wishes to suspend execution until the method completes. If you use bWait, then a completion callback will occur before $callmethod returns.
cErrorText (Character)
receives text describing the error if $callmethod fails; code 460 for module not found, and 461 for method not found.
vTag (Variant)
(for Studio 11) if supplied, some data can be passed to $methoderror or $methodreturn in the column __tag of the row parameter. This can be used, for example, to identify the caller when the worker object is shared by several instances.
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.
- wError
has two columns, an Integer named errorCode and a Character string named errorInfo.
$methoderror
$methoderror(wError)
Override this method to receive reports of the failure of an attempt to call a method with $callmethod.
- wError
has two columns, an Integer named errorCode and a Character string named errorInfo.
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.
- wReturn
is a list/row parameter with two columns: __module and __method. If the parameter is a list, then __module and __method are only populated for the first line of the list.
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,lErrorText) Returns 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(cURI, cUser, cPassword, iAction [,iMessageNumber, cPostCommand])
Initialises the object so it is ready to perform the specified action using POP3. Returns true if successful
The $init parameters are:
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:
kOW3pop3ActionStat Gets maildrop status. For a successful request, wResults has 2 columns returning the stat information, messageCount and maildropSize
kOW3pop3ActionList Lists messages. For a successful request, wResults has a column named messageList which contains a 2 column list, with columns messageNumber and messageSize
kOW3pop3ActionGetMessage Gets specified message. For a successful request, wResults has either a column rawData or columns headerList and mimeList (depending on the value of $splitfetchedmessage
kOW3pop3ActionGetHeaders Gets headers for a specified message. For a successful request, wResults has either a column rawData or a column headerList (depending on the value of $splitfetchedmessage)
kOW3pop3ActionDeleteMessage Deletes the specified message from the maildrop
kOW3pop3ActionQuit Sends a QUIT command to the server to ensure that any messages marked for deletion are deleted
Properties
The OW3 POP3 worker has the following properties in addition to those supported by all OW3 worker objects:
$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:
$start, $run and $cancel
Standard worker methods
$completed and $cancelled
Standard worker completion methods
$makerandom
$makerandom(iBytes,&xRandomData) generates some random data with the specified length in bytes. This is suitable for use as an encryption key or initialization vector. Returns true if successful (if an error occurs, the standard properties $errorcode and $errortext describe the error).
iBytes is the number of bytes of random data to generate
xRandomData is a binary variable that receives the random data
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:
- $init
$init(iAction, iEncryptionType, iCipherMode, iPadding, xKey, xIV, vInputData [,cOutputPath]) initializes the object ready to perform the encryption or decryption. Returns true if successful
iAction can be either:
iEncryptionType can be one of:
kOW3cryptoTypeAES
AES encryption. Key size must be 128, 192 or 256 bits
kOW3cryptoTypeCamellia
Camellia encryption. Key size must be 128, 192 or 256 bits
kOW3cryptoTypeDES
DES encryption. Key size must be 64 or 192 bits. Uses Triple DES if key size is 192 bits
- kOW3cryptoTypeBlowfish
(deprecated in Studio 11; do not use for new apps)
Blowfish encryption. Key size must be 128 bits
- kOW3cryptoTypeBlowfish
support for Blowfish encryption in the CRYPTO Worker has been removed. The encryption type constant kOW3cryptoTypeBlowfish still exists in Omnis to avoid issues with code conversion, but this will no longer work and you are advised to use other encryption types
iCipherMode can be one of:
kOW3cryptoCipherModeCBC
CBC (Cipher Block Chaining)
kOW3cryptoCipherModeECB
EBC (Electronic Code Book)
kOW3cryptoCipherModeCTR
CTR (Counter). Not supported for kOW3cryptoTypeDES
iPadding can be one of:
kOW3cryptoPaddingNone
No padding (use this for cipher modes other than CBC and EBC)
kOW3cryptoPaddingPKCS7
PKCS7 padding
kOW3cryptoPaddingOneAndZeros
One and zeros padding (ISO/IEC 7816-4)
kOW3cryptoPaddingZerosAndLen
Pad with N-1 zero bytes followed by a byte with value N, where N is the number of padding bytes (ANSI X.923)
kOW3cryptoPaddingZeros
Pad with N zero bytes, where N is the number of padding bytes
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:
Either omitted or empty meaning that the encrypted or decrypted data is supplied to $completed in the data column of the results row parameter (this column has type binary)
Or the pathname of a file (which must not already exist) to which the worker will write the encrypted or decrypted data
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:
$errorcode, $errortext, $state and $threadcount
Standard worker properties
$useexplicitiv
If true, a random IV is added to the start of the data when encrypting or the first IV size bytes is removed from decrypted data. Only applies to CBC cipher mode. This means that a user can decrypt data without knowing the IV (any IV can be used for decryption, which will result in just the first IV size bytes being decrypted incorrectly, because of the way the CBC cipher mode works)
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:
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:
$start, $run and $cancel
Standard worker methods: see Base Worker Methods
$completed and $cancelled
Standard worker completion methods: see Callback methods
$inithash()
$inithash(vData,iHashType,vHashParameters) initialises the object so it is ready to hash data using the specified hash type
vData specifies the data to hash. Either binary or character. A binary value is used directly. Otherwise, for PBKDF2 the worker converts character data to UTF-8 before generating the hash. For other hash types, a character parameter is the pathname of the file containing the data to hash.
iHashType the hash type, a kOW3hash… constant.
vHashParameters A row of parameters that control the hash. For all types except PBKDF2, an empty row() to generate a hash, or the binary key to use when generating an HMAC (see below). For PBKDF2, a row with 3 integer columns in the order saltLength, keyLength, iterations.
saltLength - the length of the random salt (generated by the worker). A good value for this is 16. Must be 8 to 64 inclusive
keyLength - the length of the hashed key to be generated. A good value is 32. Must be between 16 and 256 inclusive
iterations - the number of iterations to perform to generate the hash. A good value for iterations is at least 100000 - the higher the value, the more secure the hash, traded off against a longer execution time. Must be between 1 and 256000 inclusive
$initverifyhash()
$initverifyhash(vData,iHashType,vHash [,xHMACkey]) initialises the object so it is ready to generate the hash for vData using iHashType and compare it against previously generated vHash
vData specifies the data to hash. Either binary or character. For PBKDF2 the worker converts character data to UTF-8 before generating the hash. For other hash types, a character parameter is the pathname of the file containing the data to hash.
iHashType the hash type, a kOW3hash… constant.
vHash A hash previously generated by the worker using $inithash(). Either binary or character. If character, the value must be the BASE64 encoded representation of the hash. Using this method, you could create a hash using $inithash and store that for future use. To verify a password or document you call $initverifyhash, with vData as the password or document to verify, and vHash as the stored hash from your call to $inithash.
xHMACkey the key to use when verifying an HMAC authentication code (see below)
$initsignature()
$initsignature(vData,iHashType,vPrivateKeyPEM[,bBlind=kFalse]) initialises the object so it is ready to generate the signature for vData using iHashType and RSA encryption with private key xPrivateKeyPEM.
vData specifies the data for which a signature is required. Either binary or character. The worker converts character data to UTF-8 before generating the signature.
iHashType the hash type, a kOW3hash… constant.
vPrivateKeyPEM The private key in PEM (Privacy Enhanced Mail) format. Either binary or character. Binary is assumed to already be UTF-8. The worker converts character data to UTF-8 before trying to use the private key.
bBlind (default kFalse) If true, the RSA encryption used to generate the signature uses blinding.
- $initverifysignature()
$initverifysignature(vData,iHashType,vPublicKeyPEM,vSignature) verifies a signature from $initsignature.
vData the original data
iHashType the original hash type
vPublicKeyPEM the public key in PEM format
vSignature the signature from $initsignature
When returning to $completed, the row's errorCode will be 0 if the signature has been verified successfully (that is, the data has not been tampered with and it matches the signature), otherwise it will have a mbedtls or an Omnis error code if something has gone wrong (e.g. if the signature doesn't match, it should return -17280 with error info of "RSA - The PKCS#1 verification failed").
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:
- $errorcode, $errortext, $state and $threadcount
Standard worker properties
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:
- cURI: The URI of the server, optionally including the URI scheme (ldap or ldaps) e.g. ldap://ldap.myserver.com. If you omit the URI scheme e.g. ldap.myserver.com, the URI scheme defaults to ldap
cUser: The user name to be used to log on to the LDAP server
cPassword: The password to be used to log on to the LDAP server
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",lRow) Returns #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',,kTrue) Returns #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',,,,lTagID) Returns #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.
cPath
optional character string of items for the Java CLASSPATH. Paths must be separated by ; (semi colon) on Windows, and : (colon) on macOS and Linux. If empty, the worker adds the default CLASSPATH.
cExecutable
optional character string containing the path to the Java executable that should be used. If empty, Omnis uses /usr/bin/java on macOS and Linux, and java.exe on Windows.
bDebugWorker
optional boolean to put the Java Worker thread in debug mode, defaults to false. If debug is true, debugging messages are written to stdout.
cJvmOptions
optional character string of options to pass to the JVM.
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:
JavaWorker.jar
the main Java entry point for the Java Worker. This is a Spring Boot application running the http/2 endpoint that handles Java method calls.
lib
a folder containing the JAR dependencies for JavaWorker.jar.
store.jks
a Java KeyStore containing the Omnis self-signed certificate used to form a secure connection between Omnis and the JavaWorker.jar. When Omnis starts the Java process, the JavaWorker.jar, lib subfolder and <read/write location>/clientserver/server/javaworker/ are added to the CLASSPATH.
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:
lib
a global folder for JAR dependencies, for example, it contains gson-2.10.1.jar since it is used by some of the JARs in the Java Worker. If your modules have a common dependency, you should use this global lib folder.
OmnisCalls a folder that represents the OmnisCalls module, containing the OmnisCalls.jar.
OmnisTest
a folder that represents the OmnisTest module, containing the OmnisTest.jar.
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.
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.
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.
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.
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:
$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:
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.
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:
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:
$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:
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:
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:
The application opens a browser window at the OAUTH2 authorisation code URL for the authority. Note that this URL includes a scope which indicates what type of permission is being requested. Each authority has a scope value which indicates that the user wants to manage email.
The browser window may ask the user to log on to their account with the relevant authority. Once logged on, it will ask the user if they give the particular application permission to use their email. If the user agrees, the browser redirects to a URI called the redirect URI, passing an authorisation code to the URI. There are special redirect URIs for OAUTH2 authorities which cause the authorisation code to be available in the browser window after the user agrees - you need to use these special redirect URIs to use the SMTPClientWorker.
The user copies the authorisation code from the browser window, and pastes it into the application.
The application uses the authorisation code, client secret, client id and redirect URI to make an HTTP request to the token URL. A successful call to this URL returns an access token, expiry information for the access token (how long it is valid) and a refresh token.
The application uses the access token as the password.
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:
If the log on fails using the saved access token (with an authentication failure), the application will then try to use the refresh token to obtain a new access token.
The refresh token may be invalidated by the authority at some point. For this, and various other reasons, log on may fail with an authentication failure. In that case, the application needs to return to the initial step of opening the browser window at the OAUTH2 authorisation code URL, so that it can obtain the user’s permission, and a new access token and refresh token.
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:
Opening a browser window at the OAUTH2 authorisation code URL.
Accepting the pasted authorisation code.
Calling $run or $start for a second time, this time also passing the authorisation code.
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.
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:
Secure
is an optional Boolean* parameter which indicates if a secure connection is required to the server. Pass kFalse for non-secure (the default). Pass kTrue (value 1) for a secure connection; this enables the Verify option.
*In addition, you can pass value 2 to some of the commands to enable specific types of authentication. The SSL package installed on yours or the client’s system is used (Windows: Schannel, or macOS: Secure Transport). FTPS resumes the TLS session for data connections. In addition, it automatically sends PBSZ and PROT commands to the server after establishing a secure control connection
Verify
is an optional Boolean parameter which is only significant when Secure is not kFalse. When Verify is kTrue, the command instructs the SSL package to verify the server's identity using its certificate; if the verification fails, the connection will not be established. You can pass Verify as kFalse, to turn off the verification; in this case, the connection will still be encrypted, but there is a chance the server is an impostor.
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.