From: CSBVAX::CSBVAX::MRGATE::"SMTP::CRVAX.SRI.COM::RELAY-INFO-VAX" 23-JAN-1989 09:26 To: MRGATE::"ARISIA::EVERHART" Subj: VMS MAIL: PROFILE and MAI file structures Received: From KL.SRI.COM by CRVAX.SRI.COM with TCP; Wed, 18 JAN 89 22:25:11 PDT Received: from ucbvax.Berkeley.EDU by KL.SRI.COM with TCP; Wed, 18 Jan 89 22:19:42 PST Received: by ucbvax.Berkeley.EDU (5.61/1.33) id AA02302; Wed, 18 Jan 89 21:19:34-0800 Received: from USENET by ucbvax.Berkeley.EDU with netnews for info-vax@kl.sri.com (info-vax@kl.sri.com) (contact usenet@ucbvax.Berkeley.EDU if you have questions) Date: 16 Jan 89 13:24:46 GMT From: munnari!otc!metro!basser!usage!ccadfa!anucsd!csc3!csc!gih900@uunet.uu.net (Geoff Huston) Organization: VMS NEWS V5.2 Subject: VMS MAIL: PROFILE and MAI file structures Message-Id: <1397@csc.anu.oz> Sender: info-vax-request@kl.sri.com To: info-vax@kl.sri.com I have a large number of responses for the definition of the VMS MAIL PROFILE and MAI files. In view of the large number of responses I'll post a description of these file structures to the net. Also the posting to this newsgroup from "palter@victor.eng.buffalo.edu" early in October 88 describing the V5 callable mail interface and included listing of $MAILDEF module is required reading. My advice is that if you want to write a MAIL application, the callable interface description as posted is the preferable method of approach. But if you really want to poke at the bits and bytes, the following is a summary of what I've gleaned from repeated DUMPs of the relevant files. -- Geoff Huston Computer Services, Australian National University gih900@csc.anu.oz ------------snip--------snip---------snip---------------------------------- 1. The VMS MAIL PROFILE file. /* MAIL_PROFILE.H The VMS V4 profile file structure was described in the file SYS$EXAMPLES: MAILUAF.COM, so I won't repeat it here. The V5 profile file is an RMS indexed file, using a single 31 byte key. The records of the file are variable length, with a max size of 2048 bytes: */ #define PROFILE_MAXRECSIZE 2048 #define PROFILE_KEYSIZE 31 #define PROFILE_NAME "VMSMAIL_PROFILE" #define PROFILE_DEFAULT "SYS$SYSTEM:.DATA" /* The format of the file is the username, followed by a number of counted sub-records: */ typedef struct profile_record { char profile_username[PROFILE_KEYSIZE]; char profile_items[PROFILE_MAXRECSIZE - PROFILE_KEYSIZE]; } PROFILE_RECORD; /* The field profile_items are a sequence of structures of the format: +-----------+-------------+---------------------+ | ITEM TYPE | ITEM LENGTH | ITEM DATA | +-----------+-------------+---------------------+ 2 bytes 2 bytes bytes */ typedef struct profile_item { unsigned short profile_item_type; unsigned short profile_item_length; char profile_item_data; } PROFILE_ITEM, *PROFILE_ITEM_PTR; /* The defined ITEM TYPE values are: */ #define PROFILE_K_NEWMAIL 1 /* new mail count */ #define PROFILE_K_FLAGS 2 /* flag field-bit vector */ #define PROFILE_K_DIR 3 /* name of user's mail subdir */ #define PROFILE_K_FORWARD 4 /* mail forwarding address */ #define PROFILE_K_PERSNAME 5 /* user's personal name */ #define PROFILE_K_EDITOR 8 /* selected editor */ #define PROFILE_K_QUEUE 9 /* default queue for printing */ #define PROFILE_K_FORM 13 /* default print form to use */ /* The FLAGS type defines a bit vector of flags - the associated meanings of the bits in this item are: */ #define PROFILE_M_CS_SEND 1 /* Msg copy to self on SEND */ #define PROFILE_M_CS_REPLY 2 /* Msg copy to self on REPLY */ #define PROFILE_M_NOAUTOPURGE 4 /* Do not autopurge WASTEBASKET */ #define PROFILE_M_CS_FORWARD 8 /* Msg copy to self on FORWARD */ #define PROFILE_M_CC_PROMPT 16 /* Prompt for carbon copies- CC: */ /* Or as values rather than offset positions: */ #define PROFILE_V_CS_SEND 0 /* Msg copy to self on SEND */ #define PROFILE_V_CS_REPLY 1 /* Msg copy to self on REPLY */ #define PROFILE_V_NOAUTOPURGE 2 /* Do not autopurge WASTEBASKET */ #define PROFILE_V_CS_FORWARD 3 /* Msg copy to self on FORWARD */ #define PROFILE_V_CC_PROMPT 4 /* Prompt for carbon copies- CC: */ ------------end mail_profile.h----------------------------------------- 2. The VMS MAIL.MAI file. /* MAIL_MAI.H The VMS V4 .MAI files and the V5 .MAI files have the same structure: The MAI file is an RMS indexed file, using two keys. The records of the file are variable length, with a max size of 2048 bytes. The primary key is an unsigned quadword. The secondary key is a 39 byte string, with the NULL flag set (i.e. if the string value is NULL, then that record will not appear in the secondary key index tables). */ #define MAI_MAXREC_SIZE 2048 #define MAI_KEY0_SIZE 8 #define MAI_KEY1_SIZE 39 #define MAI_PROLOG_SIZE 48 #define MAI_HEADER_SIZE 64 #define MAI_NAME "MAIL.MAI" #define MAI_DEFAULT "SYS$LOGIN:" /* All .MAI records have a fixed prolog of 48 bytes: */ typedef struct mai_record { unsigned char mai_key0[MAI_KEY0_SIZE]; char mai_key1_length; char mai_key1[MAI_KEY1_SIZE]; char mai_data[MAI_MAXREC_SIZE - MAI_PROLOG_SIZE]; } MAIL_RECORD, *MAIL_RECORD_PTR; /* There are a number of different record types used in this file. The first set of record types use a small primary key value (as a quadword). The various record types of this format are: */ typedef struct mai_info_record { unsigned int mbz_1; /* must be 0 */ unsigned int mai_record_type; char mbz_2; /* must be 0 */ char mbz_3[[MAI_KEY1_SIZE]; /* null filled string */ char mai_info_data[MAI_MAXREC_SIZE - MAI_PROLOG_SIZE]; } MAI_INFO_RECORD; /* The values of the mai_record_type field are: */ #define MAIL_INFO_KEY 0 #define MAIL_LREAD_RECORD 1 #define MAIL_WASTE_RECORD 2 /* define a new wastebasket name */ #define MAIL_FILEINFO_RECORD 3 /* file information */ #define MAIL_MAILWATCH_RECORD 4 #define MAIL_NEWMESSAGE_RECORD 5 /* I have encountered 2 of these record types in my own .MAI file, and they have the following defintions - the definition of the remainder are left for the reader! A MAI record is used when the wastebasket name is re-defined - the quad key value is 2 for this record type. The wastebasket folder name is stored as a counted string following the fixed record prolog. */ typedef struct mai_wastename { unsigned int waste_fill_1; /* = 0 */ unsigned int waste_type; /* = 2 */ char waste_fill_2; /* = 0 */ char waste_fill_3[MAI_KEY1_SIZE]; /* = 0 */ char waste_name_length; char waste_foldername[MAI_MAXREC_SIZE - MAI_PROLOG_SIZE - 1]; } *MAIL_WASTENAME_PTR; /* A MAI record is ised to store file information - the quad key value is 3 for this record type. Data is stored as a 4 byte value. */ typedef struct mai_fileinfo { unsigned int fileinfo_fill_1; /* = 0 */ unsigned int fileinfo_type; /* = 3 */ char fileinfo_fill_2; /* = 0 */ char fileinfo_fill_3[MAI_KEY1_SIZE]; /* = 0 */ char fileinfo_data[4]; } *MAIL_FINFO_RECORD_PTR; /* Each stored item in the mail file is stored as either 1 or two records. In either case the primary record holds the folder name and the mail header information. This header record may either reference a text record (if the message text is from 0 to 1534 bytes in length), or may reference a .MAI external file if the message is longer than 1534 bytes. The header record has the following structure: */ typedef struct mai_header { unsigned int mai_post_time[2] /* = posting time */ char mai_folder_length; /* non zero */ char mai_folder[MAI_KEY1_SIZE]; unsigned short header_flags; /* item flags - bit vector */ char header_pad[6]; unsigned int mai_text_key[2]; /* key of text record, or (when formatted as a hex string) external file filename */ char header_data[MAI_MAXREC_SIZE - MAI_HEADER_SIZE]; } *MAIL_HEADER_RECORD_PTR; /* The header flags are a bit vector:... */ #define MAIL$M_NEWMSG 1 #define MAIL$M_REPLIED 2 #define MAIL$M_DEL 4 #define MAIL$M_EXTMSG 8 #define MAIL$M_EXTFNF 16 #define MAIL$M_SYSMSG 32 #define MAIL$M_EXTNSTD 64 #define MAIL$M_MARKED 128 #define MAIL$M_RECMODE 256 #define MAIL$S_FLAGSDEF 2 #define MAIL$V_NEWMSG 0 /* This is a new message */ #define MAIL$V_REPLIED 1 /* This message has been replied to */ #define MAIL$V_DEL 2 /* This message is deleted */ #define MAIL$V_EXTMSG 3 /* Message text in external file */ #define MAIL$V_EXTFNF 4 /* External message file not found */ #define MAIL$V_SYSMSG 5 /* Message text in system file */ #define MAIL$V_EXTNSTD 6 /* External file is not var-seq file */ #define MAIL$V_MARKED 7 /* This message has been marked */ #define MAIL$V_RECMODE 8 /* This message should be read in record mode */ /* The field header_data are a sequence of structures of the format: +-----------+-------------+---------------------+ | ITEM TYPE | ITEM LENGTH | ITEM DATA | +-----------+-------------+---------------------+ 2 bytes 2 bytes bytes */ typedef struct header_item { unsigned short header_item_type; unsigned short header_item_length; char header_item_data; } HEADER_ITEM, *HEADER_ITEM_PTR; /* The values for the header type field are: */ #define MAIL_HEADER_FROM 0 /* From: value */ #define MAIL_HEADER_TO 1 /* To: value */ #define MAIL_HEADER_SUBJECT 2 /* Subject: value */ #define MAIL_HEADER_CC 3 /* CC: value */ #define MAIL_HEADER_MAILWATCH 4 /* ?? */ #define MAIL_HEADER_RECORD_COUNT 5 /* record count (type = int) */ #define MAIL_HEADER_EXT_FILESPEC 6 /* external file spec */ #define MAIL_HEADER_UNK 7 /* ?? - all zeros seen so far!*/ /* If the body of the mail text is between 0 to 1534 bytes in length, then the header field mai_text_key is used as the primary key of the internally stored item text. An item text record has the following structure: */ typedef struct mai_text { unsigned short mai_text_key[4]; /* = [d,d,d,4] as words */ char text_fill_1; /* = 0 */ char text_fill_2[MAI_KEY1_SIZE]; /* = 0 */ char text_body[MAI_MAXREC_SIZE - MAI_PROLOG_SIZE]; } *MAIL_TEXT_RECORD_PTR; /* The field text_body is a sequence of counted strings: */ typedef struct text_record { unsigned short text_record_count; char text_record_data; } *MAIL_TEXT_PTR;