This is compactmail.m in view mode; [Download] [Up]
/* -*-C-*-
*******************************************************************************
*
* File: compactmail.m
* RCS: /usr/local/sources/CVS/mailapp-utilities/compactmail.m,v 1.5 1997/05/31 21:52:27 tom Exp
* Description: Compact Mail.app mailboxes (expunge deleted messages)
* Author: Carl Edman
* Created: Fri Mar 12 18:21:23 1993
* Modified: Sat May 31 18:08:13 1997 Tom Hageman <tom@basil.icce.rug.nl>
* Language: Objective C
* Package: mailapp-utilities
* Status: First release.
*
* (C) Copyright 1993, but otherwise this file is perfect freeware.
*
*******************************************************************************
*/
#import <libc.h>
#import <errno.h>
//#import <stdlib.h>
//#import <stdio.h>
//#import <string.h>
//#import <time.h>
#import <regex.h>
//#import <sys/file.h>
//#import <sys/param.h>
//#import <sys/types.h>
//#import <sys/stat.h>
#import <defaults/defaults.h>
#import "mailutil.h"
#import "mailtoc.h"
#import "optutil.h"
#define USAGE "\
Usage: %s [-nruv] [-d days] [-f from] [-s subject] [-V|-H] mbox...\n"
#define HELP "\
-n skip mailbox if locked\n\
-r expunge read messages too (default deleted messages only)\n\
-u expunge all messages (even unread)\n\
-v talkative mode\n\
-d days restrict to messages of at least `days' days old.\n\
-f from restrict to messages whose From: header matches (regexp)\n\
-s subject restrict to messages whose Subject: header matches (regexp)\n\
-V show version\n\
-H this help\n\
"
char line[LINELEN];
int main(int ac,char *av[])
{
char *buf=0;
int c,pos;
int nowaitflg=0,verboseflg=0,deletereadflg=0,deleteunreadflg=0;
int days=-1;
struct regex *subjectregexp=0,*fromregexp=0;
time_t mboxtime;
int mboxdis,tocdis,msgdis,changed;
int mboxfd=-1;
FILE *tocf=NULL;
struct table_of_contents_header *toch=0;
struct message_index *mi=0;
int status=EXIT_SUCCESS;
set_progname(av[0]);
while((c=getopt(ac,av,"d:s:f:nruvVH"))!=EOF) switch(c)
{
case 'd':
if (days!=-1 || (days=atoi(optarg))<=0)
status=EXIT_USAGE;
break;
case 's':
if (subjectregexp || !(subjectregexp=re_compile(optarg,0)))
status=EXIT_USAGE;
break;
case 'f':
if (fromregexp || !(fromregexp=re_compile(optarg,0)))
status=EXIT_USAGE;
break;
case 'n':
nowaitflg++;
break;
case 'r':
deletereadflg++;
break;
case 'u':
deleteunreadflg++;
break;
case 'v':
verboseflg++;
break;
case 'V':
status=EXIT_VERSION;
break;
case 'H':
status=EXIT_HELP;
break;
case '?':
default:
status=EXIT_USAGE;
}
if (status==EXIT_SUCCESS && optind>=ac) status=EXIT_USAGE;
handle_usage_help_version(status, USAGE, HELP);
for(;optind<ac;optind++)
{
if (verboseflg) fprintf(stderr,"Entering %s...\n",av[optind]);
if (cd_mbox(av[optind],1)) goto next;
if (lock_mbox(nowaitflg)) goto next;
mboxtime=mtime("mbox");
if (((mboxfd=open("mbox",O_RDWR))==-1) ||
((tocf=fopen("table_of_contents","r+b"))==NULL))
{
fprintf(stderr,"%s: opening %s: %s\n",progname(),av[optind],strerror(errno));
status=EXIT_FAILURE;
goto unlock;
}
toch=get_table_of_contents_header(tocf,0);
if (!toch)
{
fprintf(stderr,"%s: %s: invalid old table_of_contents\n",progname(),av[optind]);
status=EXIT_FAILURE;
goto unlock;
}
if (toch->mbox_time!=mboxtime)
{
fprintf(stderr,"%s: %s: table of contents out of sync\n",progname(),av[optind]);
status=EXIT_FAILURE;
goto unlock;
}
for(changed=FALSE,msgdis=mboxdis=tocdis=c=0;c<toch->num_msgs;c++)
{
if ((mi=get_message_index(tocf))==0)
{
fprintf(stderr,"%s: %s: reading old mbox entries: %s\n",progname(),av[optind],(errno?strerror(errno):"invalid"));
status=EXIT_FAILURE;
goto unlock;
}
if ((mi->status=='d' || mi->status=='D' || deleteunreadflg ||
(mi->status!='*' && deletereadflg)) &&
(days==-1 || message_age(mi)>=days) &&
(!subjectregexp || re_match(message_subject(mi),subjectregexp)) &&
(!fromregexp || re_match(message_from(mi),fromregexp)))
{
if (verboseflg>1)
{
fprintf(stderr,"Expunging \"%s\" from %s (%d days old).\n",message_subject(mi),message_from(mi),message_age(mi));
}
if (mi->msgtype=='r')
{
char *dir=mi->data;
dir+=strlen(dir)+1;
dir+=strlen(dir)+1;
if (*dir)
{
int pid,childpid=fork();
union wait status;
switch (childpid)
{
case -1:
break;
case 0:
execl("/bin/rm", "rm", "-rf", dir, NULL);
_exit(255);
default:
while ((pid=wait(&status))>=0 && pid!=childpid) ;
}
}
}
changed=TRUE;
msgdis++;
tocdis +=mi->record_length;
mboxdis+=mi->mes_length;
}
else
{
if (verboseflg>2)
{
fprintf(stderr,"Keeping \"%s\" from %s (%d days old).\n",message_subject(mi),message_from(mi),message_age(mi));
}
if (mboxdis!=0)
{
lseek(mboxfd,mi->mes_offset,SEEK_SET);
buf=malloc(mi->mes_length);
read(mboxfd,buf,mi->mes_length);
mi->mes_offset -= mboxdis;
lseek(mboxfd,mi->mes_offset,SEEK_SET);
write(mboxfd,buf,mi->mes_length);
free(buf); buf=0;
}
if (tocdis!=0 || mboxdis!=0)
{
pos=ftell(tocf);
fseek(tocf,-mi->record_length-tocdis,SEEK_CUR);
put_message_index(tocf,mi);
fseek(tocf,pos,SEEK_SET);
}
}
free(mi); mi=0;
}
if (tocdis!=0)
{
fflush(tocf);
pos=fseek(tocf,0,SEEK_END);
ftruncate(fileno(tocf),pos-tocdis);
}
if (mboxdis!=0)
{
pos=lseek(mboxfd,0,SEEK_END);
ftruncate(mboxfd,pos-mboxdis);
}
close(mboxfd), mboxfd=-1;
toch->num_msgs-=msgdis;
mboxtime=mtime("mbox");
if ((toch->mbox_time!=mboxtime) || changed)
{
toch->mbox_time=mboxtime;
fseek(tocf,0,SEEK_SET);
if (put_table_of_contents_header(tocf,toch))
{
fprintf(stderr,"%s: %s: writing updated table_of_contents: %s\n",progname(),av[optind],strerror(errno));
status=EXIT_FAILURE;
goto unlock;
}
}
unlock:
if(mboxfd>=0) close(mboxfd), mboxfd=-1;
if(tocf!=NULL) fclose(tocf), tocf=NULL;
unlock_mbox();
next:;
if (toch) { free(toch); toch=0; }
if (mi) { free(mi); mi=0; }
if (buf) { free(buf); buf=0; }
uncd_mbox();
}
exit(status);
}
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.