	CALLABLE MAIL

	What is it
	What it isn't
	About callable mail
	Getting started
	The User Profile context
	The Mail File context
	The Message context
	The Send context

What it is:

	Callable mail is a set of routines which you can use to perform
any function that can be done from within the MAIL utility, plus a little.
You can find out what folders exist within a mail file, you can find out
where a specific users mail file is, you can send messages, you can read
messages, etc.

What it isn't:

	It is not a mail transport agent. You can't write a replacement
for handling incoming mail. An example of a transport agent would be
something like PMDF, PonyExpress, and MRGATE. For example, if you are
trying to write a mail agent that speaks to a Unix machine using TCP/IP
speaking whatever protocol they use for sending mail, and want to interface
it directly with VMSMail you'll have a problem! That sort of use requires
knowledge of the "foreign mail protocol" which is also undocumented, although
you can find information on it in the DECUS tapes (sorry, I don't have a
reference handy - check the UUCP/VMSNET submission).

Sources of information:

	All of the material was compiled via reading the microfiche source
listing kit from VMS V5.2. I would also like to acknowledge the resources
of the Internet, for responding to my request for hints & kinks. Copies
of this talk, as well as several example programs, will appear on the
Spring '90 VAX Sig tape. This information is also available to anyone on
BITNET or the Internet, by sending a mail message to "VMSSERV@FHCRCVAX.BITNET"
with the one line of "SEND MAIL.PACKAGE".

About callable mail:

	Callable mail is broken up into four sets of routines, each dealing
with a different aspect of mail. These routines each deal with a particular
"context". The "mail file" context, the "message" context, the "send"
context, and the "user" context.

	The "mail file" context deals with accessing the mail file itself.
This includes opening, closing, and compressing the file, as well as
getting information about the mailfile, including getting a list of all
the folder names, how much space is being wasted, and so forth. All of
the "mail file" routines have names that start with "MAIL$MAILFILE_",
and all of the mail file item codes start with "MAIL$_MAILFILE_".

	The "message" context allows you to access messages. You can
move messages around, read them, or just get information about them,
such as when they were received, who sent it, and so forth. All of the
"message" routines have names that start with "MAIL$MESSAGE_", and all
of the mail file item codes start with "MAIL$_MESSAGE_".

	The "send" context allows you to send messages to users. All of
the "send" routines have names that start with "MAIL$SEND_", and all of
the mail file item codes start with "MAIL$_SEND_".

	The "user" context gives you access to the "user profile
database". This database (SYS$SYSTEM:VMSMAIL_PROFILE.DATA) contains
information about each mail user. This includes all the information you
see when you use the SHOW ALL command within Mail (i.e. the users mail
directory, personal name, forwarding address, etc.). All of the "user"
routines have names that start with "MAIL$USER_", and all of the mail
file item codes start with "MAIL$_USER_".

Conventions:
	Throughout this talk I will refer to routine names and item codes
without actually giving the full name of the routine or item code. All
of the routines have long names that start out with MAIL$, followed by
a name that signifies what context it deals with (i.e. MAILFILE), an
underscore, then the routine name. The item code names are very similar
except they have an underscore before the context name as well.

Getting started:

	All four contexts have a START and END routine, which must be
called to start and end processing within that context. For example,
MAIL$MAILFILE_BEGIN and MAIL$MAILFILE_END. All of the routines have
exactly the same calling sequence. You always pass in a "context"
variable, an "input" item list, and an "output" item list. For example:
             
	status = mail$mailfile_begin(context, input, output);

	The input and output item lists are similar to those used in the
SYS$GET%%I routines. They are arrays where each element of the array
looks like the following C structure definition:

	struct ItemList
	{
	  short buffer_length;
	  short item_code;
	  void *buffer_address;
	  long *return_length_address;
	};

	If you aren't familiar with C, this merely declares a structure with
two "word" integers (2 bytes each), a "longword" (which contains an address)
and another "longword" (which contains the address of a "longword" integer).
The only difference between this and the item lists used by the SYS$GET%%I
routines is that the returned_length_address specifies a longword into
which the length will be returned (the SYS$GET%%I routines return a
word instead).

	Each element of the array describes something that you are either
passing into the routine, or expecting to be passed back. You signify the
end of the item list by filling in all the fields of the structure with a 0.
You must always pass the input and output item lists, even if you don't need
to send in (or get out) any information. For example, you might want to declare
an empty list as follows:

	struct itmlst null_item = {0,0,0,0};
	status = mail$mailfile_begin(context, &null_item, &null_item);

	All of the routines will signal any errors they encounter, as well
as returning them as the result of the call, unless you specifically request
them not to signal errors, which you do by including the item code
"MAIL$_NOSIGNAL" in the input item list.

The User Profile context:

	The user profile routines allow you to get information about
any specific mail user. As I mentioned earlier, you MUST call the
BEGIN routine to start a user context, and the END routine to finish.
If you plan to open somebody elses mail file, you will need to acces
the user profile database to find out where it is!

	I should note that there doesn't have to be a one-to-one
