1825512 Members
1833 Online
109681 Solutions
New Discussion юеВ

MAIL.MAI file structure

 
SOLVED
Go to solution
Ruslan R. Laishev
Super Advisor

MAIL.MAI file structure

Hello All!

I looking for legal structure definition MAIL.MAI file, I'd like to write some application to perfrom an automatic repair ofr VMS mailboxes.


TIA.
5 REPLIES 5
Karl Rohwedder
Honored Contributor

Re: MAIL.MAI file structure

There is a utility called VFYMAIl (e.g. at http://mvb.saic.com/freeware/vmslt03a/vu/), which checks the integrity of your mail file and allows some repairs. I don't know if it satisfies your needs, but perhaps its worth a look.

regards Kalle
Ruslan R. Laishev
Super Advisor

Re: MAIL.MAI file structure

Thanks Karl, I'll look this package. In the same time I interesting by MAIL-structure file provided by VMS-Eng.
Hein van den Heuvel
Honored Contributor
Solution

Re: MAIL.MAI file structure

You're not going to get an official definition.
It was never properly documented.

The structure is easy enough though.
It is just on indexed file with a munged date and time stamp as primary key, and the older name as (duplicates allowed of course) alternate key.
The folder name has a byte count length.
The data is TLV (Tag, Length, Values).
There are Tags for Sender, Subject, CC, BCC and so on.
A quick DUMP/RECORD=COUNT=5 for a known MAIL.MAI will soon bring you up to speed.

Here is a simple program to 'prove' the folder structure by asking RMS to count messages in a specified folder:

#include
#include
#define MYBUFSIZ 8192
char buf[MYBUFSIZ];
main (int argc, char *argv[])
{
struct FAB fab;
struct RAB rab;
int i, stat;

if (argc < 2) return 16;
fab = cc$rms_fab;
rab = cc$rms_rab;
fab.fab$b_shr = FAB$M_SHRPUT;
fab.fab$b_fac = FAB$M_GET;
if (argc > 2) fab.fab$l_fna = argv[2];
if (argc > 2) fab.fab$b_fns = STRLEN( argv[2] );
fab.fab$l_dna = "MAIL.MAI";
fab.fab$b_dns = STRLEN( fab.fab$l_dna );
rab.rab$l_fab = &fab;
rab.rab$b_rac = RAB$C_KEY;
rab.rab$b_krf = 1;
rab.rab$l_ubf = buf;
rab.rab$w_usz = MYBUFSIZ;
rab.rab$l_kbf = argv[1];
rab.rab$b_ksz = STRLEN( argv[1] );
stat = SYS$OPEN ( &fab );
if (stat&1) stat = SYS$CONNECT ( &rab );
if (stat&1) stat = SYS$GET ( &rab ); /* establish next record pointer */
rab.rab$l_rop = RAB$M_LIM;
rab.rab$b_rac = RAB$C_SEQ;
for (i = 0; (stat&1) && (stat!=RMS$_OK_LIM); i++) stat = SYS$FIND ( &rab );
printf ("%d messages\n", i);
return ;
}


And here is a script I made short while ago to construct a mail file to point to mail messages in a directory. It is readily extended to only add message not currently existing (orphans), and to report on messages with a missing external file (runaways).

Once you crack the DCL below, plus that record dump, you will be well on your way to manipulate mail.mai files yourself.


$found_file = "FOUND.MAI"
$folder = "FOUND"
$sender = "Unknown"
$! yeah... there may be quicker ways to make nulls.
$null = "1234"
$null[0,32] = 0
$nulls = null + null + null + null + null + null + null + null + null + null
$record = f$extr(0,92+f$len(sender),nulls + nulls + nulls + nulls + nulls)
$record[8*8,8] = f$len(folder)
$record[9,f$len(folder)] := "''folder'"
$record[48*8,16] = 8 ! External
$record[64*8,32] = %x00140007 ! Tag 7, Len 20, all zeroes
$record[90*8,16] = f$len(sender) ! Tag 0 = from, Len from data
$record[92,f$len(sender)] := "''sender'"
$
$open/write found tmp.tmp
$loop:
$file = f$parse(f$search("mail$*.mai"),,,"NAME")
$if file.eqs."" then goto done
$record[2*8,16] = %x'f$extrac(9,4,file)
$record[4*8,16] = %x'f$extrac(5,4,file)
$record[6*8,16] = %x'f$extrac(17,4,file)
$record[60*8,32] = %x'f$extrac(13,8,file)
$record[56*8,32] = %x'f$extrac(5,8,file)
$write found record
$goto loop
$done:
$close found
$conv/fdl=sys$input tmp.tmp 'found_file
FILE; ALLOC 300; ORG INDEXED
RECORD; SIZE 2048
KEY 0; SEG0_LEN 8; SEG0_POS 0; TYPE bin8
KEY 1; DUP yes; CHANGES yes; SEG0_LEN 39; SEG0_POS 9


And her is a message/folder counter usign the official api.

#include
#include
typedef struct { short len, cod; void *address; int *retlen; } item;
main (int argc, char *argv[])
{
int s, file_context = 0, msg_context = 0, msg_selected = 0;
item null[] = {0,0,0,0};
item msg_begin_in[] = {4,MAIL$_MESSAGE_FILE_CTX,&file_context,0, 0,0,0,0};
item msg_select_in[] = {0,MAIL$_MESSAGE_FOLDER,0,0, 0,0,0,0};
item msg_select_out[] = {4,MAIL$_MESSAGE_SELECTED,&msg_selected,0, 0,0,0,0};

if (argc < 2) return 16;
msg_select_in[0].address = argv[1];
msg_select_in[0].len = strlen(argv[1]);
s = mail$mailfile_begin(&file_context,null,null);
if (s & 1) s = mail$mailfile_open(&file_context,null,null);
if (s & 1) s = mail$message_begin(&msg_context,msg_begin_in,null);
if (s & 1) s = mail$message_select(&msg_context,
msg_select_in,msg_select_out);
printf ("%d messages in folder %s\n",msg_selected,argv[1]);
return s; /* Actually... MAIL will Signal errors unless told not to */
}


Enjoy,
Hein.
Volker Halle
Honored Contributor

Re: MAIL.MAI file structure

Ruslan,

I've also found the MAIL_MAI_TOOLS helpful.

http://groups.google.de/group/vmsnet.mail.pmdf/browse_frm/thread/472417b9a51cd031/6c8e37f9ab7d199a?lnk=st&q=stuffer+mail+vms&rnum=1&hl=de#6c8e37f9ab7d199a

These tools can re-construct a MAIL.MAI file from individual MAIL$nnn.MAI files. You can lean something about the MAIL.MAI record structures from STUFFER.FOR

Volker.
Ruslan R. Laishev
Super Advisor

Re: MAIL.MAI file structure

Thanks a lot to all!
Now I have what I'm need.