.spr0.ap.ebb.date.fl subs .require "ident" .title $ident() Extension Image Interface .subtit $ident() ### .b6 .c;DEC INTERNAL USE ONLY .b .c;N#M#A#I#L .b .c;EXTENSION IMAGE INTERFACE .b4 This document describes the interface through which $ident() can make calls to an external shareable image, in order to implement extensions to normal Nmail processing. Nmail was written by Dave Porter and is entirely unfunded; please send comments, suggestions, gratitude and legal tender to MU::PORTER. Supply of this software and documentation does not commit me to anything, anytime. .pg;.do contents "/deepest=2/double_space" .pg;.hl1 Introduction This document describes the interface through which $ident() can make calls to an external shareable image, in order to implement extensions to normal Nmail processing. In the current version, the extension interface offers support for two different functions. Firstly, it allows for mail addresses to be modified as they are entered by the user. Secondly, it provides hooks to support the collection of usage statistics in the Nmail sending daemon. The extension interface is intended for use by experienced programmers, and very little assistance is available beyond the present document. It is my intention that the interface will not be changed in incompatible ways in future versions of Nmail, but I cannot guarantee that I won't make such a change. You have been warned! .hl1 Declaring the image to Nmail .hl2 Entry-Point Table The extension image must include a table of entry points. The table format is: .lt +-----------------+ | count | :00 +--------+--------+ | majver | minver | :04 +--------+--------+ | start | :08 +-----------------+ | send-address | :12 +-----------------+ | finish | :16 +-----------------+ | symbiont-start | :20 +-----------------+ | symbiont-stats | :24 +-----------------+ | symbiont-finish | :28 +-----------------+ .el .lm+12 .b.i-8;count .b;Specifies the number of longwords following; it must be at least one. That is, the version number longword must always be present, but other table entries are optional. .b.i-8;majver and minver .b;The version of the Nmail extension interface to which the image is implemented. This specification describes version 1.2 (value 1 in high word, 2 in low word). .b.i-8;start .b;A pointer to the extension's user-context start routine. .b.i-8;send-address .b;A pointer to the extension's user-context send-address routine. .b.i-8;finish .b;A pointer to the extension's user-context finish routine. .b.i-8;symbiont-start .b;A pointer to the extension's symbiont-context start routine. .b;.i-8;symbiont-stats .b;A pointer to the extension's symbiont-context statistics-recording routine. .b.i-8;symbiont-start .b;A pointer to the extension's symbiont-context finish routine. .lm-12 The value of a routine pointer depends on the machine architecture. On VAX, it is the address of the register save mask which precedes the first instruction of the routine. On Alpha, it is the address of the procedure descriptor structure. This difference should be invisible to all but assembly-language programmers. If the extension image has no use for a particular routine, a null pointer (value of zero) can be used. The purpose of the supplied routines is described in the next section, together with the calling sequence which Nmail will use to invoke the routines. Some extension routines are called in user context (for example, when running MAIL.EXE), and others are called from the Nmail symbiont. The same image is activated in both cases. The entry point table must be labelled with the symbol NM_$EXTENSION. At link time, use the UNIVERSAL option (VAX) or the SYMBOL__VECTOR option (Alpha) to make the symbol visible outside the image; Nmail will search for this symbol when it activates the shareable image. .hl2 Telling Nmail about the extension image The extension image can have any name you wish. A system logical name must be used to identify the image to Nmail: .lt $ ASSIGN /SYS/EXEC dev:yourimage.exe NM$EXTENSION .el This logical name must be defined before starting the Nmail queues, or else the symbiont will not make use of it. The definition must have an access mode of 'executive' to be seen by Nmail. If Nmail cannot activate the image for any reason, or if it considers the format of the entry point table to be invalid, then it will treat this as a fatal error, rather than continuing to operate but without the extension. In other words, if the system manager has specified that an Nmail extension is to be used, its use is considered to be mandatory. In the case of the symbiont, the DCL command to start the queue will fail with "bad parameter value". An OPCOM message will be sent to class CENTRAL, giving a slightly more informative cause of failure. .hl2 Miscellaneous design notes Some routines are called in user context from NM__MAILSHR.EXE, which is in turn called from MAIL.EXE, or some other program which allows the user to send mail. Other routines are called in symbiont context from NM_$DAEMON.EXE. The two contexts are quite different. When your extension image is running in user context, no special privileges are available. Since VMS MAIL provides a callable interface, the user could be running any image at all, not only MAIL.EXE. Therefore, you cannot rely on being able to install the image with elevated privilege. Don't forget that user context also includes running to send outgoing mail from a network mail server which was started to handle an incoming mail message. This can happen as a result of someone sending mail to an address like node1::NM%node2::user, or a SET FORWARD command with the same effect. In user context, you can write to SYS_$OUTPUT for debugging purposes. You should not try to use this for reporting errors back to the original user; in the mail server case, SYS_$OUTPUT is the mail server's log file and thus the text is unlikely to do any good. When your extension image is running in symbiont context, then TMPMBX, NETMBX, SYSPRV, and OPER privileges will always be enabled. Other privileges may be enabled, but you shouldn't rely on that. In addition, you have SETPRV, so you can turn on anything you need. If you do modify the symbiont's current privileges in any extension routine, then you MUST restore the original values before returning control to Nmail. Do not simply turn off all extra privileges when you return---that might cause Nmail to subsequently fail. The extension image is activated only once for each run of the main image (mail user agent or symbiont) but it may be invoked to handle several independent mail messages. You should ensure that your image will function correctly in this environment; for example, static data may need to be initialised at run time, rather than having initial values compiled in to the image. An extension image finish routine can be used to ensure cleanup after each mail message. You can not write to SYS_$OUTPUT when running in symbiont context. That file points to the job controller's input mailbox, and it doesn't appreciate random text messages. Note that NM__MAILSHR.EXE is not the only creator of Nmail jobs. The symbiont also submits jobs into the queue, for use in reporting errors, returning cancelled messages, and so on. Therefore, you can't assume that every job you see when called from the symbiont will have previously been seen in user context. .hl1 Routine specifications .hl2 The Start Routine (User Context) Nmail calls the extension image's start routine when beginning to process a new mail message. The calling sequence is as follows: ####status = start(qtime, sender) .lm+12 .b.i-8;qtime###quadword date-time by reference; input parameter. .b;The time at which this message was entered into Nmail. This is not necessarily unique, and can not be reliably used to deduce the name of the Nmail work file. .b.i-8;sender##character string by descriptor; input parameter. .b;The "from" address. It can include one or more node names, if the message has been forwarded through any intermediate nodes. .b.i-8;status##longword value; routine return value. .b;The return status; not currently checked by Nmail. .lm-12 .hl2 The Send-Address Routine (User Context) Nmail calls the send-address routine once for each mail address to which the message is to be sent. The send-address routine may change or reformat the address, before Nmail writes it to the work file. The calling sequence is as follows: ####status = send__address(node, addr, result) .lm+12 .b.i-8;node####character string by descriptor; input parameter. .b;Specifies the node name for this mail address; it may be the empty string. .b;The node name can be a simple name (for example, MU) or something more complicated, such as a DECdns full name (for example, DEC:.lkg.mu). .b.i-8;addr####character string by descriptor; input parameter. .b;The rest of the address; in the simple case this is just a user name, but it may include further node names if more than one was specified in the original address. .b;The end of the address list is indicated by a call in which the string is exactly one null byte---that is, the descriptor length contains one, and the descriptor pointer points to a byte containing zero. The node name parameter is arbitrary in this case. .b.i-8;result##character string by descriptor; output parameter. .b;The reformatted address returned by send__address. The address is returned by dynamic descriptor, so the routine should write to it using a library function such as str_$copy__dx. .b;The string is initialised to null. If it is null on return (but the status shows successful completion) then Nmail assumes that normal node::addr formatting is needed for this address. .b.i-8;status##longword value; routine return value. .b;The return status; if true, then the address was valid and the call succeeded. If false, then the call failed; Nmail will tell MAIL that the address was invalid, and it will not be written to the work file. .lm-12 Returning a false (low bit clear) status value will cause MAIL to treat that address as being invalid, but it will not cause any error message to be displayed. Errors must be explicitly signalled. If the severity of the signal is 'fatal' then MAIL will be abruptly terminated; otherwise, the signalled error will be considered as applying to the address currently being processed. You must signal errors; you cannot simply write them to the terminal. MAIL needs to handle the case where it is using Nmail in server context (for example, if mail was sent to node1::NM%node2::user) and it does this by using VMS conditional handling. .hl2 The Finish Routine (User Context) Nmail calls the extension image's finish routine at the end of processing a mail message. Under normal circumstances, this will occur just after the work file has been submitted to the Nmail queue. However, the finish routine is also called if mail processing is abnormally terminated. This can happen as a result of some previous error, cancellation by Ctrl/C, or image rundown. In any case, the finish routine should clean up, and leave the extension image in a state where it is able to start processing a new mail message (if the user chooses to send another message before leaving MAIL). The calling sequence is as follows: ####status = finish(sndsts, txtlen, naddr) .lm+12 .b.i-8;sndsts##longword value; input parameter. .b;A VMS status value: low bit set if the Nmail job was successfully submitted to the queue, and low bit clear otherwise. .b.i-8;txtlen##longword integer value; input parameter. .b;The length of the body of the mail message; the sum of the record lengths for the file. .b.i-8;naddr###longword integer value; input parameter. .b;Total number of mail addresses written to the Nmail control file. Invalid addresses (rejected by the extension's send-address routine) are not included in the count. .b.i-8;status##longword value; routine return value. .b;The return status; not currently checked by Nmail. .lm-12 Note that the finish routine may be called even if no other routine in the extension image has yet been called. Therefore, it should operate cautiously and check whether it really has any work to perform. .hl2 The Start Routine (Symbiont Context) Nmail calls the start routine when the symbiont starts to process a message; that is to say, when a job becomes active in the queue. The start routine is called every time the symbiont needs to reprocess the message, not just for the first time in the queue. The calling sequence is as follows: ####status = symbiont__start(qtime, sender, natt) .lm+12 .b.i-8;qtime###quadword date-time by reference; input parameter. .b;The time at which this message was entered into Nmail. This is not necessarily unique, and can not be reliably used to deduce the name of the Nmail work file. .b.i-8;sender##character string by descriptor; input parameter. .b;The "from" address. It can include one or more node names, if the message has been forwarded through any intermediate nodes. .b.i-8;natt####longword integer by value; input parameter. .b;The number of times that delivery of this message has been attempted (number of times the Nmail job has been processed). .b.i-8;status##longword value; routine return value. .b;The return status; not currently checked by Nmail. .lm-12 .hl2 The Statistics Routine (Symbiont Context) Nmail calls the statistics routine at the end of each attempt to send the message to a single node. The statistics routine is provided with information about the sending pass which has just completed. The calling sequence is as follows: ####status = symbiont__stats(node, iocnt) .lm+12 .b.i-8;node####character string by descriptor; input parameter. .b;The destination node name for this pass; it may be the empty string. .b.i-8;iocnt###array of longword integers by reference; input parameter. .b;The network I/O counters, with the following layout: .lt +-------------------+ | links connected | :0 +-------------------+ | APDUs transmitted | :4 +-------------------+ | bytes transmitted | :8 +-------------------+ | APDUs received | :12 +-------------------+ | bytes received | :16 +-------------------+ .el Notes: An APDU is an application protocol data unit; it corresponds to a single DECnet QIO. During the transfer of the body of the mail message, an APDU is either a disk block or a line of text, depending on the capabilities of the receiver. Since the counters apply to a single pass, the "links#connected" value can only be zero or one, depending on whether the connection succeeded. .b.i-8;status##longword value; routine return value. .b;The return status; not currently checked by Nmail. .lm-12 .hl2 The Finish Routine (Symbiont Context) Nmail calls the finish routine when the symbiont has finished processing a message; that is to say, when a job is about to become inactive in the queue. The finish routine is called whether or not the message is fully completed or needs to be requeued. The calling sequence is as follows: ####status = symbiont__finish(alldon) .lm+12 .b.i-8;alldon##longword integer by value; input parameter. .b;True (low bit set) if this is the final execution of this message, false (low bit clear) if the message will be resubmitted for a further attempt. .b.i-8;status##longword value; routine return value. .b;The return status; not currently checked by Nmail. .lm-12 .b2 [End of Nmail Extension Manual]