correspondence between the list of authorized users (as seen by AUTHORIZE),
and the list of "mail users". For instance, when you create an account with
AUTHORIZE, the user profile database isn't automatically updated to include
that user. The user would only be added when that user invokes mail (or a
message gets sent to them). When you delete accounts from within AUTHORIZE,
the user profile database doesn't get modified either, so the user is never
removed! You can also add records to the user profile database that don't
correspond to any real users. For example, within MAIL you can say:
	MAIL> SET FORWARD/USER=mail-username real-username
which will create an entry in the user profile database for "mail-username".

	There are just 5 user profile routines, MAIL$USER_BEGIN and
MAIL$USER_END (as with all the contexts), plus MAIL$USER_DELETE_INFO,
MAIL$USER_GET_INFO and MAIL$USER_SET_INFO.

	MAIL$USER_DELETE_INFO completely removes a username from the database.
You must pass it (in the input item list) the username to remove.

	MAIL$USER_GET_INFO and MAIL$USER_SET_INFO get and set information
about any given username. You can use the GET_INFO routine to go through
all the records in the database (by using the item codes MAIL$_USER_FIRST
and MAIL$_USER_NEXT), or to return information about a specific username
(by using MAIL$_USER_USERNAME). If you don't specify who to get information
on, it will return information about the process making the call.

Here's a short C code fragment to demonstrate the GET_INFO routine:

#include maildef /* if you have VAX C 3.0 or greater */

int display_editor_setting()
{
  char editor[255];
  int len, status, context = 0;
  struct ItemList
    out_list[] = {{sizeof editor, MAIL$_USER_EDITOR, editor, &len}, {0,0,0,0}},
    null_list[] = {{0,0,0,0}};

  if (!((status = mail$user_begin(&context, null_list, null_list)) & 1))
    return status;

  if (mail$user_get_info(&context, null_list, out_list) & 1)
    printf("Editor is defined as %.*s\n", len, editor);

  return mail$user_end(&context, null_list, null_list);
}

Note that VMS Mail also translates the logical name MAIL$EDIT to determine
what editor you want to use. If this logical exists, it supersedes the
information in the User Profile Database (this only applies if you're
getting information on yourself of course).

When you want to add a new user to the User Profile Database, you need
to use the MAIL$USER_SET_INFO routine. You must pass in the username and
tell it to create the record if it doesn't exist by passing in the two
item codes MAIL$_USER_USERNAME, and MAIL$_USER_CREATE_IF. You must also
pass in at least one of the MAIL$_USER_SET_xxx item codes, otherwise the
record will not be created, for example you might set the new message
count to zero by specifying MAIL$_USER_SET_NEW_MESSAGES.

The Mailfile context:

	The Mailfile context allows you to access a mail file. You can
open and close mail files (for use with the message context), purge
and/or compress them, modify the name of the wastebasket, and list the
folder names within the mail file.

	The OPEN routine (MAIL$MAILFILE_OPEN) can return a flag
indicating whether the mail file is an indexed file or not. This is
important as several operations do not work with the old style
sequential files. Specify the INDEXED item (MAIL$_MAILFILE_INDEXED) in
the output item list to return whether the file is indexed or not.

	The INFO_FILE routine can be used to retrieve a list of all the
folder names. To do so, you use the FOLDER_ROUTINE item and you pass it
the address of a "folder action routine". This is simply a routine which
will get called once for each folder that exists in the mail file. The
routine you specify will be passed two arguments, the first one is the
user data specified by the USER_DATA item (or 0), and the second one is
a string containing a folder name. Your routine will be called one extra
a time with a blank folder name to specify that there are no more folders
to process. For examples of this, check out the LIST-FOLDERS-n.C
routines in the appendix (or on the SIG tape).

	The other routines and items are fairly self explanatory so I
won't go into any further detail about them.

The Message Context:

	The Message context is used to read and copy/move mail messages.
These routines are different from the rest, in that before you can begin
a message context, you must use the mailfile context to open a mail
file. Once you have done that, you must pass the address of the mailfile
context variable in to MAIL$MESSAGE_BEGIN.

	All messages within a folder have an ID associated with them,
which currently appears to be simply an integer starting at 1 for the
first message, incrementing for each new message. When you BEGIN a new
message context, you can retrieve the first message by using the NEXT
item code, or by explicitly stating what ID you want to start with. If
you SELECT a new folder, without beginning a new message context, the
NEXT item code will not necessarily return the first message. To get
around this, you can either take advantage of the fact that the ID is
simply an integer and ask for the first item explicitly, or you can END
the current message context and BEGIN a new one. Using the END and BEGIN
sequence saves you from taking advantage of (potentially internal,
highly changeable) knowledge about an ID.

	Each message in a mail file also has a set of flags associated
with them. There are actually two sets of flags, one is a 2 byte system
defined flag, and the other is a 4 byte user defined flag. The user
defined flag longword is (of course) undefined, and can be used anyway
you like. Just realize that any other program is free to do the same.
The system defined flag word has the following bits defined:

	mail$v_newmsg	/*This is a new message            */
	mail$v_replied	/*This message has been replied to */
