KVC@engvax.UUCP.UUCP (09/12/87)
Here are some notes I wrote a few years ago when I figured out how to use the VMS MAIL foreign protocol hook. This is not everything you need to know and my sources are too big to post (they are on the Spring '87 and Spring '85 DECUS tapes anyway). Someone recently posted some sources anyway. Just some details about the interface that I didn't see described by the previous postings. One suggestion I'd like to make! If you think you need to write a foreign interface, think again! Take a look at the PMDF mail system first. PMDF may support your network already. If not, it's FAR easier to write a delivery program for PMDF than a foreign protocol interface. PMDF also provides a centralized mail system supporting multiple networks so you don't have a proliferation of disgusting addresses when the time comes that you want to add more and more network mail facilities. Of course you also get all the other benefits (full RFC-822, store-and-forward of all messages (even DECnet), etc) of PMDF. The PMDF support for the MAIL interface goes far beyond what I've seen in other interfaces. It attempts to deal with MAIL status return conditions and situations that you are not likely to handle correctly. Many long hours were spent initially on the PMDF interface to MAIL and many more were spent rewriting it this summer for PMDF V2.4. PMDF is available for cost of distribution ($50) from: Ned Freed PMDF Project Harvey Mudd College Claremont, CA 91711 (714)621-8006 As promised here are my notes. I wrote these 2 years ago, I believe the fiche references are different. Also, please don't ask for UUCP, you have to have a UNIX source license anyway. /Kevin Carosso kvc@engvax.scg.hac.com Hughes Aircraft Co. kvc%engvax@oberon.usc.edu ------------ UUCP_ROOT:[SOURCE.UUCP_MAIL]NOTES.TXT -------------------- Here's an all too brief description of the foreign mail interface. This information comes from the VMS MAIL source listings on the microfiche. The best place to look is in routine NETJOB in module MAIL$MAIL (page 230, frame E-2), for incoming mail, and in the various routines in NETSUBS (also page 230, frame N-11), which cover both in- and out-bound mail. The fundamental mechanism here is that MAIL recognizes certain address forms as foreign, and uses two mechanisms to hook into a foreign delivery system. Any address of the form: protocol-name%address is an indicator to MAIL that it should be using a foreign mechanism. MAIL first attempts to translate a logical name of the form: MAIL$PROTOCOL_protocol-name If this translates to a string that looks like: %decnet-task-invocation-spec then MAIL will set up the DECnet connection to the task spec it gets after stripping away the "%" and speak MAIL-11 to it. MAIL-11 is, as near as I can figure, the protocol that myself and others were using in VMS V3 to speak to MAIL in order to hook our foreign delivery systems to it. For more information on MAIL-11, see the code for SENDMAIL which I provided on either the Spring or Fall '84 DECUS tapes. I would assume that this protocol is used internally within DEC to get VMS MAIL talking to other DEC operating systems which support DECnet. The second mechanism that MAIL uses to invoke a foreign delivery system is indicated by the absence of a leading "%" in the translation of the logical name I mentioned above or by the complete absence of the logical name. In this case, MAIL uses the new VMS V4 Run-Time Library routine LIB$FIND_IMAGE_SYMBOL to map the interface code into it's address space at run time. If the logical name MAIL$PROTOCOL_protocol-name exists, then it must point to the shareable image to be mapped. If the logical name does not exist, then MAIL will map in the shareable image in SYS$SHARE called: protocol-name_MAILSHR.EXE The VAX-11 PSI product, for example, comes with a shareable image called PSI_MAILSHR.EXE which it places in SYS$SHARE. This allows the PSI product to use MAIL for delivery of messages over a PSI network without the need for DECnet on the network. A little more about foreign addresses: I've experimented with various formats of foreign addresses and I think I've figured out most of the rules. The simplest format is an address of the form: aaa%bbb In this case, the protocol is "AAA" and the address is "BBB" (MAIL upcases the address before doing anything else). If you need to preserve case in the address, then you can use something like: aaa%"bbb" Unlike previous versions of MAIL, the V4 utility preserves case inside quoted character strings. It is possible to include double-quotes inside the protocol portion of the address (i.e. before the "%") to preserve case within the protocol string. The protocol string, however, cannot start with a double quote. Since you, as the foreign interface implementor, have complete control over the protocol naming conventions within the context of a MAIL interface, I would suggest that you not use this feature and make your protocols distinct, regardless of the case of the letters within the protocol name. I say this because I'm not sure what all the rules are when MAIL attempts to translate the logical name or reference a file spec which may have double quotes in it. The foreign address conventions can be mixed with the normal DECnet syntax that MAIL already supports. For example, it should be perfectly reasonable to set up one system on your network as a gateway and have it understand the foreign interface. Other systems on the DECnet network can then route messages through the gateway with an address like: gate::protocol-name%foreign-address The concept of a node name is also supported within the "foreign-address" portion of the string, if you want to use it. For example, MAIL routed over an X.25 network with the PSI product is addressed like: PSI%X.25-network-address::username In my foreign mailer, I could route UUCP messages with an address of the form: UUCP%uucp-host-name::username but because the UUCP network needs to have routing explicitly specified in the address (and for consistency with address formats on other UUCP mailers) I do not use the "host::user" format of a foreign address specification. In my case, mail to be sent out with UUCP is addressed as: UUCP%"host!user" or UUCP%"host1!host2!user", etc. The decision to use MAIL's concept of a "node::user" specifier is completely up to the implementor. If you DO use this syntax, then MAIL will separate the foreign node name and the foreign username before calling your interface routines and will pass them separately. If you do not use it, then you will have to parse your foreign address yourself. ARPAnet addresses, for example, could be handled with either: arpa%sri-kl::info-vax or arpa%"info-vax@SRI-KL" The first is a little cleaner as it does not require double quoting and the interface routines will receive "SRI-KL" and "INFO-VAX" as separate parameters; the second is more consistent with ARPAnet address syntax (the quotes are required because of the "@"). Inbound foreign mail to be delivered to VMS MAIL users is handled by including an undocumented MAIL switch on the MAIL command line. A MAIL command like: $ mail/protocol=protocol-image-name filename recipient will cause MAIL to map in the shareable image specified in "protocol-image-name". Note that the process executing this command must have both SYSPRV and DETACH privileges or MAIL will ignore the switch. This is, I assume, to prevent unauthorized persons from delivering forged mail. Unfortunately, this means that you will have to come up with some way of granting these privileges to your network process that will trusted with mail delivery. I personally do not like this requirement, because my network entity can be trusted with MAIL delivery, but should NOT be trusted with the SYSPRV privilege. A much better solution, I think, would have been to check whether the process attempting to deliver mail posseses a special access control identifier that has been granted by the system manager. But then, I'm a big fan of ACL's and identifiers. The first thing that MAIL does upon mapping in your shareable interface is obtain the values of the two universal symbols MAIL$C_PROT_MAJOR and MAIL$C_PROT_MINOR. I assume that these exist to allow future inclusion of other protocol types. For now, however, the only legal value for either symbol is 1. MAIL invokes the interface when it needs to by calling the entry point in your shareable image called MAIL$PROTOCOL. It calls the same entry point for all functions. The call is of the form: MAIL$PROTOCOL (context, function_code, function-dependent-arguments...) "context" is a variable that you may use for aything you like. Usually, it points to some area that your procedure allocates initially to keep connection-dependent information. You should maintain NO static storage, since your routines must be completely reentrant. Use the context pointer to maintain anything you need between calls. "function_code" refers to any of the values: LNK_C_OUT_CONNECT = 0 LNK_C_IN_CONNECT = 8 LNK_C_IO_READ = 14 LNK_C_OUT_SENDER = 1 LNK_C_IN_SENDER = 9 LNK_C_IO_WRITE = 15 LNK_C_OUT_CKUSER = 2 LNK_C_IN_CKUSER = 10 LNK_C_OUT_TO = 3 LNK_C_IN_TO = 11 LNK_C_OUT_SUBJ = 4 LNK_C_IN_SUBJ = 12 LNK_C_OUT_FILE = 5 LNK_C_IN_FILE = 13 LNK_C_OUT_CKSEND = 6 LNK_C_OUT_DEACCESS = 7 which indicate exactly what function the caller expects. Because it's often difficult or impossible to write procedures that handle varying numbers of arguments, I wrote a simple dispatcher in MACRO that invokes interface routines with fixed argument lists. This means that the interface may be implemented in whatever language the developer likes. The dispatcher (in the file MAILSHR.MAR) is completely independent of any foreign mailer, and can be used to dispatch to several different high-level implementations. For complete information on the protocol, see my UUCP_MAIL.PAS code. There are some interesting tidbits I have discovered: MAIL provides routines in the argument list that look like you are supposed to call them with error text when something goes wrong. I found it a lot easier to simply use the standard VMS message utility and signal errors with a severity level of ERROR. The error message is printed and MAIL recovers control and aborts the send. There may be problems with this not working properly under all circumstances (e.g. when mailing to multiple addresses, if one of the foreign ones is incorrect, MAIL should still attempt to send to the other addresses -- this may not work with a signaled error), but until I figure out exactly how to call the error text routines (UTIL$REPORT_IO_ERROR and MAIL$READ_ERROR_TEXT) I will simply signal my errors. Debugging this is a real trip. I took a copy of MAIL.EXE and used the new PATCH/ABSOLUTE to change the image transfer vectors and image activator flags to force it to come up with the debugger. Then, I assembled a BPT instruction as the first thing in the dispatcher so that the debugger got a breakpoint trap whenever my dispatcher was called. You have to do this because you cannot set a breakpoint in your shareable image until after it's been mapped. I was then able to trace the calls from MAIL. The file MAIL_DBG.EXE is the patched version of VMS MAIL that will come up with the debugger. /Kevin Carosso April 13, 1985