[comp.os.vms] Foreign mail interface

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