|Note that mail$v_del and mail$v_dwmail are the same bit...
|	mail$v_del	/*This message is deleted          */ v5.0, 5.1?
|__	mail$v_dwmail	/*DW mail flag                     */ v5.1? v5.2
	mail$v_extmsg	/*Message text in external file    */
	mail$v_extfnf	/*External message file not found  */
|Note that mail$v_sysmsg and mail$v_notrans are the same bit...
|	mail$v_sysmsg	/*Message text in system file      */ v5.0, 5.1?
|__	mail$v_notrans	/*No translator for this message   */ v5.1? v5.2
	mail$v_extnstd	/*External file is not var-seq file*/
	mail$v_marked	/*This message has been marked     */
	mail$v_recmode	/*This message should be read in record mode */

	If the EXTMSG flag is set, then the message is stored in an
external file. You can use the EXTID item code to have the name of the
file returned to you. A message can be stored externally for several
reasons. If the message is too large to fit within a single record of
the mail file (about 3 blocks), then it will be stored externally.
Further, if the message is in a foreign format (either a CDA document,
or mailed using the MAIL/FOREIGN command [which can be used to mail
executable files for instance]), then the message has to be stored
externally. The EXTNSTD flag is used to show that the file is in not a
plain ascii file, and may require a translator of some sort (if it's CDA
compliant). The RECMODE flag specifies that you should use record mode
to retrieve records from the message, which will invoke the appropriate
translator to retrieve the document in textual format. The NOTRANS flag
(previously called SYSMSG) signifies that there is no translator for
the file. This can occur when you use MAIL/FOREIGN to send an executable
image for example.


	When you COPY a mail message, you can end up creating a new
folder, or even a new mail file. You can use an action routine (similar
to the folder action routine in the MAILFILE context), to intercept
actions that would create a new mailfile or new folder. You could use
this to notify the user about what is going to take place for instance.
If your action routine returns an error status (i.e. an even number),
then the file or folder will not be created (and an error status will
be returned by the COPY routine). You must specify the destination
folder name, and in general, you will also want to specify the mailfile
name since it does not default to the currently open mailfile, instead
it appears to default to SYS$LOGIN:MAIL.MAI, which may happen to be
correct, but usually isn't! You can also have the message deleted from
the original folder by specifying the DELETE item code.

The Send Context:

	The send context gives you the ability to send mail messages.
All you need to do is to call the ADD_ADDRESS routine, passing it a
USERNAME to send the message to, call ADD_BODY_PART to pass the message
(either a record at a time, or a filename, but not both in one call),
then call the MESSAGE routine to actually send the message. You can
create a CC list by calling the ADD_ADDRESS routine, passing in a
username, and passing in the USERNAME_TYPE item which should point to a
longword containing the value MAIL$_CC. By passing a USERNAME_TYPE of
MAIL$_TO you can add usernames to the TO line, however this appears to
be the default behavior anyway.

	Th ADD_ATTRIBUTE routine allows you to specify your own text
for the contents of the CC_LINE, SUBJECT, TO_LINE and even the
FROM_LINE. Changing the FROM_LINE requires SYSPRV privilege however. To
emulate the SEND/FOREIGN (or MAIL/FOR) command withing MAIL, you can
also specify the FOREIGN item to the ADD_ATTRIBUTE routine.

	The ADD_BODYPART routine allows you to specify what the text of
the message will be. You can either pass text in a record at a time with
the RECORD item, or you can pass a file to be used (by FILENAME, or by
FID).

	Note, when you are sending messages, the setting of the
COPY_SELF flags (COPY_FORWARD, COPY_REPLY, COPY_SEND) is not
automatically honored, you must do this yourself. You can find this
information out with the BEGIN routine, or if you are performing a send
on behalf of somebody else, you could use the MAIL$USER_GET_INFO routine
to determine it.

Known problems, quirks:

	Sequential mail files aren't well supported. For example, if you
attempt to retrieve the date for a message in a sequential file, you
usually get 17-NOV-1858. A (non-DEC) suggested work-around is to extract
the date from the FROM: field (the last 17 characters).

	Other problems with sequential mail files are more obvious, and
relate to the fact that they don't have an index. Attempts to use any
selection items, such as FOLDER, SUBJ_SUBSTRING or any other substring
item won't work with sequential mail files, and produce an error.

	The callable routines check your process privileges for certain
things, such as when you specify the FROM field when you are sending a
message. To be allowed to set the FROM field, you must have SYSPRV
privilege enabled. The routines check your PROCPRIV mask rather than
your CURPRIV mask, so that (for instance) installing your program with
SYSPRV won't automatically allow the FROM field to be specified. Your
code would have to explicitly enable the privilege via SYS$SETPRV.

Wishlist:

	There is no capability for application specific values, which is
quite dissappointing, given the format of the user profile database, and
the mail files themselves. It should be easy for DEC to implement some
sort of "application registry", so that an application could have it's
own set of data and item codes for storing and retrieving information
from the user profile database, mail files, and even messages.
