v20i051: procmail - mail processing program v2.02, Part03/03
Stephen R. van den Berg
berg at messua.informatik.rwth-aachen.de
Mon Jun 17 14:31:58 AEST 1991
Submitted-by: Stephen R. van den Berg <berg at messua.informatik.rwth-aachen.de>
Posting-number: Volume 20, Issue 51
Archive-name: procmail/part03
Environment: UNIX, sendmail
Supersedes: procmail: Volume 17, Issue 31-32
---- Cut Here and feed the following to sh ----
#!/bin/sh
# This is part 03 of procmail
# ============= procmail/retint.c ==============
if test ! -d 'procmail'; then
echo 'x - creating directory procmail'
mkdir 'procmail'
fi
if test -f 'procmail/retint.c' -a X"$1" != X"-c"; then
echo 'x - skipping procmail/retint.c (File already exists)'
else
echo 'x - extracting procmail/retint.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'procmail/retint.c' &&
X/************************************************************************
X * Collection of routines that return an int (sort of anyway :-) *
X * *
X * Copyright (c) 1990-1991, S.R.van den Berg, The Netherlands *
X * The sources can be freely copied for non-commercial use. *
X * #include "README" *
X * *
X * #include "STYLE" *
X * *
X ************************************************************************/
X#ifdef RCS
Xstatic char rcsid[]="$Id: retint.c,v 2.0 1991/06/10 14:35:35 berg Rel $";
X#endif
X#include "config.h"
X#include "procmail.h"
X#include "shell.h"
X
Xsetdef(name,contents)const char*const name,*const contents;{
X strcat(strcat(strcpy(sgetcp=buf2,name),"="),contents);
X readparse(buf,sgetc,0);sputenv(buf);}
X
Xchar*backblock; /* what is to be recovered in case of filter failure */
Xlong backlen; /* its length */
Xpid_t pidfilt,pidchild;
Xint pbackfd[2]; /* the emergency backpipe :-) */
X
Xpipthrough(line,source,len)char*line,*source;const long len;{
X int pinfd[2],poutfd[2];
X rpipe(pbackfd);rpipe(pinfd);flaggerd=0; /* main pipes setup */
X if(!(pidchild=fork())){ /* create a sending procmail */
X backblock=source;backlen=len;signal(SIGTERM,stermchild);
X signal(SIGINT,stermchild);signal(SIGHUP,stermchild);
X signal(SIGQUIT,stermchild);rclose(rc);rclose(PRDI);rclose(PRDB);
X rpipe(poutfd);rclose(STDOUT);
X if(!(pidfilt=fork())){ /* create the filter */
X rclose(PWRO);rclose(PWRB);rdup(PWRI);rclose(PWRI);getstdin(PRDO);
X callnewprog(line);}
X rclose(PWRI);rclose(PRDO);
X if(forkerr(pidfilt,line)){
X rclose(PWRO);stermchild();}
X if(dump(PWRO,source,len)){ /* send in the text to be filtered */
X writeerr(line);stermchild();}
X if(pwait&&waitfor(pidfilt)!=EX_OK){ /* check the exitcode of the filter */
X progerr(line);stermchild();}
X rclose(PWRB);kill(thepid,SIGQUIT);exit(EX_OK);} /* tell parent to proceed */
X rclose(PWRI);rclose(PWRB);getstdin(PRDI);
X if(forkerr(pidchild,"procmail"))
X return 1;
X return 0;} /* we stay behind to read back the filtered text */
X
Xwaitflagger(){ /* wait for SIGQUIT from child */
X while(!flaggerd)
X suspend();} /* to prevent polling */
X
Xgrepin(expr,source,len,casesens)const char*const expr,*const source;long len;{
X pid_t pid;int poutfd[2];static const char*newargv[5]={0,"-e"};
X newargv[3]=casesens?(char*)0:"-i";*newargv=tgetenv(grep);newargv[2]=expr;
X rpipe(poutfd);
X if(!(pid=sfork())){ /* start grep */
X rclose(PWRO);rclose(rc);getstdin(PRDO);shexec(newargv);}
X rclose(PRDO);len=dump(PWRO,source,len);
X if(!forkerr(pid,*newargv)){
X if(len)
X writeerr(*newargv);
X else
X return waitfor(pid)!=EX_OK;} /* did it grep? */
X return EX_UNAVAILABLE;}
X
Xwaitfor(pid)const pid_t pid;{int i; /* wait for a specific process */
X while(pid!=wait(&i)||(i&127)==127);
X return i>>8&255;}
X
Xgetstdin(pip)const int pip;{
X rclose(STDIN);rdup(pip);rclose(pip);}
X
Xcallnewprog(newname)const char*const newname;{
X if(sh){const char*newargv[4]; /* should we start a shell? */
X yell(executing,newname);newargv[3]=0;newargv[2]=newname;
X newargv[1]=tgetenv(shellflags);*newargv=tgetenv(shell);shexec(newargv);}
X {register const char*p;int argc;const char**newargv;
X argc=1;p=newname; /* If no shell, chop up the arguments ourselves */
X if(verbose){
X log(executing);log(oquote);goto no_1st_comma;}
X do{ /* show chopped up command line */
X if(verbose){
X log(",");
Xno_1st_comma:
X log(p);}
X while(*p++);}
X while(argc++,*p!=TMNATE);
X if(verbose)
X log(cquote);
X newargv=malloc(argc*sizeof*newargv);p=newname;argc=0; /* alloc argv array */
X do{
X newargv[argc++]=p;
X while(*p++);}
X while(*p!=TMNATE);
X newargv[argc]=0;shexec(newargv);}}
X
Xwriteerr(line)const char*const line;{
X log("Error while writing to");logqnl(line);}
X
Xforkerr(pid,a)const pid_t pid;const char*const a;{
X if(pid==-1){
X log("Failed forking");logqnl(a);return 1;}
X return 0;}
X
Xprogerr(line)const char*const line;{
X log("Program failure of");logqnl(line);}
X
Xopena(a)const char*const a;{
X lastfolder=cstr(lastfolder,a);yell("Opening",a);
X return ropen(a,O_WRONLY|O_APPEND|O_CREAT,0666);}
X
Xyell(a,b)const char*const a,*const b;{ /* log if -d option set */
X if(verbose){
X log(a);logqnl(b);}}
X
Xunlock(lockp)const char**const lockp;{
X lcking=1;
X if(*lockp){
X yell("Unlocking",*lockp);
X if(unlink(*lockp)){
X log("Couldn't unlock");logqnl(*lockp);}
X free(*lockp);*lockp=0;}
X if(nextexit==1){ /* make sure we are not inside terminate already */
X log(newline);terminate();}
X lcking=0;}
X
Xnomemerr(){
X log("Out of memory\nbuffer 0: \"");buf[linebuf-1]=buf2[linebuf-1]='\0';
X log(buf);log("\"\nbuffer 1:");logqnl(buf2);retval=EX_OSERR;terminate();}
X
Xlogqnl(a)const char*const a;{
X log(oquote);log(a);log(cquote);}
X
Xnextrcfile(){const char*p; /* next rcfile specified on the command line */
X while(p= *gargv){
X gargv++;
X if(!strchr(p,'=')){
X rcfile=p;return 1;}}
X return 0;}
X
Xrclose(fd)const int fd;{int i; /* a sysV secure close (signal immune) */
X while((i=close(fd))&&errno==EINTR);
X return i;}
X
Xrwrite(fd,a,len)const int fd,len;void*const a;{int i; /* a sysV secure write */
X while(0>(i=write(fd,a,(size_t)len))&&errno==EINTR);
X return i;}
X
Xrread(fd,a,len)const int fd,len;void*const a;{int i; /* a sysV secure read */
X while(0>(i=read(fd,a,(size_t)len))&&errno==EINTR);
X return i;}
X
Xropen(name,mode,mask)const char*const name;const mode_t mask;{int i,r;
X for(r=noresretry;0>(i=open(name,mode,mask));) /* a sysV secure open */
X if(errno!=EINTR)
X if(!((errno==EMFILE||errno==ENFILE)&&(r<0||r--)))
X break; /* survives a temporary "file table full" condition */
X return i;}
X
Xrdup(p)const int p;{int i,r;
X for(r=noresretry;0>(i=dup(p));) /* catch "file table full" */
X if(!((errno==EMFILE||errno==ENFILE)&&(r<0||r--)))
X break;
X return i;}
X
Xrpipe(fd)int fd[2];{int i,r;
X for(r=noresretry;0>(i=pipe(fd));) /* catch "file table full" */
X if(!((errno==EMFILE||errno==ENFILE)&&(r<0||r--))){
X *fd=fd[1]= -1;break;}
X return i;}
X
Xlockit(name,lockp)char*name;const char**const lockp;{int i;struct stat stbuf;
X unlock(lockp); /* unlock any previous lockfile FIRST */
X if(!*name)
X return;
X for(lcking=1;;){ /* to prevent deadlocks (I hate deadlocks) */
X yell("Locking",name);
X if(!NFSxopen(name)){
X *lockp=tstrdup(name); /* lock acquired, hurray! */
Xterm: if(nextexit){
X log(whilstwfor);log("lockfile");logqnl(name);terminate();}
X lcking=0;return;} /* check if it's time for a lock override */
X if(errno==EEXIST&&!stat(name,&stbuf)&&!stbuf.st_size){time_t t;
X if(locktimeout&&(t=time((time_t*)0),!stat(name,&stbuf))) /* from stat */
X if(locktimeout<t-stbuf.st_mtime){ /* till unlink should be atomic */
X if(unlink(name)){ /* but can't guarantee that */
X log("Forced unlock denied on");logqnl(name);}
X else{
X log("Forcing lock on");logqnl(name);suspend();}}}
X else{ /* maybe filename too long, shorten and retry */
X if(0<(i=strlen(name)-1)&&!strchr(dirsep,(name[i-1]))){
X name[i]='\0';continue;}
X log("Lockfailure on");logqnl(name);return;}
X sleep(DEFlocksleep,locksleep);
X if(nextexit)
X goto term;}}
X
Xlcllock(){ /* lock a local file (if need be) */
X if(locknext)
X if(tolock)
X lockit(tolock,&loclock);
X else
X lockit(strcat(buf2,tgetenv(lockext)),&loclock);}
X
Xterminate(){
X nextexit=2; /* prevent multiple invocations of terminate */
X if(retval!=EX_OK)
X log("Mail bounced\n");
X unlock(&loclock);unlock(&globlock);exit(retval);}
X
Xsuspend(){
X sleep((unsigned)suspendv);}
X
Xskipspace(){
X while(testb(' ')||testb('\t'));}
X
Xsgetc(){ /* a fake fgetc for a string */
X return *sgetcp?*(uchar*)sgetcp++:EOF;}
X
Xskipped(x)const char*const x;{
X log("Skipped");logqnl(x);}
X
Xstatic uchar rcbuf[STDBUF],*rcbufp,*rcbufend; /* buffers for custom stdio */
Xstatic ungetb; /* pushed back char */
X
Xbopen(name)const char*const name;{ /* my fopen */
X rcbufp=rcbufend=0;ungetb= -1;yell("Rcfile:",name);
X return rc=ropen(name,O_RDONLY);}
X
Xgetbl(p)char*p;{int i;char*q; /* my gets */
X for(q=p;;){
X switch(i=getb()){
X case '\n':case EOF:
X *p='\0';return p!=q;} /* did we read anything at all? */
X *p++=i;}}
X
Xgetb(){ /* my fgetc */
X if(ungetb>=0){int i; /* anything pushed back? */
X i=ungetb;ungetb= -1;return i;}
X if(rcbufp==rcbufend){
X rcbufend=rcbuf+rread(rc,rcbufp=rcbuf,STDBUF);} /* refill */
X return rcbufp<rcbufend?*rcbufp++:EOF;}
X
Xtestb(x)const int x;{int i; /* fgetc that only succeeds if it matches */
X if((i=getb())==x)
X return 1;
X ungetb=i;return 0;}
X
Xalphanum(c)const int c;{
X return c>='0'&&c<='9'||c>='a'&&c<='z'||c>='A'&&c<='Z'||c=='_';}
X /* open file or new file in directory */
Xdeliver(boxname)char*const boxname;{struct stat stbuf;
X strcpy(buf,boxname); /* boxname can be found back in buf */
X return stat(buf,&stbuf)||!S_ISDIR(stbuf.st_mode)?opena(buf):dirmail();}
X
X#include "exopen.h"
X /* an NFS secure exclusive file open */
XNFSxopen(name)char*name;{char*p,*q;int j= -1,i;
X for(q=name;p=strpbrk(q,dirsep);q=p+1); /* find last DIRSEP */
X i=q-name;strncpy(p=malloc(i+UNIQnamelen),name,i);
X if(unique(p,p+i,0))
X j=myrename(p,name); /* try and rename it, fails if nonexclusive */
X free(p);return j;}
SHAR_EOF
chmod 0644 procmail/retint.c ||
echo 'restore of procmail/retint.c failed'
Wc_c="`wc -c < 'procmail/retint.c'`"
test 9348 -eq "$Wc_c" ||
echo 'procmail/retint.c: original size 9348, current size' "$Wc_c"
fi
# ============= procmail/shell.h ==============
if test -f 'procmail/shell.h' -a X"$1" != X"-c"; then
echo 'x - skipping procmail/shell.h (File already exists)'
else
echo 'x - extracting procmail/shell.h (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'procmail/shell.h' &&
X/*$Id: shell.h,v 2.0 1991/06/10 14:39:08 berg Rel $*/
X
X#define malloc(n) tmalloc((size_t)(n))
X#define realloc(p,n) trealloc(p,(size_t)(n))
X#define tmemmove(t,f,n) memmove(t,f,(size_t)(n))
SHAR_EOF
chmod 0644 procmail/shell.h ||
echo 'restore of procmail/shell.h failed'
Wc_c="`wc -c < 'procmail/shell.h'`"
test 188 -eq "$Wc_c" ||
echo 'procmail/shell.h: original size 188, current size' "$Wc_c"
fi
# ============= procmail/INSTALL ==============
if test -f 'procmail/INSTALL' -a X"$1" != X"-c"; then
echo 'x - skipping procmail/INSTALL (File already exists)'
else
echo 'x - extracting procmail/INSTALL (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'procmail/INSTALL' &&
XTo install procmail, lockfile and formail: edit Makefile accordingly (if need
Xbe, config.h as well) and type 'make install'.
X
X'make install' will:
X - execute autoconf (a shell script that repeatedly calls the C compiler
X to determine if certain features/symbols are supported), which will
X create a file named autoconf.h
X - compile the *.c files, create the three binaries: procmail, lockfile,
X formail
X - copy these binaries to $(BINDIR)
X - copy the man pages to $(MANDIR)
X
X
XMinimal requirements:
X
Xprocmail must be installed.
Xlockfile needs only to be installed if you plan to read several mailboxes
X with one of the standard mailers.
Xformail needs only to be installed if mail sometimes arrives in nonstandard
X mailbox format (or if you want to generate auto replies, split up
X mailboxes/digests etc., see the man page of formail for more info).
X
X
XIf things don't compile automagically, I suggest you take a look at:
Xautoconf, autoconf.h, config.h, includes.h
X
XThe program is supposed to be fully ANSI and K&R compliant.
X
XIf you run procmail by hand and pipe in some sample mail, then make
Xsure that if you kill procmail, you use "kill pid" and NOT "kill -9 pid".
XShould procmail seem to hang, check if the $LOCKFILE is still present.
XIf you kill procmail with "kill pid" it will clean up the $LOCKFILE
Xitself.
X
XSuggested command line for a test run: "procmail -d LOGFILE=/dev/tty"
X(now type in a mail message).
X
XEvery user that wants to use procmail should have a .forward and a
X.procmailrc file in his HOME directory. For starters, you can look
Xat the supplied example files in "examples".
X(BTW, be sure to make .forward *world* readable).
X
XFor more info about the program, see the man page.
X
X------------------------------------------------------------------------------
X-----------------------Frequently Asked Questions-----------------------------
X------------------------------------------------------------------------------
X
X1. Why does the logfile have lines containing "file -i not found"?
X
X Your egrep doesn't understand the -i option (ignore case). Either
X use a different grep (e.g. set GREP to /bin/grep), or be sure
X to specify the 'D' option on every recipe.
X
X2. I installed procmail (i.e. typed 'make install'), but how am I supposed to
X use it? When I type procmail on the command line it simply does nothing.
X
X You're not supposed to start procmail from the command line.
X Be sure to have a .forward and a .procmailrc file in your home
X directory (see the examples subdirectory or the man page).
SHAR_EOF
chmod 0644 procmail/INSTALL ||
echo 'restore of procmail/INSTALL failed'
Wc_c="`wc -c < 'procmail/INSTALL'`"
test 2542 -eq "$Wc_c" ||
echo 'procmail/INSTALL: original size 2542, current size' "$Wc_c"
fi
# ============= procmail/Makefile ==============
if test -f 'procmail/Makefile' -a X"$1" != X"-c"; then
echo 'x - skipping procmail/Makefile (File already exists)'
else
echo 'x - extracting procmail/Makefile (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'procmail/Makefile' &&
X#$Id: Makefile,v 2.0 1991/06/10 14:39:08 berg Rel $
X
X# change BASENAME to your home directory if need be
XBASENAME = /usr/local
X
XBINDIR = $(BASENAME)/bin
XMANDIR = $(BASENAME)/man/man1
X
X########################################################################
X# Only edit below this line if you *think* you know what you are doing #
X########################################################################
X
X# Directory for the standard include files
XUSRINCLUDE = /usr/include
X
XOCFLAGS = -O
XOLDFLAGS = -s
X
XCFLAGS = $(OCFLAGS) -I$(USRINCLUDE) -I./include
XLDFLAGS = $(OLDFLAGS)
X
XCC = cc
XO = o
XRM= rm -f
X
XBINS=procmail lockfile formail
X
XOBJ=procmail.$(O) nonint.$(O) goodies.$(O)
X
XDEP=shell.h procmail.h config.h
X
Xall: autoconf.h $(BINS)
X
Xprocmail: $(OBJ) exopen.$(O) common.$(O) retint.$(O)
X $(CC) $(CFLAGS) -o procmail $(OBJ) exopen.$(O) common.$(O) \
Xretint.$(O) $(LDFLAGS)
X
Xlockfile: lockfile.$(O) exopen.$(O)
X $(CC) $(CFLAGS) -o lockfile lockfile.$(O) exopen.$(O) ${LDFLAGS}
X
Xformail: formail.$(O) common.$(O)
X $(CC) $(CFLAGS) -o formail formail.$(O) common.$(O) ${LDFLAGS}
X
X_autotst: _autotst.c
X $(CC) $(CFLAGS) -o _autotst _autotst.c $(LDFLAGS)
X
Xautoconf.h: autoconf Makefile
X /bin/sh autoconf
X
X$(OBJ): $(DEP)
X
Xretint.$(O): $(DEP) exopen.h
X
Xexopen.$(O): config.h includes.h exopen.h
X
Xformail.$(O): config.h includes.h shell.h
X
Xlockfile.$(O): config.h includes.h
X
Xcommon.$(O): includes.h shell.h
X
Xprocmail.h: includes.h
X touch procmail.h
X
Xincludes.h: autoconf.h
X touch includes.h
X
X.c.$(O):
X $(CC) $(CFLAGS) -c $*.c
X
Xinstall: all
X chmod 755 $(BINS)
X cp $(BINS) $(BINDIR)
X chmod 644 man/procmail.1 man/lockfile.1 man/formail.1
X cp man/procmail.1 man/lockfile.1 man/formail.1 $(MANDIR)
X
Xclean:
X $(RM) $(OBJ) common.$(O) lockfile.$(O) exopen.$(O) retint.$(O) \
Xformail.$(O) $(BINS) autoconf.h _autotst*
SHAR_EOF
chmod 0644 procmail/Makefile ||
echo 'restore of procmail/Makefile failed'
Wc_c="`wc -c < 'procmail/Makefile'`"
test 1801 -eq "$Wc_c" ||
echo 'procmail/Makefile: original size 1801, current size' "$Wc_c"
fi
# ============= procmail/autoconf ==============
if test -f 'procmail/autoconf' -a X"$1" != X"-c"; then
echo 'x - skipping procmail/autoconf (File already exists)'
else
echo 'x - extracting procmail/autoconf (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'procmail/autoconf' &&
X#!/bin/sh
X#$Id: autoconf,v 2.1 1991/06/11 12:59:16 berg Rel $
X
XSHELL=/bin/sh || exec /bin/sh <autoconf # we're in a csh, feed myself to sh
X
XACONF=autoconf.h
Xtrap "rm $ACONF;exit 1" 1 2 3 15
Xcat >$ACONF <<HERE
X/* This file was automagically generated by autoconf */
X
XHERE
X
X# WARNING: in ./include/stdlib.h the const keyword is already used!
X# hence the const test has to precede all others.
X
Xcat >_autotst.c <<HERE
Xmain(){const int i;return 0;}
XHERE
X
Xecho 'Testing for const'
Xif make _autotst >/dev/null 2>&1
Xthen
X:
Xelse
X echo '#define const' >>$ACONF
Xfi
Xrm -f _autotst _autotst.o
X
Xcat >_autotst.c <<HERE
Xmain(){volatile int i;return 0;}
XHERE
X
Xecho 'Testing for volatile'
Xif make _autotst >/dev/null 2>&1
Xthen
X:
Xelse
X echo '#define volatile' >>$ACONF
Xfi
Xrm -f _autotst _autotst.o
X
Xcat >_autotst.c <<HERE
Xmain(){int i;i= -1;return i=-i;}
XHERE
X
Xecho 'Testing for compiler age'
Xmake _autotst >_autotst.rrr 2>&1
X
Xif _autotst
Xthen
X echo 'Aha, this one is genuine antique!'
X echo '#define void char' >>$ACONF
Xfi
Xrm -f _autotst _autotst.o
X
X
Xcat >_autotst.c <<HERE
X#include "includes.h"
Xmain(){int i;
X void*p;
X i=(size_t)1;
X i+=(pid_t)1;
X i+=(time_t)1;
X i+=(mode_t)1;
X return 0;}
XHERE
X
Xecho 'Testing for void*,size_t,pid_t,time_t,mode_t'
Xmake _autotst >_autotst.rrr 2>&1
Xrm -f _autotst _autotst.o
X
Xgrepfor(){
Xif fgrep "$1" _autotst.rrr >/dev/null
Xthen
X echo "$2" >>$ACONF
Xfi
X}
X
Xgrepfor void '#define void char'
Xgrepfor size_t 'typedef unsigned size_t;'
Xgrepfor pid_t 'typedef int pid_t;'
Xgrepfor time_t 'typedef long time_t;'
Xgrepfor mode_t 'typedef int mode_t;'
X
Xcat >_autotst.c <<HERE
X#include "includes.h"
Xmain(){char a[1];
X setpwent();endpwent();memmove(a,"t",1);bcopy("t",a,1);strstr(a,"t");return 0;}
XHERE
X
Xecho 'Testing for memmove & strstr'
Xmake _autotst >_autotst.rrr 2>&1
Xrm -f _autotst _autotst.o
X
Xif fgrep memmove _autotst.rrr >/dev/null
Xthen
X echo '#define NOmemmove' >>$ACONF
X grepfor bcopy '#define NObcopy'
Xfi
Xgrepfor strstr '#define NOstrstr'
Xgrepfor setpwent '#define setpwent()'
Xgrepfor endpwent '#define endpwent()'
X
Xrm -f _autotst*
X
Xecho -----------------------------autoconf.h-----------------------------------
Xcat autoconf.h
Xecho --------------------------------------------------------------------------
SHAR_EOF
chmod 0644 procmail/autoconf ||
echo 'restore of procmail/autoconf failed'
Wc_c="`wc -c < 'procmail/autoconf'`"
test 2224 -eq "$Wc_c" ||
echo 'procmail/autoconf: original size 2224, current size' "$Wc_c"
fi
# ============= procmail/exopen.h ==============
if test -f 'procmail/exopen.h' -a X"$1" != X"-c"; then
echo 'x - skipping procmail/exopen.h (File already exists)'
else
echo 'x - extracting procmail/exopen.h (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'procmail/exopen.h' &&
X/*$Id: exopen.h,v 2.0 1991/06/10 14:39:08 berg Rel $*/
X#define SERIALchars 3
X#define UNIQnamelen (1+SERIALchars+HOSTNAMElen+1)
X#define SERIALmask ((1L<<6*SERIALchars)-1)
SHAR_EOF
chmod 0644 procmail/exopen.h ||
echo 'restore of procmail/exopen.h failed'
Wc_c="`wc -c < 'procmail/exopen.h'`"
test 170 -eq "$Wc_c" ||
echo 'procmail/exopen.h: original size 170, current size' "$Wc_c"
fi
# ============= procmail/formail.c ==============
if test -f 'procmail/formail.c' -a X"$1" != X"-c"; then
echo 'x - skipping procmail/formail.c (File already exists)'
else
echo 'x - extracting procmail/formail.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'procmail/formail.c' &&
X/************************************************************************
X * formail.c a mail (re)formatter *
X * *
X * Seems to be relatively bug free. *
X * *
X * Copyright (c) 1990-1991, S.R.van den Berg, The Netherlands *
X * The sources can be freely copied for non-commercial use. *
X * #include "README" *
X * *
X * #include "STYLE" *
X * *
X ************************************************************************/
X#ifdef RCS
Xstatic char rcsid[]="$Id: formail.c,v 2.3 1991/06/12 10:50:21 berg Rel $";
X#endif
Xstatic char rcsdate[]="$Date: 1991/06/12 10:50:21 $";
X#include "config.h" /* I know, overkill, only need BinSh */
X#include "includes.h"
X
X#define BSIZE 4096
X
X#define FROM "From "
X#define UNKNOWN "foo at bar"
X
X#define Re (re+1)
X#define Nextchar(x) do{x=getchar();if(feof(stdin))goto foundeof;}while(0)
X#define putssn(a,l) tputssn(a,(size_t)(l))
X#define putcs(a) (errout=putc(a,mystdout))
X#define PRDO poutfd[0]
X#define PWRO poutfd[1]
X
Xstatic const char From[]=FROM,replyto[]="Reply-To:",Fromm[]="From:",
X returnpath[]="Return-Path",sender[]="Sender:",outofmem[]="Out of memory\n",
X subject[]="Subject:",re[]=" Re:",couldntw[]="Couldn't write to stdout",
X references[]="References:",messageid[]="Message-ID:",Date[]="Date:";
Xconst char binsh[]=BinSh;
Xstatic struct {const char*const head;const int len,wrepl;}sest[]={
X {sender,STRLEN(sender),0},{replyto,STRLEN(replyto),4},
X {Fromm,STRLEN(Fromm),2},{returnpath,STRLEN(returnpath),1}};
Xstatic struct {const char*const headr;const int lenr;size_t offset;}rex[]={
X {subject,STRLEN(subject)},{references,STRLEN(references)},
X {messageid,STRLEN(messageid)}};
X#define subj rex[0]
X#define refr rex[1]
X#define msid rex[2]
Xstatic struct {const char*const hedr;const int lnr;}cdigest[]={
X {Fromm,STRLEN(Fromm)},{Date,STRLEN(Date)},{subject,STRLEN(subject)}};
X#define mxl(a,b) mx(STRLEN(a),STRLEN(b))
X#define dig_HDR_LEN mx(mxl(From,Fromm),mxl(Date,subject))
Xstatic errout,oldstdout;
Xstatic pid_t child= -1;
Xstatic FILE*mystdout;
Xstatic size_t nrskip,nrtotal= -1;
X
X#ifdef NOstrstr
Xchar*strstr(whole,part)const char*whole,*const part;{size_t len;
X if(!(len=strlen(part)))
X return(char*)whole;
X while(*whole&&strncmp(whole,part,len))
X ++whole;
X return *whole?(char*)whole:(char*)0;}
X#endif
X
Xvoid*tmalloc(len)const size_t len;{void*p;
X if(p=malloc(len))
X return p;
X log(outofmem);exit(EX_OSERR);}
X
Xvoid*trealloc(old,len)void*old;const size_t len;{
X if(old=realloc(old,len))
X return old;
X log(outofmem);exit(EX_OSERR);}
X
X#include "shell.h"
X
Xmain(argc,argv)const char*const argv[];{time_t t;
X int i,lastm,nowm,thelen=0,split=0,force=0,bogus=1,every=0,areply=0,
X trust=0,digest=0,nowait=0;
X size_t buflen,p=0,lnl=0,thename,ll;
X char*buf,*chp;
X while(*++argv){
X if((lastm= **argv)=='+')
X goto number;
X else if(lastm!='-')
X goto usg;
X for(i=1;;){
X switch((*argv)[i++]){
X case 't':trust=1;continue; /* trust the sender for valid headers */
X case 'r':areply=1;continue; /* generate a reply */
X case 'f':force=1;continue; /* accept arbitrary format */
X case 'e':every=1;continue; /* split on every From */
X case 'd':digest=1;continue; /* split up digests */
X case 'n':nowait=1;continue; /* don't wait for the programs */
X case 's':split=1;bogus=0;
X if(!(*argv++)[i])
X goto parsedoptions;
X goto usg;
Xnumber: default:
X if((*argv)[1]-'0'>(unsigned)9){
Xusg: log("Usage: formail [+nnn] [-nnn] [-bfrtned] \
X[-s command argument ...]\n");return EX_USAGE;}
X ll=strtol((*argv)+1,(char**)0,10);
X if(lastm=='+')
X nrskip=ll;
X else
X nrtotal=ll;
X break;
X case 'b':bogus=0;continue; /* leave bogus Froms intact */
X case '\0':;}
X break;}}
Xparsedoptions:
X mystdout=stdout;
X if(split){
X oldstdout=dup(STDOUT);fclose(stdout);startprog(argv);}
X while('\n'==(i=getchar()));
X buf=malloc(buflen=BSIZE);t=time((time_t*)0);
X for(;;){ /* start parsing the header */
X if((buf[p++]=i)=='\n'){
X chp=buf+lnl;i=maxindex(rex);
X while(strnicmp(rex[i].headr,chp,rex[i].lenr)&&i--);
X if(i>=0) /* found anything already? */
X rex[i].offset=lnl+rex[i].lenr;
X else if(!strncmp(From,chp,STRLEN(From))){
X if(!lnl){ /* was the real "From " line */
X if(!areply)
X goto endofheader;
X nowm=trust?1:3/*wreply*/;ll=lnl+STRLEN(From);goto foundfrom;}
X if(bogus){
X tmemmove(chp+1,chp,p++-lnl);*chp='>';}} /* disarm */
X else{
X i=maxindex(sest);
X do
X if(!strnicmp(sest[i].head,chp,sest[i].len)){
X nowm=areply?sest[i].wrepl:i;ll=lnl+sest[i].len;
Xfoundfrom: buf[p]='\0';
X if(chp=strchr(buf+ll,'<')) /* extract the address */
X ll=chp-buf+1;
X chp=buf+(ll+=strspn(buf+ll," \t"));
X if((i=strcspn(chp,">(\n \t"))&&(!thelen||nowm>lastm)){
X thename=ll;thelen=i;
X lastm=strstr(chp,".UUCP")?nowm-maxindex(sest)-1:nowm;}
X break;}
X while(i--);
X if(lnl==p-1)
X break;} /* end of header reached */
X lnl=p;}
X if(p>=buflen-2)
X buf=realloc(buf,buflen+=BSIZE);
Xredigest:
X i=getchar();
X if(feof(stdin))
X i='\n';} /* make sure the header ends with 2 newlines */
X if(areply||!force){
X putss(areply?"To: ":From);
X if(thelen) /* found any sender address? */
X putssn(buf+thename,thelen);
X else
X putss(UNKNOWN);
X if(areply){
X putcs('\n');
X if(subj.offset){ /* any Subject: ? */
X putss(subject);chp=buf+subj.offset;
X if(strnicmp(chp+strspn(chp," "),Re,STRLEN(Re)))
X putss(re); /* no Re: , add one ourselves */
X nlputss(chp);}
X if(refr.offset||msid.offset){ /* any Message-ID: or References: ? */
X putss(references);
X if(refr.offset){
X chp=buf+refr.offset;
X putssn(chp,strchr(chp,'\n')-chp+!msid.offset);}
X if(msid.offset){
X nlputss(buf+msid.offset);putss("In-Reply-To:");
X nlputss(buf+msid.offset);}}
X putcs('\n');
X while(getchar(),!feof(stdin));return EX_OK;}
X putcs(' ');putss(ctime(&t));}
Xendofheader:
X putssn(buf,p);p=0;lnl=1;
X if(!bogus&&!split)
X for(;;putcs(i))
X Nextchar(i);
X for(;;){ /* continue the quest */
X do{ /* read line until not From */
X if(p==buflen-1)
X buf=realloc(buf,++buflen);
X Nextchar(i=buf[p]);
X if(++p==STRLEN(From))
X if(!strncmp(From,buf,STRLEN(From))){
X if(bogus){
X putcs('>');break;} /* disarm */
X else if(every)
X goto splitit;
X else if(split&&lnl)
X lnl=2;} /* mark line as possible postmark */
X if(lnl==1&&digest){
X thelen=maxindex(cdigest);
X do /* check for new digest header */
X if(p==cdigest[thelen].lnr&&!strncmp(buf,cdigest[thelen].hedr,p)){
X lnl=thelen=0;goto splitit;} /* pretend we started over */
X while(thelen--);}}
X while(i!='\n'&&(lnl==2||p<dig_HDR_LEN));
X if(lnl==2){
X buf[p]='\0'; /* perform more thorough check for postmark */
X for(i=STRLEN(From)-1;buf[++i]==' ';);
X if(ll=strcspn(buf+i,"\n \t")){
X i+=ll;
X if(ll=strspn(buf+i," ")&&(ll=buf[i+ll])!='\t'&&ll!='\n'){
Xsplitit: if(fclose(mystdout)==EOF||errout==EOF){
X log(couldntw);log(", continuing...\n");split= -1;}
X if(!nowait)
X waitforit();
X startprog(argv);
X if(!lnl) /* digest split? */
X goto redigest;
X i='\n';}}}
X lnl=p==1;putssn(buf,p);p=0;
X if(i!='\n')
X do Nextchar(i);
X while(putcs(i),i!='\n');}
Xfoundeof:
X putssn(buf,p);
X if(fclose(mystdout)==EOF||errout==EOF){
X log(couldntw);return EX_IOERR;}
X child= -1;waitforit();return split<0?EX_IOERR:EX_OK;} /* wait for everyone */
X
Xstrnicmp(a,b,l)register const char*a,*b;register unsigned l;{int i,j;
X if(l) /* case insensitive strncmp */
X do{
X while(*a&&*a==*b&&--l)
X ++a,++b;
X if(!l)
X break;
X if((i= *a++)>='A'&&i<='Z')
X i+='a'-'A';
X if((j= *b++)>='A'&&j<='Z')
X j+='a'-'A';
X if(j!=i)
X return i>j?1:-1;}
X while(i&&j&&--l);
X return 0;}
X
Xlog(a)const char*const a;{
X fputs(a,stderr);}
X
Xlogqnl(a)const char*a;{
X log(" \"");log(a);log("\"\n");}
X
Xnlputss(a)const char*const a;{
X putssn(a,strchr(a,'\n')+1-a);}
X
Xputss(a)const char*a;{
X while(*a)
X putcs(*a++);}
X
Xtputssn(a,l)const char*a;size_t l;{
X while(l--)
X putcs(*a++);}
X
Xstartprog(argv)const char*const*const argv;{int poutfd[2];
X if(!nrtotal)
X goto squelch;
X if(nrskip){
X --nrskip;
Xsquelch:
X if(!(mystdout=fopen(DevNull,"a")))
X goto nofild;
X return;}
X if(nrtotal>0)
X --nrtotal;
X dup(oldstdout);pipe(poutfd);
X if(!(child=fork())){
X close(oldstdout);close(PWRO);fclose(stdin);dup(PRDO);close(PRDO);
X shexec(argv);}
X close(STDOUT);close(PRDO);
X if(STDOUT!=dup(PWRO)||!(mystdout=fdopen(STDOUT,"a"))){
Xnofild:
X log("File table full\n");exit(EX_OSERR);}
X close(PWRO);
X if(0>child){
X log("Can't fork\n");exit(EX_OSERR);}}
X
Xwaitforit(){int i;
X while(child!=wait(&i)||(i&127)==127);}
SHAR_EOF
chmod 0644 procmail/formail.c ||
echo 'restore of procmail/formail.c failed'
Wc_c="`wc -c < 'procmail/formail.c'`"
test 8833 -eq "$Wc_c" ||
echo 'procmail/formail.c: original size 8833, current size' "$Wc_c"
fi
# ============= procmail/config.h ==============
if test -f 'procmail/config.h' -a X"$1" != X"-c"; then
echo 'x - skipping procmail/config.h (File already exists)'
else
echo 'x - extracting procmail/config.h (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'procmail/config.h' &&
X/*$Id: config.h,v 2.0 1991/06/10 14:35:35 berg Rel $*/
X
X/*#define console "/dev/console" /* uncomment if you want procmail to
X use the console (or any other
X terminal) to print any error messages that could not be dumped in the
X "logfile". (Only recommended for debugging purposes, if you have
X trouble creating a "logfile") */
X
X/************************************************************************
X * Only edit below this line if you *think* you know what you are doing *
X ************************************************************************/
X
X#define DEFlinebuf 2048 /* default max expanded line length */
X#define BLKSIZ 16384 /* blocksize while reading/writing */
X#define STDBUF 1024 /* blocksize for emulated stdio */
X#define HOSTNAMElen 8 /* nr of significant chararacters for HOST */
X#define PROCMAILRC ".procmailrc"
X#define DEFsuspend 16 /* multi-purpose 'idle loop' period */
X#define DEFlocksleep 8
X#define TOkey "^TO"
X#define TOsubstitute "^(To|Cc|Apparently-To):.*"
X#define DEFshellmetas "&()[]*?|<>~;:" /* never put '$' in here */
X#define DEFmaildir "$HOME"
X#define DEFdefault "$MAILDIR/.mailbox"
X#define DEFmsgprefix "msg."
X#define DEForgmail "/usr/spool/mail/$USER"
X#define DEFgrep "/usr/bin/egrep"
X#define DEFsendmail "/usr/lib/sendmail"
X#define DEFlockext ".lock"
X#define DEFshellflags "-c"
X#define DEFlocktimeout 3600 /* defaults to one hour */
X#define DEFnoresretry 2 /* default nr of retries if no resources left */
X
X#define NRRECFLAGS (9+1)
X#define RECFLAGS " %9[HBDIhbfcws] %[^\n]" /* 'I' and 's' are obsolete */
X#define BinSh "/bin/sh"
X#define Tmp "/tmp"
X#define DevNull "/dev/null"
X#define DIRSEP "/" /* directory separator symbols, the */
X /* last one should be the most common one */
X
X/* the regular expression we use to look for bogus headers
X (which I took from /usr/ucb/mail) is:
X "\n\nFrom +[^\t\n ]+ +[^\n\t]" */
X
X#define FromSCAN "From%*[ ]%*[^\t\n ]%*[ ]%1[^\n\t]"
X#define EOFName "%[^ \t\n#'\")};]"
X
X#define VERSIONOPT 'v' /* option to display version */
X#define PRESERVOPT 'p'
X#define DEBUGOPT 'd'
X
X#define MINlinebuf 128 /* minimal LINEBUF length (don't change this) */
X#define SFROM "From "
X#define SFROM_S "From%*[ ]%74[^\n]"
X#define SSUBJECT " Subject:"
X#define SSUBJECT_S \
X "%*1[Ss]%*1[Uu]%*1[Bb]%*1[Jj]%*1[Ee]%*1[Cc]%*1[Tt]:%70[^\n]"
X#define FOLDER " Folder: "
X#define LENtSTOP 9 /* tab stop at which message length will be logged */
X
X#define TABCHAR "\t"
X#define TABWIDTH 8
SHAR_EOF
chmod 0644 procmail/config.h ||
echo 'restore of procmail/config.h failed'
Wc_c="`wc -c < 'procmail/config.h'`"
test 2501 -eq "$Wc_c" ||
echo 'procmail/config.h: original size 2501, current size' "$Wc_c"
fi
# ============= procmail/procmail.h ==============
if test -f 'procmail/procmail.h' -a X"$1" != X"-c"; then
echo 'x - skipping procmail/procmail.h (File already exists)'
else
echo 'x - extracting procmail/procmail.h (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'procmail/procmail.h' &&
X/*$Id: procmail.h,v 2.0 1991/06/10 14:35:35 berg Rel $*/
X
X#include "includes.h"
X
Xtypedef unsigned char uchar;
X
X#ifndef console
X#define console devnull
X#endif
X
X#define XTRAlinebuf 2 /* surplus of LINEBUF (see readparse()) */
X#define TMNATE '\377' /* terminator (see readoarse()) */
X
X#define PRDO poutfd[0]
X#define PWRO poutfd[1]
X#define PRDI pinfd[0]
X#define PWRI pinfd[1]
X#define PRDB pbackfd[0]
X#define PWRB pbackfd[1]
X#define LENoffset (TABWIDTH*LENtSTOP)
X#define MAXfoldlen (LENoffset-STRLEN(sfolder)-1)
X#define MCDIRSEP (dirsep+STRLEN(dirsep)-1) /* most common DIRSEP */
X
Xstruct varval{const char*const name;long val;};
X#define locksleep (strenvvar[0].val)
X#define locktimeout (strenvvar[1].val)
X#define suspendv (strenvvar[2].val)
X#define noresretry (strenvvar[3].val)
X#define MAXvarvals maxindex(strenvvar)
X
X#ifndef MAIN
Xextern char*buf,*buf2,*globlock,*loclock,*tolock,*lastfolder;
Xextern const char grep[],shellflags[],shell[],lockext[],newline[],binsh[],
X unexpeof[],shellmetas[],*const*gargv,*sgetcp,*rcfile,dirsep[],msgprefix[],
X devnull[],executing[],oquote[],cquote[],whilstwfor[];
Xextern struct varval strenvvar[];
Xextern long lastdump;
Xextern sh,pwait,retval,lcking,locknext,verbose,linebuf,rc;
Xextern volatile flaggerd,nextexit;
Xextern pid_t thepid;
X#endif
X
X#ifdef NOmemmove
Xvoid*memmove();
X#endif
X
Xvoid*tmalloc(),*trealloc();
Xpid_t sfork();
Xvoid sterminate(),stermchild(),flagger(),errgrandchild();
Xlong dump(),pipin(),renvint();
Xchar*readdyn(),*fromprog(),*cat(),*findnl(),*tstrdup(),*cstr();
Xconst char*tgetenv(),*hostname();
Xint sgetc(),getb();
SHAR_EOF
chmod 0644 procmail/procmail.h ||
echo 'restore of procmail/procmail.h failed'
Wc_c="`wc -c < 'procmail/procmail.h'`"
test 1582 -eq "$Wc_c" ||
echo 'procmail/procmail.h: original size 1582, current size' "$Wc_c"
fi
# ============= procmail/HISTORY ==============
if test -f 'procmail/HISTORY' -a X"$1" != X"-c"; then
echo 'x - skipping procmail/HISTORY (File already exists)'
else
echo 'x - extracting procmail/HISTORY (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'procmail/HISTORY' &&
X1990/12/07: v1.00
X First release (after 2 weeks of coding and testing)
X1990/12/12: v1.01
X Added fsync to procmail.c
X Removed longjmp in lockfile.c out of the signal handler
X (not portable, so I'm told)
X1991/02/04: v1.02
X Changes to procmail.c:
X Added physical-write-error check
X Altered egrep invocation (left out the -s flag, not supported
X on all machines; this didn't change functionality though)
X Avoided the 'dirty' allocation of one more byte than needed by
X rewriting the bogus_header_replace routine
X Made the search for bogus headers more robust
X Added sysV lines in Makefile
X1991/02/13: v1.10
X Changes to procmail.c:
X Fixed slight error in parsing the recipe when 'h' and 'b' where
X specified
X Started using the official exit codes
X Made sure that the procmail is not influenced by falsely
X set environment variables like LOCKSLEEP
X1991/02/21: v1.20
X Changes to procmail.c:
X Removed library conflict on some machines for 'locking'
X Added uname call as alternative for gethostname
X Changed name of SHELLMETA to SHELLMETAS (for conformance
X with dmake)
X Added LOCKTIMEOUT to learn procmail to decide wether or not
X a certain lockfile is still 'valid'
X Added the function sputenv (smart-putenv) to avoid library
X problems and to finally have a putenv that works the
X way it was supposed to work all along (you wouldn't believe
X how brain damaged this library function is :-)
X Changed environment variable assignment to skip trailing blanks
X only, and allow intermediate blanks (parsing like make)
X1991/02/22: v1.21
X Split up procmail.c in procmail.c, nonint.c, retint.c, procmail.h,
X config.h, sysexits.h, shell.h
X Changes to lockfile.c:
X Added -l option (locktimeout)
X Moved virtually all configuration stuff from Makefile into
X config.h
X Added -v option to procmail
X1991/03/01: v1.30
X Added out of memory/swap space immunity (NOMEMRETRY)
X Made forced terminations of procmail more reliable and verbose
X (previously, procmail would display erroneous error messages
X if an attempt was made to kill procmail more than once in
X rapid succession)
X Fixed up man pages and comments
X Included more example files
X Made sure that variable substitution works in locallockfile-
X specifications too
X1991/03/15: v1.35
X Fixed the problem when no rcfile was found (rc!=NULL)
X Made my memmove replacement ANSI compatible
X Fixed up the Makefile (include file dependencies were incorrect)
X Started using RCS to manage the source
X1991/06/04: v1.99
X Changed NOMEMRETRY into NORESRETRY, now all machine limitations
X are caught
X Beefed up the parsing routine, now supports virtually complete
X /bin/sh syntax (*all* quotes and escapes are understood)
X Cleaned up the code, arranged for all remotely configuration-
X dependent looking values to be in config.h
X Created an include directory to catch missing include files
X Created an autoconf script that determines all installation
X specifics (all the user has to do now is make)
X Threw out (the last?) BSD specific library routines
X ANSI'fied the code, it's now as close as you can get to 'native'
X ANSI while maintaining compatibility with K&R
X Stopped using the %i identifier from sscanf
X Improved the diagnostic messages when procmail is killed (tells
X you what it was waiting for)
X Made the file locking mechanism RELIABLE over NFS
X Procmail now is able to deliver to directories too (AMS --
X Andrew Mail System), it creates a uniquely named new file for
X every new mail
X Threw out the 's' and 'I' options in rcfiles, introduced 'D'
X Completely rewrote the filter code, made sure that the pid number
X off procmail does not change anymore while filtering
X Threw out the stdio library (out of procmail) to avoid the hidden
X malloc on fopen (I want to catch all mallocs), reliability
X was improved, binary size did not shrink because the getpwent
X library links in the stdio library (aargh!)
X Procmail ditches the environment completely now upon startup
X Provided a -p flag to preserve the environment
X Provided a -d flag for debugging purposes (debugging rc scripts)
X Improved logfile format, now logs a third entry on mail arrival:
X which folder the mail finally went to and how long it was
X Made logfile output line buffered to get a cleaner logfile if
X several programs write it concurrently
X Changes to lockfile.c:
X Added -s flag to maintain step with procmail
X Created formail.c:
X A new (the third) program
X Rearranged the routines a bit, so that two object files could be
X shared between the three programs
X1991/06/10: v2.00
X Changed all "ambiguous assignments" to have a space inserted
X (preserves compatibility with older compilers)
X Made some more entries in the config.h file
X Changes to formail.c:
X Added strstr library replacement
X Added the option to split digests
X Updated the manual files (I hate doing this)
X Updated the example files
X1991/06/11: v2.01
X Fixed up includes.h and autoconf to be more POSIX compliant
X Fixed up small bug in readparse() (goodies.c) that caused trouble
X with recursively nested backquotes (nobody will probably ever
X use this, but I was testing worst case behaviour)
X Documented the $$ environment variable in procmail.1
X1991/06/12: v2.02
X Fixed typo in strstr replacement
X Fixed runaway line while logging long folder names
SHAR_EOF
chmod 0644 procmail/HISTORY ||
echo 'restore of procmail/HISTORY failed'
Wc_c="`wc -c < 'procmail/HISTORY'`"
test 5739 -eq "$Wc_c" ||
echo 'procmail/HISTORY: original size 5739, current size' "$Wc_c"
fi
# ============= procmail/FEATURES ==============
if test -f 'procmail/FEATURES' -a X"$1" != X"-c"; then
echo 'x - skipping procmail/FEATURES (File already exists)'
else
echo 'x - extracting procmail/FEATURES (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'procmail/FEATURES' &&
XFeature summary for procmail:
X + Easy to install
X + Simple to maintain and configure because
X all you need is actually only ONE executable (procmail)
X and ONE configuration file (.procmailrc)
X + Uses *your* (i.e. easily configurable) favourite regular expression
X syntax
X + Allows for very-easy-to-use yes-no decisions on where the mail
X should go
X + Filters, delivers and forwards mail *reliably*
X + Provides a stable and guaranteed environment for any programs or
X shell scripts you may wish to start upon mail arrival
X + Is designed for reliability, once procmail gets hold of your mail
X you can consider it delivered
X + Is event driven (i.e. gets invoked automagically when mail arrives)
X + Performs heroically under even the worst conditions
X (file system full, out of swap space, process table full,
X file table full, missing support files, unavailable executables,
X denied permissions) and tries to deliver the mail somehow anyway
X (it usually succeeds were other programs would have given up)
X + procmail is the closest you can get to a program that outlives
X the swapper :-)
X + Absolutely undeliverable mail (after trying every trick in the book)
X will bounce back to the sender
X + Does not use *any* temporary files
X + Is explicitly designed to work under NFS as well
X + Performs more reliable mailbox locking than most other mailers
X (especially across NFS, DON'T use NFS mounted mailboxes WITHOUT
X installing procmail, you may use valuable mail one day)
X + Supports both mailfolder standards (single file folders (standard
X *NIX format) as well as directory folders (AMS -- Andrew Mail System)
X that contain one file per message)
X + Variable assignment and substitution is a subset of the standard
X /bin/sh syntax
X + Provides a mail log file, which logs all mail arrival, shows
X in summary whence it came from, what it was about, where it went
X (what folder) and how long (in bytes) it was
X + Uses this log file to display a wide range of diagnostic and error
X messages (if something went wrong)
X + Processed mail can contain arbitrary 8-bit characters (including
X '\0'); i.e. binary mailings can be processed if the rest of the
X mailing system knew how to handle them too
X + It has a man page (boy, does *it* have a man page)
X + It can be used as a local delivery agent (substitute for /bin/mail)
X
XFeature summary for formail:
X + Can generate auto-reply headers
X + Can force mail into mailbox format (so that you can process it with
X standard mail programs)
X + Can split up mailboxes into the individual messages
X + Can split up digests into the individual messages
X
XFeature summary for lockfile:
X + Provides NFS-secure lockfiles to shell script programmers
SHAR_EOF
chmod 0644 procmail/FEATURES ||
echo 'restore of procmail/FEATURES failed'
Wc_c="`wc -c < 'procmail/FEATURES'`"
test 2717 -eq "$Wc_c" ||
echo 'procmail/FEATURES: original size 2717, current size' "$Wc_c"
fi
exit 0
exit 0 # Just in case...
--
Kent Landfield INTERNET: kent at sparky.IMD.Sterling.COM
Sterling Software, IMD UUCP: uunet!sparky!kent
Phone: (402) 291-8300 FAX: (402) 291-4362
Please send comp.sources.misc-related mail to kent at uunet.uu.net.
More information about the Comp.sources.misc
mailing list