The result was that the user ended up with about 260 messages in their
MAIL folder and 60 messages in NEWMAIL (there are no other folders!).
Unfortunately their [.MAIL] subdirectory contains around 1300
MAIL$*MAI;1 files. So we got the user to issue a SET MAIL [.MAIL2]
command from mail expecting to end up with about 320 files (approx) in
[.MAIL2], and about 980 in [.MAIL] which we could delete.
Unfortunately ALL 1300 files got moved into [.MAIL2].
It seems like whatever algorithm MAIL uses to relocate its
MAIL$....MAI files is only approximate - possibly involving a
wildcard.
MAIL simply moves *all* files that have the right form.
Does anyone have a procedure for getting rid of spurious
MAIL$....MAI files?
I have two, one which I've used successfully, written in C; and one I've
never tried (though knowing the author, it probably works) which is a command
file. I've attached both below.
-- Jerry
----------------MAIL-SCAN.COM----------------
$!
$! From a message posted to INFO-VAX.
$!
$! Subject: Re: Yet ANOTHER Mail Problem ...
$! From: vanden...@eps.enet.dec.com (Hein RMS van den Heuvel)
$! Date: 24 OCT 94 09:35:27
$!
$! ...
$! So now lets move to the secondary problem you managed to get into.
$! There are a number of mail 'orphan' detectors on the net that should be
$! able to deal with this gracefully.
$!
$! It so happens (ha!) that I've written a special purpose on not too long
$! ago, that I'll repost. It is not too clean and you'll need to wrap it in a
$! 'loop though all users' too, and for now it only reports. You may want to
$! change it to generate a massive command file to delete or move all orphans
$! found. No smarts about current directory or mail file names, but it works
$! for me! Yes, a 'real' program with more RMS buffers would work faster and
$! without exceptions for 'funny' key values, but this thingie should get you
$! going. You can speed it up by giving it 98 as argument which cause it to
$! bother only with files after 15-Jun this year.
$start:
$i = 0
$key = "12345678"
$start_date = P1 ! 96="2-Sep-1992", 97="24-Jul-1993", 98="15-Jun-1994"
$OPEN/READ/SHARE=WRITE/ERROR=Oooops file MAIL.MAI
$loop:
$ i = i + 1
$ IF i.EQ.(i/100)*100 THEN WRITE sys$output i, " files. Last file ", file_name
$ file_name = f$search ( "MAIL$*.MAI" )
$ IF file_name .eqs. "" THEN GOTO done
$ id = F$PARSE(file_name,,,"NAME","SYNTAX_ONLY") - "MAIL$"
$ IF start_date .GTS. F$EXTRACT(14,2,id) THEN GOTO loop
$key[48,16]=%x'f$extract(12,4,id)
$key[16,32]=%x0005'f$extract(0,8,id)
$key[0,16]=0
$q = F$LOC("""",key) ! help read/key with quotes in key string a little
$if q.ne.8 then key = F$EXT(0,q,key) + "!" + F$EXT(q+1,8,key)
$READ/MATCH=GE/KEY=&key file rec
$bin_date = F$EXTRACT(0,8,rec)
$asc_date = F$FAO("!%D",f$cvui(32,32,f$fao("!AD",8,bin_date)))
$k1 = F$FAO("!XL", F$CVSI(16,32,rec))
$k2 = F$FAO("!XL", F$CVSI(48,16,rec))
$folder = F$EXTRACT(9,F$CVSI(0,8,F$EXTRACT(8,1,rec)),rec)
$IF F$EXTRACT(0,8,id).EQS.k1 THEN GOTO loop ! Close enough
$WRITE SYS$OUTPUT asc_date, " ", id, " ", k1, " ", k2, " ", folder
$GOTO loop
$
$Done:
$WRITE sys$output i, " files processed in total."
$CLOSE file
$EXIT
$
$Oooops:
$WRITE SYS$OUTPUT "Failed to open MAIL.MAI"
$EXIT
$!
$! Hope this helps, +--------------------------------------+
$! | All opinions expressed are mine, and |
$! Hein van den Heuvel, Digital | may not reflect those of my employer |
$! vanden...@eps.enet.dec.com +--------------------------------------+
----------------MAILCOUNT.C----------------
/* MAILCOUNT.C
Description: This program determines the location of a user's mail directory,
tabulates all MAIL$nnnnnnnnnnnnnnnn.MAI files found and correlates this
information with the files expected in MAIL.MAI. A summary report is output
at the end indicating if any extra files exist, or if any are missing. It
does a lot of work, so it can take a while to execute...
Environment: Works in the mail environment for the current username only.
Privileges required: none
Written: H. Brydon, December 1991
Disclaimer: Be kind to me - I'm a new C programmer. I know it looks like
Fortran.
Modifications:
*/
#include descrip
#include ctype
#include maildef
#include fscndef
#include <stdio.h>
long stat;
#define ckstat(x) if(((stat = x) & 7) != 1) SYS$EXIT(stat)
#define min(a,b) ((a) < (b) ? (a) : (b))
#define TRUE (1)
#define FALSE (0)
#define maxmsgs 5000 /***/
typedef struct _ItemList
{
short buffer_length;
short item_code;
void *buffer_address;
long *return_length_address;
} ItemList;
typedef struct _minfo /* Structure to hold message info */
{ char name[26]; /* Name of external message */
unsigned ptrfound : 1; /* Ptr to message identified */
unsigned msgfound : 1; /* Actual message file has been located */
} Minfo;
Minfo msgs[maxmsgs];
int msgctr = -1;
char mfds[255];
int mfdslen;
/*
add_msgid scans the Minfo data and adds a given message name if
not already there, or updates the information if previously entered
*/
unsigned add_msgid(char *msgid, unsigned pf, unsigned mf)
{
int i;
char *p;
if(msgid[0] == 0)
{
fprintf(stderr,
"\nMAILCOUNT-W: Attempt to enter null string\n");
}
if (++msgctr >= maxmsgs)
{
fprintf(stderr,
"\nMAILCOUNT-F: Number of messages exceeds maxmsgs(%d) - recompile required\n",
maxmsgs);
exit(2);
}
if(strlen(msgid) > sizeof msgs[msgctr].name)
{
fprintf(stderr,
"\nMAILCOUNT-W: Size of message name exceeds data field size\n");
fprintf(stderr, "Message file name: >%s<", msgid);
}
/* Strip the ".MAI" extension and anything after it... */
for(p=msgid; p<=msgid + sizeof msgs[msgctr].name; p++)
if(*p == ".") *p = 0;
strcpy(msgs[msgctr].name, msgid);
for(i=0; i<= msgctr; i++)
if(!strcmp(msgs[i].name, msgid))
{
msgs[i].ptrfound |= pf;
msgs[i].msgfound |= mf;
if (i == msgctr)
{
return 1;
}
else
{
msgctr--;
return 0;
}
}
}
int folder_routine(int *pfctx, struct dsc$descriptor *name)
{
static int folders = 0;
short rectype;
char subject[510], extid[255];
int subjlen, extid_len;
int mcontext =0;
ItemList
null_list[] = {{0,0,0,0}},
mslist[] = {
{0, MAIL$_MESSAGE_FOLDER, 0, 0},
{0, MAIL$_NOSIGNAL, 0, 0},
{0,0,0,0}},
mblist[] = {{4,MAIL$_MESSAGE_FILE_CTX,pfctx,0},
{0,0,0,0}},
milist[] = {{0,MAIL$_MESSAGE_NEXT,0,0},
{0,MAIL$_NOSIGNAL,0,0},
{0,0,0,0}},
molist[] = {{sizeof subject, MAIL$_MESSAGE_SUBJECT, subject, &subjlen},
{sizeof extid, MAIL$_MESSAGE_EXTID, extid, &extid_len},
{0,0,0,0}};
if (name->dsc$w_length)
{
ckstat(mail$message_begin(&mcontext, mblist, null_list));
mslist[0].buffer_length = name->dsc$w_length;
mslist[0].buffer_address = name->dsc$a_pointer;
if (mail$message_select(&mcontext, mslist, null_list) & 1)
{
printf("\nScanning folder %.*s...",
name->dsc$w_length, name->dsc$a_pointer);
++folders;
while (mail$message_info(&mcontext, milist, molist) & 1)
{
subject[subjlen] = 0;
extid[extid_len] = 0;
if(extid_len)
{
/* printf("\n Message %.*s found, subj=%.*s", /**/
/* extid_len, extid, min(subjlen, 50), subject); /**/
add_msgid(extid, TRUE, FALSE);
}
}
ckstat(mail$message_end(&mcontext, null_list, null_list));
}
}
else
{ /* no more folders, print out the total! */
printf("\n\n Total of %d folder%s processed\n",
folders,(folders == 1)?"":"s");
}
return 1;
}
/*
get_names_from_mail_mai collects the names of all valid external
MAIL$nnnnnnnnnnnnnnnn.MAI files from the user's mail.mai file.
*/
unsigned get_names_from_mail_mai()
{
int sts;
int mcontext=0;
int fcontext=0;
ItemList
null_list[] = {{0,0,0,0}},
mblist[] = {{4,MAIL$_MESSAGE_FILE_CTX,&fcontext,0}, {0,0,0,0}},
mflist[] = {{4,MAIL$_MAILFILE_FOLDER_ROUTINE,folder_routine,0},
{4,MAIL$_MAILFILE_USER_DATA,&fcontext,0},
{0,0,0,0}};
if (mail$mailfile_begin(&fcontext, null_list, null_list) & 1)
{
if (mail$mailfile_open(&fcontext, null_list, null_list) & 1)
{
ckstat(mail$mailfile_info_file(&fcontext, mflist, null_list));
mail$mailfile_close(&fcontext, null_list, null_list);
}
mail$mailfile_end(&fcontext, null_list, null_list);
}
printf(
"\n Total of %d message%s found following processing of MAIL.MAI file",
msgctr+1,(msgctr==0)?"":"s");
}
/*
get_names_from_dir collects the names of all existing external
MAIL$nnnnnnnnnnnnnnnn.MAI files from the user's mail [sub]directory.
*/
unsigned get_names_from_dir()
{
int i;
int ffcontext;
char *filext;
char rfs[200];
struct dsc$descriptor rfs_desc =
{sizeof rfs, DSC$K_DTYPE_T, DSC$K_CLASS_S, rfs};
struct dsc$descriptor dfs_desc =
{strlen(mfds), DSC$K_DTYPE_T, DSC$K_CLASS_S, mfds};
$DESCRIPTOR(filespec_desc, "*.MAI");
ffcontext = 0;
while(lib$find_file(&filespec_desc, &rfs_desc, &ffcontext, &dfs_desc, 0,
0, 0) & 1)
{
/*
rfs now has device, directory, name, extension and version info in it. We
need to locate the name.ext info only and pass to add_msgid.
*/
filext = &rfs[sizeof rfs];
for(i = 0; i <= sizeof rfs; i++)
if(rfs[i] == ';')
{
rfs[i] = 0;
filext = &rfs[i];
break;
}
while(filext > &rfs)
if( *--filext == ']')
{
filext++;
break;
}
add_msgid(filext, FALSE, TRUE);
}
printf(
"\n Total of %d message%s found following processing of mail directory",
msgctr+1,(msgctr==0)?"":"s");
}
/*
make_report outputs the list of all MAIL$nnnnnnnnnnnnnnnn.MAI files that
either exist but have no pointer referencing them or do not exist but a
dangling pointer assumes they are present.
*/
unsigned make_report()
{
int i;
for(i=0; i<= msgctr; i++)
{
if ((!msgs[i].ptrfound) && msgs[i].msgfound)
{
printf("\nNo mail file pointer exists for external file %s",
msgs[i].name);
}
else if ((msgs[i].ptrfound) && (!msgs[i].msgfound))
{
printf("\nPointer exists but no external file %s found",
msgs[i].name);
}
}
}
main (int argc, char *argv[])
{
int ucontext;
ItemList
null_list[] = {{0,0,0,0}},
info_list[] = {
{sizeof mfds, MAIL$_USER_FULL_DIRECTORY, &mfds, &mfdslen},
{0,0,0,0}};
ucontext = 0;
ckstat(mail$user_begin(&ucontext, null_list, info_list));
mfds[mfdslen] = 0;
printf("\n Mail files are in directory %.*s\n", mfdslen, mfds);
get_names_from_mail_mai();
get_names_from_dir();
make_report();
}