home *** CD-ROM | disk | FTP | other *** search
Text File | 1992-05-12 | 53.3 KB | 1,466 lines |
- Newsgroups: comp.sources.misc
- From: berg@pool.informatik.rwth-aachen.de (Stephen R. van den Berg)
- Subject: v29i092: procmail - mail processing program v2.70, Part03/05
- Message-ID: <1992May11.151604.29066@sparky.imd.sterling.com>
- X-Md4-Signature: a3ac9653f966d6d489efdf66a918d847
- Date: Mon, 11 May 1992 15:16:04 GMT
- Approved: kent@sparky.imd.sterling.com
-
- Submitted-by: berg@pool.informatik.rwth-aachen.de (Stephen R. van den Berg)
- Posting-number: Volume 29, Issue 92
- Archive-name: procmail/part03
- Environment: UNIX, sendmail, smail, MMDF
- Supersedes: procmail: Volume 28, Issue 01-05
-
- #! /bin/sh
- # This is a shell archive. Remove anything before this line, then unpack
- # it by saving it into a file and typing "sh file". To overwrite existing
- # files, type "sh file -c". You can also feed this as standard input via
- # unshar, or by typing "sh <file", e.g.. If this archive is complete, you
- # will see the following message at the end:
- # "End of archive 3 (of 5)."
- # Contents: procmail/autoconf procmail/config.h
- # procmail/examples/advanced procmail/examples/mailinglist
- # procmail/regexp.c procmail/strpbrk.h
- # Wrapped by berg@drunol on Thu Apr 30 13:42:57 1992
- PATH=/bin:/usr/bin:/usr/ucb ; export PATH
- if test -f 'procmail/autoconf' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'procmail/autoconf'\"
- else
- echo shar: Extracting \"'procmail/autoconf'\" \(7670 characters\)
- sed "s/^X//" >'procmail/autoconf' <<'END_OF_FILE'
- X
- X#$Id: autoconf,v 2.20 1992/04/29 16:38:45 berg Exp $
- X
- XSHELL=$4 || exec $4 autoconf $* # we're in a csh, feed myself to sh
- X
- X# All possible entries in autoconf.h:
- X
- X# #define UNISTD_H_MISSING
- X# #define STDDEF_H_MISSING
- X# #define STDLIB_H_MISSING
- X# #define SYS_WAIT_H_MISSING
- X# #define SYS_UTSNAME_H_MISSING
- X# #define STRING_H_MISSING
- X# #define SYSEXITS_H_MISSING
- X# #define SYS_FILE_H_MISSING
- X# #define const
- X# #define volatile
- X# #define void char
- X# typedef int mode_t;
- X# typedef int pid_t;
- X# typedef int uid_t;
- X# typedef int gid_t;
- X# typedef unsigned size_t;
- X# typedef long time_t;
- X# #define NOmemmove
- X# #define NObcopy
- X# #define NOstrcspn
- X# #define NOstrpbrk
- X# #define NOrename
- X# #define strchr(s,c) index(s,c)
- X# #define endpwent()
- X# #define endgrent()
- X# #define strtol(str,ptr,base) ((long)atoi(str))
- X# #define WMACROS_NON_POSIX
- X# #define oBRAIN_DAMAGE
- X# #define SMALLHEAP
- X# #define SYSTEM_MAILBOX "/usr/spool/mail/$USER"
- X# #define SENDMAIL "/usr/lib/sendmail"
- X
- X# A conforming ANSI compiler and POSIX library should only produce six
- X# entries in autoconf.h: SYS_FILE_H_MISSING, endpwent(), endgrent(), rename(),
- X# SYSTEM_MAILBOX, SENDMAIL (and perhaps SMALLHEAP)
- X# Anything else indicates failure of your installation to comply with either
- X# the ANSI or POSIX standards (but procmail should be installable anyway).
- X
- XPATH=:$PATH
- XACONF=$3
- XMAKE="$2"
- XRM="$5"
- XUSRINC=$6
- XDEVNULL=/dev/null
- Xexport SHELL PATH
- Xif test -f $ACONF
- Xthen
- X trap "exit 1" 1 2 3 15
- Xelse
- X trap "$RM $ACONF; exit 1" 1 2 3 15
- Xfi
- X
- Xif test -n "$LD_LIBRARY_PATH"
- Xthen
- X echo '***************************** WARNING *********************************'
- X echo '* You seem to have set the LD_LIBRARY_PATH variable, this might cause *'
- X echo '* some trouble during the execution of this autoconf script. If you *'
- X echo '* encounter errors about "_autotst not found" or any other *'
- X echo '* irregularities, stop the make, do a: "make clean", *'
- X echo '* clear LD_LIBRARY_PATH from the environment, and start over. *'
- X echo '***************************** WARNING *********************************'
- Xfi
- X
- Xcat >grepfor <<HERE
- Xfgrep -e "\$1" _autotst.rrr >$DEVNULL && echo "\$2" >>$ACONF
- XHERE
- Xchmod 0755 grepfor
- X
- Xcat >$ACONF <<HERE
- X/* This file was automagically generated by autoconf */
- X
- XHERE
- X
- Xtest -f $USRINC/unistd.h || echo "#define UNISTD_H_MISSING" >>$ACONF
- Xtest -f $USRINC/stddef.h || echo "#define STDDEF_H_MISSING" >>$ACONF
- Xtest -f $USRINC/stdlib.h || echo "#define STDLIB_H_MISSING" >>$ACONF
- Xtest -f $USRINC/sys/wait.h || echo "#define SYS_WAIT_H_MISSING" >>$ACONF
- Xtest -f $USRINC/sys/utsname.h || echo "#define SYS_UTSNAME_H_MISSING" >>$ACONF
- Xtest -f $USRINC/string.h || echo "#define STRING_H_MISSING" >>$ACONF
- Xtest -f $USRINC/sysexits.h || echo "#define SYSEXITS_H_MISSING" >>$ACONF
- Xtest -f $USRINC/sys/file.h || echo "#define SYS_FILE_H_MISSING" >>$ACONF
- 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()
- X{ char*const*p;char*q;
- X p= &q;return 0;
- X}
- XHERE
- X
- Xecho 'Testing for const'
- Xif ${MAKE} _autotst.$1 >_autotst.rrr 2>&1 && test -f _autotst.$1
- Xthen
- X grepfor const '#define const'
- Xelse
- X echo '#define const' >>$ACONF
- Xfi
- X${RM} _autotst.$1
- X
- Xcat >_autotst.c <<HERE
- Xmain(){volatile int i;return(i=0);}
- XHERE
- X
- Xecho 'Testing for volatile'
- Xif ${MAKE} _autotst.$1 >$DEVNULL 2>&1 && test -f _autotst.$1
- Xthen
- X:
- Xelse
- X echo '#define volatile' >>$ACONF
- Xfi
- X${RM} _autotst.$1
- X
- Xcat >_autotst.c <<HERE
- X#include "includes.h"
- Xvoid*vvoid;
- Xmain(){int i;char*p="t";
- X {size_t vsize_t;i=vsize_t=1;}
- X {pid_t vpid_t;i=vpid_t=1;}
- X {time_t vtime_t;i=vtime_t=1;}
- X {mode_t vmode_t;i=vmode_t=1;}
- X {uid_t vuid_t;i=vuid_t=1;}
- X {gid_t vgid_t;i=vgid_t=1;}
- X vvoid=p;
- X return !vvoid;}
- XHERE
- X
- Xecho 'Testing for void*,size_t,pid_t,time_t,mode_t,uid_t,gid_t'
- X${MAKE} _autotst.$1 >_autotst.rrr 2>&1
- X${RM} _autotst.$1
- 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;'
- Xgrepfor uid_t 'typedef int uid_t;'
- Xgrepfor gid_t 'typedef int gid_t;'
- X
- Xcat >_autotst.c <<HERE
- X#include "includes.h"
- Xmain(){int i;i=1;
- X i+=WIFEXITED(i);
- X i+=WIFSTOPPED(i);
- X i+=WEXITSTATUS(i);
- X return i;}
- XHERE
- X
- Xecho 'Testing for WIFEXITED(), WIFSTOPPED() & WEXITSTATUS()'
- Xif ${MAKE} _autotst.$1 >_autotst.rrr 2>&1
- Xthen
- X grepfor struct '#define WMACROS_NON_POSIX' ||
- X grepfor union '#define WMACROS_NON_POSIX'
- Xelse
- X echo '#define WMACROS_NON_POSIX' >>$ACONF
- Xfi
- X${RM} _autotst.$1
- X
- Xcat >_autotst.c <<HERE
- X#include "includes.h"
- Xmain(){char a[2];
- X endpwent();endgrent();memmove(a,"0",1);bcopy("0",a,1);strcspn(a,"0");
- X strtol("0",(char**)0,10);strchr("0",'0');strpbrk(a,"0");rename(a,"0");
- X return 0;}
- XHERE
- X
- Xecho 'Testing for memmove, strchr, strpbrk, strcspn & strtol'
- X${MAKE} _autotst.$1 >$DEVNULL 2>&1
- X${MAKE} _autotst >_autotst.rrr 2>&1
- X${RM} _autotst _autotst.$1
- X
- Xgrepfor strcspn '#define NOstrcspn'
- Xgrepfor strpbrk '#define NOstrpbrk'
- Xgrepfor rename '#define NOrename'
- Xgrepfor strchr '#define strchr(s,c) index(s,c)'
- Xgrepfor setpwent '#define setpwent()'
- Xgrepfor endpwent '#define endpwent()'
- Xgrepfor endgrent '#define endgrent()'
- Xgrepfor strtol '#define strtol(str,ptr,base) ((long)atoi(str))'
- Xgrepfor memmove '#define NOmemmove' &&
- Xif fgrep -e bcopy _autotst.rrr >$DEVNULL
- Xthen
- X echo '#define NObcopy' >>$ACONF
- X
- X echo 'Testing for brain damage'
- X cat >_autotst.c <<HERE
- X#include "includes.h"
- Xstruct tests{int a,b;};
- Xmain(){
- X return offsetof(struct tests,b);}
- XHERE
- X if ${MAKE} _autotst.$1 >$DEVNULL 2>&1
- X then
- X :
- X else
- X echo 'Yep, it is' # ISC chokes on its own offsetof()
- X echo '#define oBRAIN_DAMAGE' >>$ACONF
- X fi
- X ${RM} _autotst.$1
- X
- Xelse
- X
- X cat >_autotst.c <<HERE
- X#include "includes.h"
- X#define M256 256
- X#define F33 33
- Xmain(){int j=0,i=M256-1;static char a[M256];
- X do a[i]=i;while(i--);
- X bcopy(a+F33,a,M256-F33);bcopy(a,a+F33,M256-F33);i=F33-1;
- X do j|=a[i]!=(char)(i+F33);while(i--);i=M256-1;
- X do j|=a[i]!=(char)i;while(--i!=F33-1);return!j;}
- XHERE
- X
- X echo 'Testing for bcopy handling overlaps'
- X ${MAKE} _autotst >$DEVNULL 2>&1
- X
- X if _autotst
- X then
- X echo 'Sorry, incompetent bcopy'
- X echo '#define NObcopy' >>$ACONF
- X fi
- X ${RM} _autotst
- Xfi
- X
- Xcat >_autotst.c <<HERE
- X#include "includes.h"
- Xmain(){unsigned long s=(size_t)~0;int i;
- X for(i=1;s>>=1;++i);
- X if(i<=16)
- X puts("#define SMALLHEAP");
- X return 0;}
- XHERE
- X
- Xecho 'Determining the most applicable block size'
- X
- X${MAKE} _autotst >$DEVNULL 2>&1
- X_autotst >>$ACONF
- X${RM} _autotst
- X
- Xif test -d /usr/spool/mail
- Xthen
- X echo '#define SYSTEM_MAILBOX "/usr/spool/mail/$USER"' >>$ACONF
- Xelif test -d /usr/mail
- Xthen
- X echo '#define SYSTEM_MAILBOX "/usr/mail/$USER"' >>$ACONF
- Xelse
- X echo '#define SYSTEM_MAILBOX "$HOME/.mail"' >>$ACONF
- X echo Could not find the system-mailbox directory, supplied substitute
- Xfi
- X
- Xcat >lookfor <<HERE
- Xfor a in /usr/lib /lib /usr/etc /etc /usr/bin /bin /usr/local/bin /usr/lbin \
- X /usr/local/lib /usr/local /usr/.lib
- Xdo
- X if test -f "\$a/\$1"
- X then
- X echo "#define SENDMAIL \"\$a/\$1\"" >>$ACONF
- X exit 0
- X fi
- Xdone
- Xexit 1
- XHERE
- Xchmod 0755 lookfor
- X
- Xif lookfor sendmail || lookfor smail
- Xthen
- X:
- Xelse
- X echo 'Could not find any mailer. It should be a mailer accepting at least'
- X echo "one plain destination address as it's only argument (any sendmail"
- X echo 'compatible mailer will do), and the mail-to-be-sent on stdin.'
- X echo 'What is your mailer called? (You can override this in config.h)'
- X read a
- X echo "#define SENDMAIL \"$a\"" >>$ACONF
- Xfi
- X
- X${RM} _autotst* lookfor grepfor
- X
- Xecho -----------------------------autoconf.h-----------------------------------
- Xcat $ACONF >&2
- Xecho --------------------------------------------------------------------------
- END_OF_FILE
- if test 7670 -ne `wc -c <'procmail/autoconf'`; then
- echo shar: \"'procmail/autoconf'\" unpacked with wrong size!
- fi
- # end of 'procmail/autoconf'
- fi
- if test -f 'procmail/config.h' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'procmail/config.h'\"
- else
- echo shar: Extracting \"'procmail/config.h'\" \(7789 characters\)
- sed "s/^X//" >'procmail/config.h' <<'END_OF_FILE'
- X/*$Id: config.h,v 2.19 1992/04/29 15:54:33 berg Rel $*/
- X
- X/*#define KERNEL_LOCKS /* uncomment if you want to use kernel locks on file
- X descriptors (not recommended if your system uses a
- X buggy lockd across a net, or if your mailer uses tmp files in updating
- X mailboxes and moves them into place); only advisable if your mailreader
- X can't be convinced to use "dotfile"-locks */
- X
- X/*#define sMAILBOX_SEPARATOR "\1\1\1\1\n" /* sTART- and eNDing separ. */
- X#define eMAILBOX_SEPARATOR "\2\1\1\1\n" /* uncomment if your mail
- X system uses nonstandard
- X mail separators (non sendmail or smail compatible mailers like MMDF),
- X if yours is even different, uncomment and change the value of course */
- X
- X/* KEEPENV and PRESTENV should be defined as a comma-separated null-terminated
- X list of strings */
- X
- X/* every environment variable appearing in KEEPENV will not be thrown away
- X * upon startup of procmail, e.g. you could define KEEPENV as follows:
- X * #define KEEPENV {"TZ","LANG",0}
- X */
- X#define KEEPENV {0}
- X
- X/* every environment variable appearing in PRESTENV will be set or wiped
- X * out of the environment (variables without an '=' sign will be thrown
- X * out), e.g. you could define PRESTENV as follows:
- X * #define PRESTENV {"IFS","PATH=$HOME/bin:/bin:/usr/bin",0}
- X * any side effects (like setting the umask after an assignment to UMASK) will
- X * *not* take place
- X */
- X#define PRESTENV {"IFS","LD_LIBRARY_PATH",0}
- X
- X/*****************************************************************
- X * Only edit below this line if you have edited this file before *
- X *****************************************************************/
- X
- X/*#define NO_USER_TO_LOWERCASE_HACK /* uncomment if your getpwnam() is
- X case insensitive or if procmail
- X will always be supplied with the correct case in the explicit
- X delivery mode argument */
- X
- X/*#define NO_NFS_ATIME_HACK /* uncomment if you're definitely not using
- X NFS mounted filesystems and can't afford
- X procmail to sleep for 1 sec. before writing a mailbox */
- X
- X/* every user & group appearing in TRUSTED_IDS is allowed to use the -f option
- X if the list is empty (just a terminating 0), everyone can use it
- X TRUSTED_IDS should be defined as a comma-separated null-terminated
- X list of strings */
- X
- X#define TRUSTED_IDS {"root","daemon","uucp","mail","x400",0}
- X
- X/*#define SYSTEM_MBOX "$HOME/.mbox" /* uncomment and/or change if the
- X preset default mailbox is *not*
- X either /usr/spool/mail/$USER or /usr/mail/$USER (it will supersede
- X the value of SYSTEM_MAILBOX) */
- X
- X/*#define DEFsendmail "/bin/mail" /* uncomment and/or change if the
- X preset default SENDMAIL is not
- X suitable */
- 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 NOBODY_uid 0xfffe /* default uid when no valid recipient */
- X#define NOBODY_gid 0xfffe /* default gid when no valid recipient */
- X#define ROOT_uid 0
- X
- X#define INIT_UMASK (S_IRWXG|S_IRWXO) /* == 077 */
- X#define NORMperm (S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH)
- X /* == 0666, normal mode bits used to create files, before umask */
- X#define LOCKperm 0 /* mode bits used while creating lockfiles */
- X#define MAX_LOCK_SIZE 0 /* lockfiles are expected not to be longer */
- X#ifndef SMALLHEAP
- 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#else /* and some lower defaults for the unfortunate amongst us */
- X#define DEFlinebuf 512
- X#define BLKSIZ 1024
- X#define STDBUF 128
- X#endif /* SMALLHEAP */
- X#define HOSTNAMElen 9 /* nr of significant chararacters for HOST */
- X#define BOGUSprefix "BOGUS." /* prepended to bogus mailboxes */
- 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 "$ORGMAIL"
- X#define DEFdefaultlock "LOCKFILE=$DEFAULT$LOCKEXT"
- X#define DEFmsgprefix "msg."
- X#define DEFlockext ".lock"
- X#define DEFshellflags "-c"
- X#define DEFlocktimeout 3600 /* defaults to one hour */
- X#define DEFtimeout (DEFlocktimeout-60) /* 60 seconds to clean up */
- X#define DEFnoresretry 4 /* default nr of retries if no resources left */
- X
- X#define BinSh "/bin/sh"
- X#define Tmp "/tmp"
- X#define DEBUGPREFIX ':' /* debug prefix for LOGFILE */
- X#define DevNull "/dev/null"
- X#define DIRSEP "/" /* directory separator symbols, the */
- X /* last one should be the most common one */
- X
- X#define EOFName " \t\n#`'\");"
- X
- X#define VERSIONOPT 'v' /* option to display version */
- X#define PRESERVOPT 'p' /* preserve environment */
- X#define TEMPFAILOPT 't' /* return EX_TEMPFAIL on error */
- X#define FROMWHOPT 'f' /* set name on From_ line */
- X#define ALTFROMWHOPT 'r' /* alternate and obsolete form of -f */
- X#define DELIVEROPT 'd' /* deliver mail to named recipient */
- X#define PROCMAIL_USAGE \
- X "Usage: procmail [-vpt] [-f fromwhom] [parameter=value | rcfile] ...\
- X\n Or: procmail [-vpt] [-f fromwhom] -d recipient ...\n"
- X
- X#define MINlinebuf 128 /* minimal LINEBUF length (don't change this) */
- X#define FROM_EXPR "\nFrom "
- X#define FROM "From "
- X#define NSUBJECT "^Subject:.*$"
- X#define MAXSUBJECTSHOW 78
- 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
- X
- X#define RECFLAGS "HBDAahbfcwWi"
- X#define HEAD_GREP 0
- X#define BODY_GREP 1
- X#define DISTINGUISH_CASE 2
- X#define ALSO_NEXT_RECIPE 3
- X#define ALSO_N_IF_SUCC 4
- X#define PASS_HEAD 5
- X#define PASS_BODY 6
- X#define FILTER 7
- X#define CONTINUE 8
- X#define WAIT_EXIT 9
- X#define WAIT_EXIT_QUIET 10
- X#define IGNORE_WRITERR 11
- X
- X#define UNIQ_PREFIX '_' /* prepended to temporary unique filenames */
- X#define ESCAP '>'
- X
- X /* some formail-specific configuration options: */
- X
- X#define UNKNOWN "foo@bar" /* formail default originator name */
- X#define OLD_PREFIX "Old-" /* formail field-Old-prefix */
- X
- X#define FM_SKIP '+' /* skip the first nnn messages */
- X#define FM_TOTAL '-' /* only spit out a total of nnn messages */
- X#define FM_BOGUS 'b' /* leave bogus Froms intact */
- X#define FM_FORCE 'f' /* force formail to accept an arbitrary format */
- X#define FM_REPLY 'r' /* generate an auto-reply header */
- X#define FM_KEEPB 'k' /* keep the header, when replying */
- X#define FM_TRUST 't' /* trust the sender to supply a valid header */
- X#define FM_SPLIT 's' /* split it up */
- X#define FM_NOWAIT 'n' /* don't wait for the programs */
- X#define FM_EVERY 'e' /* don't require empty lines leading headers */
- X#define FM_MINFIELDS 'm' /* the number of fields that have to be found */
- X#define DEFminfields 2 /* before a header is recognised as such */
- X#define FM_DIGEST 'd' /* split up digests */
- X#define FM_QUIET 'q' /* ignore write errors on stdout */
- X#define FM_EXTRACT 'x' /* extract field contents */
- X#define FM_ADD_IFNOT 'a' /* add a field if not already there */
- X#define FM_REN_INSERT 'i' /* rename and insert a field */
- X#define FM_DEL_INSERT 'I' /* delete and insert a field */
- X#define FM_USAGE "Usage: \
- Xformail [+nn] [-nn] [-bfrktnedq] [-m nn] [-xaiI field] [-s prog arg ...]\n"
- END_OF_FILE
- if test 7789 -ne `wc -c <'procmail/config.h'`; then
- echo shar: \"'procmail/config.h'\" unpacked with wrong size!
- fi
- # end of 'procmail/config.h'
- fi
- if test -f 'procmail/examples/advanced' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'procmail/examples/advanced'\"
- else
- echo shar: Extracting \"'procmail/examples/advanced'\" \(11463 characters\)
- sed "s/^X//" >'procmail/examples/advanced' <<'END_OF_FILE'
- XDiscusses:
- X 1. One home directory, several machine architectures
- X 2. Procmail as an integrated local mail delivery agent
- X 2a.Special directions for sites with sendmail
- X 2b.Special directions for sites with smail
- X 3. Security considerations (when installing procmail suid root)
- X 4. How to generate autoreplies
- X 4a.`Vacation' functionality
- X 5. Some exorbitant examples of rcfile formats
- X 6. Some advanced examples of the use of the 'A' flag
- X
- X ---
- X
- X1. One home directory, several machine architectures
- X -------------------------------------------------
- X
- XFor users that have the very same home directory on machines with differing
- Xarchitectures (i.e. you need different executables), and they
- Xhave to explicitly use (i.e. the system administrator did not arrange,
- Xfor example, /usr/local/bin/procmail to have exactly the right contents
- Xdepending on from which machine it is called) two executables of procmail,
- XI have the following suggestion to use as a .forward file (examples are for
- Xsparc and sun3 architectures):
- X
- X"|IFS=' ';if /usr/bin/sparc;then exec /home/berg/bin.sun4/procmail;else exec /home/berg/bin.sun3/procmail;fi #YOUR_LOGIN_NAME"
- X
- Xor alternatively:
- X
- X"|IFS=' ';exec /home/berg/bin.`/usr/bin/arch`/procmail #YOUR_LOGIN_NAME"
- X
- XPlease note, in the .forward file there can NOT be any newlines between
- Xthe doublequotes, i.e. the former example *has* to be typed in as one long
- Xline.
- X
- XIf, on the other hand, you have to log in to every machine to read mail
- Xarrived for you on that machine, a different solution might be more
- Xappropriate; in that case put something like the following two lines in your
- X.forward file:
- X
- XYOUR_LOGIN_NAME@your.favourite.machine
- X"|IFS=' ';if test .`/bin/uname -n` = .your.favourite.machine; then /exec /home/berg/bin/procmail; else exit 0; fi #YOUR_LOGIN_NAME"
- X
- XThe leading dots are important. Check what `/bin/uname -n` returns on
- Xyour.favourite.machine, and substitute that for your.favourite.machine in the
- Xsample .forward file. If your system does not have /bin/uname, /bin/hostname
- Xwill do too.
- X
- X ---
- X
- X2. Procmail as an integrated local mail delivery agent
- X ---------------------------------------------------
- X
- XCompletely integrating procmail in the mail delivery means that mail is
- Xdelivered as normal, unless a .procmailrc file is present in the home
- Xdirectory of the recipient. This will be completely independent of the
- Xfact if a .forward file is present. This will not break anything, it
- Xjust makes the use of procmail easier because people are not required to
- Xstart up procmail from within their .forward files. Creation of a .procmailrc
- Xfile will suffice.
- X
- XThe generic way to accomplish this (works with sendmail, smail and any other
- Xmail system that uses a local mail delivery program that takes the mail-
- Xto-be-delivered on stdin and the recipient(s) on the command line, with or
- Xwithout the "-d" option) is this:
- X
- XMove your current local mail delivery agent (e.g. /bin/mail, /bin/lmail,
- X/usr/lib/mail/mail.local, etc.) out of the way, and create a (symbolic or hard)
- Xlink from there to procmail, as in "ln /usr/local/bin/procmail /bin/lmail".
- X
- XIn addition to needing root priviliges upon startup, on some systems procmail
- Xneeds to be sgid to daemon or mail. One way to check is by looking at the
- Xcurrent mail delivery agent (usually /bin/mail) and to mimic its permissions,
- Xowner and group. If you're not quite sure, just type "make recommend" and some
- Xsuitable recommendations will be made for your particular environment.
- X
- XThe same might apply to the "lockfile" program, in order for it to be able to
- Xcreate and unlink lockfiles in the mail spool directory it might need to be
- Xsgid to daemon or mail, not to worry however, "lockfile" will not enable users
- Xto abuse the sgid/suid-ness.
- X
- X ---
- X
- X2a.Special directions for sites with sendmail
- X ------------------------------------------
- X
- XHere you have two options:
- X i. Procmail *not* being suid root
- X ii.Procmail suid root (actually preferred and recommended)
- X
- X)Ad i.
- XThe following line should take the place of the standard
- XMlocal rule in your sendmail.cf (this way sendmail will start up procmail with
- Xroot priv, procmail will immediately setuid itself to the recipient's uid):
- X
- XMlocal, P=/usr/local/bin/procmail, F=lsSDFMuhP, S=10, R=20, A=procmail -d $u
- X
- X)Ad ii.
- XIf your sendmail does not allow starting programs with root privs (the
- X'S' flag), you can instead make procmail suid root (this is actually the
- Xpreferred way to go, it closes a security hole which actually sendmail should
- Xhave closed). This will not create a security hole, procmail will normally
- Xsetuid immediately to the real uid (effectively losing root privs), or will
- Ximmediately setuid to the recipient's uid (and be completely loyal to the
- Xrecipient's absent or present .procmailrc file). Actually installing procmail
- Xsuid root is a slightly more flexible approach (not at all more dangerous).
- X
- XIf using the suid root version of procmail, you only need to insert the
- Xfollowing line in your sendmail.cf:
- X
- XMlocal, P=/usr/local/bin/procmail, F=lsDFMuhP, S=10, R=20, A=procmail -d $u
- X
- XSo, to summarise, if you install procmail not-suid-root you should use the
- Xfirst rule (with the 'S' flag), and if you install it suid-root you should
- Xuse the second rule (without the 'S' flag). If you install procmail
- Xnot-suid-root you cannot use the second rule, since procmail will not be
- Xable to change uid to the recipient, and therefore it cannot read/write
- Xthe recipient's files (including any .procmailrc). The alternative would
- Xbe that procmail already has the recipient's uid upon startup, this is not
- Xpossible in sendmail without changing some configuration options.
- X
- XAs for the remaining flags "S=10, R=20", if your system uses others or
- Xnone on the current Mlocal rule, use those instead of "S=10, R=20".
- X
- X ---
- X
- X2b.Special directions for sites with smail
- X ---------------------------------------
- X
- XFor smail 2.x users there are two options:
- X i. Move the current local-mail-delivery program (probably /bin/lmail) out of
- X the way, make a symbolic or hard link from procmail to the name of that
- X program (e.g. "ln /usr/local/bin/procmail /bin/lmail")
- X ii.Make sure the following macro is defined in src/defs.h:
- X #define LMAIL(frm,sys) "/usr/local/bin/procmail -d"
- X
- XFor smail 3.x users there are also two options:
- X i. The same solution as for smail 2.x (however, method ii is preferred)
- X ii.Replace any existing "local"-entry in the /usr/lib/smail/transports file
- X (create one, if need be) with the following two lines:
- X
- Xlocal: return_path, local, from, driver=pipe;
- X cmd="/usr/local/bin/procmail -d $($user$)"
- X
- XFor any ideas on suid/sgid modes which *might* be needed, see the previous
- Xparagraph (2).
- X
- X ---
- X
- X3. Security considerations (when installing procmail suid root)
- X -------------------------------------------------------------
- X
- XIf in EXPLICIT DELIVERY mode (typically when called from within sendmail)
- Xprocmail will ALWAYS change UID and gid to the RECIPIENT's defaults as soon as
- Xit starts reading the recipient's $HOME/.procmailrc file.
- X
- XIf NOT in explicit delivery mode (typically when called from within the
- Xrecipient's $HOME/.forward file) procmail will ALWAYS change UID and gid to
- Xthe real uid and gid of the INVOKER (effectively losing any suid or sgid
- Xpriviliges).
- X
- XThese two precautions should effectively eliminate any security holes because
- Xprocmail will always have the uid of the person whose commands it is executing.
- X
- XTo summarise, procmail will only behave better if made suid/sgid something, in
- Xfact, making procmail suid/sgid something will *improve* security on systems
- Xwhich have dynamically linked libraries.
- X
- X ---
- X
- X4. How to generate autoreplies
- X ---------------------------
- X
- XUsing a recipe like the following, you can generate autoreplies to mail
- Xreceived by you:
- X
- X: 2 h c
- X!^From +[^ ]*(postmaster|Mailer)
- X!^From +YOUR_LOGIN_NAME
- X| (formail -r ; echo "Mail received.") | $SENDMAIL -t
- X
- XAs you can see, I made sure that neither bouncing mail (from postmaster or the
- Xmailer-daemon), nor mail coming from yourself will be autoreplied. If this
- Xprecaution would not be taken, disaster could result ("ringing" mail).
- XThe abovementioned recipe should be inserted before all other recipes in
- Xyour rcfile, however, it is advisable to put it *after* any recipes that
- Xprocess mailinglist subscriptions; it generally is not a good idea to
- Xgenerate autoreplies to mailinglists.
- X
- X ---
- X
- X4a.`Vacation' functionality
- X ------------------------
- X
- XSHELL=/bin/sh # for other shells, this might need adjustment
- XALREADYSENT=$MAILDIR/vacation # the vacation database
- X
- X: 2 hWc: # the lockfile is important
- X!^From +[^ ]*(postmaster|Mailer)
- X!^From +YOUR_LOGIN_NAME
- X| FROM="`formail -rx To:`" ;\
- X if fgrep -e "$FROM" <$ALREADYSENT ;\
- X then exit 1 ;\
- X else echo "$FROM" >>$ALREADYSENT ;\
- X fi
- X
- X :ahc
- X | (formail -r ; echo "Mail received.") | $SENDMAIL -t
- X
- XThis example is based on the same principles as before (sort out bounced mail
- Xand mail coming from oneself). In addition to that however, it maintains a
- Xvacation database by extracting the name of the sender and appending it
- Xto $ALREADYSENT if the name is *not* already in there. If the name was new,
- Xan autoreply will be sent (using the "a" flag functionality, see the man
- Xpage of procmail for more info). To reliably extract the name of the sender,
- XI let formail generate an autoreply header (thereby making it figure out the
- Xmost appropriate sender address), and then telling it to extract the value
- Xof the "To:" field.
- X
- X ---
- X
- X5. Some exorbitant examples of rcfile formats
- X ------------------------------------------
- X
- X# Now follows an example of what you can do in a procmailrc file
- XHELLO=oneword
- XHELLO="two words"
- XHELLO='two words' HELLO = one\
- Xword
- XHELLO=two\ words
- XHELLO=two\ `echo words`
- XHELLO= # empty
- XHELLO # This will wipe "HELLO" from the environment
- XHELLO = "three words"\ yes
- XHELLO = "$HELLO `cat somefile` " # Trailing blanks
- XHELLO = "wheeee`date`${HELLO} this works too" HELLO = 'But so does this!'
- X
- X# As you can see, every trick in the book of /bin/sh programming can be used
- X# (and more).
- X
- XLOCALLOCKFILE = llf
- X
- X ::$LOCALLOCKFILE
- Xgrep for this
- X |$HELLO # calls up a program named "But" with 3 arguments
- X
- X:: "test ing" # lockfilename with a space in it
- Xgrep for this
- X |$HELLO
- X
- X:
- Xor for this
- X|"$HELLO" # tries to call up a program named "But so does this!"
- X
- X:
- Xand this
- X|$HELLO \
- Xthere # action lines can be continued
- X
- X ---
- X
- X6. Some advanced examples of the use of the 'A' flag
- X -------------------------------------------------
- X
- X:c # Specify the 'c' otherwise we never arrive at the next recipe
- X^From Myfriend
- Xevery_message_from_my_friend # Mailbox for everything he/she writes
- X
- X:Ac # Note the 'c' again
- X! my_other_friend # Forward everything Myfriend writes to my_other_friend
- X
- X:1Ac
- X^Subject:.*jokes
- X! my_third_friend # Forward everything Myfriend writes about jokes
- X # to my_third_friend
- X
- X:2A
- X^Subject:.*parties
- X!beach
- X! my_third_friend # Forward everything Myfriend writes about parties,
- X # except beach parties, to my_third_friend
- X
- X:A # Provide a mail sink, in order to fake procmail into
- X/dev/null # believing that the mail was absorbed/delivered,
- X # even if the mail was about beach parties :-).
- X # This is not the best solution though, better would be to
- X # rearrange these last five recipes so that the current
- X # number one or two is last, the current number five can be
- X # omitted then.
- X
- X ---
- END_OF_FILE
- if test 11463 -ne `wc -c <'procmail/examples/advanced'`; then
- echo shar: \"'procmail/examples/advanced'\" unpacked with wrong size!
- fi
- # end of 'procmail/examples/advanced'
- fi
- if test -f 'procmail/examples/mailinglist' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'procmail/examples/mailinglist'\"
- else
- echo shar: Extracting \"'procmail/examples/mailinglist'\" \(11170 characters\)
- sed "s/^X//" >'procmail/examples/mailinglist' <<'END_OF_FILE'
- X$Id: mailinglist,v 2.6 1992/04/09 16:17:41 berg Rel $
- X
- X How to set up mailing lists
- X ---------------------------
- X
- X Written by Stephen R. van den Berg.
- X berg@messua.informatik.rwth-aachen.de
- X berg@physik.tu-muenchen.de
- X
- XThis document mainly describes a sendmail environment, much of it applies
- Xto non-sendmail mail agents as well.
- X
- X
- XContents:
- X--------- 1. Intro
- X 2. Bouncing mail
- X 3. The disadvantages
- X 4. How to circumvent these disadvantages
- X 5. Why use procmail to filter the mailinglist mail?
- X 6. How do I use procmail to filter the mailinglist mail?
- X 7. Now, what does the above all do?
- X 8. The result of this exercise
- X
- X1. Intro
- X -----
- X
- XThe simplest and most direct way to do it is by insert a line in
- Xthe /usr/lib/aliases file looking like:
- X
- Xmylist: fred,john, wilma, barney@bedrock, pebbles
- X
- XNow all the mail arriving at your machine for "mylist" (either local or
- Xmylist@your.domain) will be automatically forwarded to all the mentioned
- Xaddresses (fred, john, etc.).
- X
- XThe address mylist@your.domain is intended for submissions to the list that
- Xare supposed to be forwarded to all the subscribers. For the administrative
- Xtasks like removals from the list, new subscribtions to the list, or address
- Xchanges of subscribers one should create a second entry in the /usr/lib/aliases
- Xfile:
- X
- Xmylist-request: your_login_name@your.domain
- X
- X
- X2. Bouncing mail
- X -------------
- X
- XIn order to deal with bouncing mail gracefully, an extra precaution should
- Xbe taken. If for example mail to wilma bounces (user non-existent, mail
- Xfilesystem full, etc.), it will bounce back to the original sender.
- XNow, the only person that should be concerned with distribution failures
- Xshould be the mylist-request holder. Therefore you should be using a
- Xsendmail special alias like:
- X
- Xowner-mylist: mylist-request@your.domain
- X
- XThis way local mail will bounce back to mylist-request@your.domain.
- X
- X
- X3. The disadvantages
- X -----------------
- X
- XIf you are using the above methods, some obvious disadvantages come to mind
- Xhowever:
- X
- Xa. The subscriber list cannot exceed 1000 bytes (on most sendmails).
- Xb. The subscriber list cannot be changed on-the-fly (/usr/lib/aliases needs
- X to be edited, and newaliases has to be run).
- Xc. People cannot be prevented from submitting messages like "Please remove
- X me from this mailinglist" to mylist (and thereby annoying all subscribers).
- Xd. People cannot be guarded from themselves in case they insert
- X "Return-Receipt-To:" fields in their headers (if they are particularly
- X unlucky, they will receive an acknowledge mail from *every* subscriber's
- X sendmail).
- Xe. People including "Errors-To:" or "Sender:" fields can cause the bounce
- X messages to bypass owner-mylist anyway.
- Xf. There is no way of limiting the number of submitters, i.e. every person
- X who knows the name of the mailing list and who can send mail to your.domain
- X is able to submit messages to the list. This means, for example, that you
- X cannot limit a mailing list to local users (i.e. only local users can
- X submit).
- Xg. You are unable to insert a "Reply-To: mylist@your.domain" in case you
- X would want to (this makes replying to the list easier).
- X
- X
- X4. How to circumvent these disadvantages
- X -------------------------------------
- X
- Xa. Can be circumvented by using nested aliases like:
- X mylist: mylist1, mylist2
- X mylist1: fred,john
- X mylist2: wilma,barney@bedrock,pebbles
- X This can however, become extremely messy to maintain.
- X
- Xb. This can partly be avoided if you use aliases like:
- X mylist: :include:/path/to/the/memberfile
- X The memberfile should contain:
- X fred,john,wilma,barney@bedrock,pebbles
- X You cannot avoid using newaliases however, and it *will* get extremely messy
- X if you have to start using nested aliases.
- X
- Xc. Can only be taken care of by using a mailfilter like procmail.
- X
- Xd. Can only be taken care of by using a mailfilter like procmail.
- X
- Xe. Can only be taken care of by using a mailfilter like procmail.
- X
- Xf. Can only be taken care of by using a mailfilter like procmail.
- X
- Xh. Can only be taken care of by using a mailfilter like procmail.
- X
- X
- X5. Why use procmail to filter the mailinglist mail?
- X ------------------------------------------------
- X
- XInstead of using a mailfilter you could also take care of most of the problems
- Xthree till seven by editing the sendmail.cf file. I would strongly recommend
- Xagainst this approach however, since this will be too much of a customising
- Xoperation and surely will not be a trivial task (in all cases). As a general
- Xrule: don't mess with a sendmail.cf file once it is working :-).
- X
- XNow, you could, instead of procmail, simply use immediate VNIX commands
- Xlike grep, sed, awk to do the mail filtering. Again, there are some obvious
- Xdisadvantages with this approach:
- X
- XA. In case any system resources go out (no more file descriptors, no more
- X swap space, process table full, file system full (for temporary files))
- X your awk or shell script will fail generously (i.e. several bad things
- X could happen: mail munged, truncated, lost, hanging awk or sh programs,
- X etc., you get the picture).
- X
- XB. All mail headers (including From: and Reply-To:) could very well be
- X multi-line headers; it will be very difficult to make it understandable
- X to awk that somehow the header line could continue on the next line
- X (in case you want to remove a header, or do some complicated substitution).
- X
- XC. Another hairy problem will be determining the end of the header, of course
- X that is solvable, but you have to make some extra precautions in your
- X awk script to ensure that any substitutions/changes will not occur in
- X the body of the message.
- X
- XProcmail does not *directly* allow you to change any headers, but that
- Xfeature is not really necessary since you can tell procmail to send ONLY the
- Xheader through some filter of your choice.
- X
- XTo comment on the previously mentioned three disadvantages:
- X
- XA. procmail takes care of that. Should the filter have problems anyway,
- X procmail will graciously notice that the filter was in some kind of
- X trouble, and will try something else with the original unmunged mail
- X (you can specify what it should do of course, obvious choices: try
- X the same filter again, drop the mail in a file and send you a notice,
- X forward the mail to you instead (unfiltered), etc.)
- X
- XB. procmail will concatenate any headers that were continued according to
- X the RCF 822 recommendations, i.e. your filters will see one line per header.
- X
- XC. procmail can be told to send the header, the body or both through the
- X filter, hence your filter need not watch out to avoid doing any
- X substitutions in the body, and the filter can therefore be a lot simpler.
- X
- XProcmail has some additional advantages too:
- X
- X -- It will probably all go a bit faster, since only the header of the mail
- X is being piped through the filter. Also, procmail reads in the mail in
- X 16KB chunks, not line by line as sed does.
- X
- X -- You could use procmail to filter out any messages to the normal mailing
- X list that should have gone to the mylist-request and remail them to
- X mylist-request.
- X
- XWell, anyway, as you see, procmail does not give you everything you would want,
- Xbut this was intentional in accordance to the true VNIX spirit (modularity).
- XWhat procmail does provide is a *very* reliable hook (you might say it
- Xprovides an anchor :-) for any mail processing you might do. For the more
- Xcomplex things you still have to use shell scripts or call other programs
- Xfrom within procmail, but then again, that saves you from learning any
- Xparticular syntax procmail would have had to do the same.
- X
- XAs it happens, the accompanying formail program is able to cater to most
- X(if not all) of your needs regarding mail munging.
- X
- XIf, on the other hand, you want to do more complex things like moderated
- Xmailing lists with several moderators, etc., if would suggest you take
- Xa look at the more complex/specialised mail-server packages like:
- Xlistserv available on cs.bu.edu, author: tasos@cs.bu.edu
- XOf course, most of what these packages can do, can be done with procmail as
- Xwell; it is just that you might be forced to write some additional shell
- Xscripts/programs to accomplish the same.
- X
- X
- X6. How do I use procmail to filter the mailinglist mail?
- X -----------------------------------------------------
- X
- XFirst you have to create these two entries in your /usr/lib/aliases file of
- Xmachine "your.domain" (the mylist: line should be typed in as one long line):
- X
- Xmylist: "|IFS=' ';exec /usr/local/bin/procmail /some/path/listrc subscribers=/some/path/memberlist list=mylist@your.domain listreq=mylist-request@your.domain"
- Xmylist-request: your_login_name@your.domain
- Xowner-mylist: mylist-request
- X
- XCreate a file named /some/path/memberlist which contains the names of the
- Xsubscribers separated by whitespace (blanks, tabs or newlines) like:
- X
- X fred john wilma barney@bedrock pebbles
- X
- XThe /some/path/listrc file should look like the sample listrc file
- Xsupplied in this directory. This listrc file need only be present once,
- Xit will cater for all the mailinglists you'd like to create.
- X
- X
- X7. Now, what does the above all do?
- X --------------------------------
- X
- XIf mail arrives at mylist, first of all procmail will be started using
- X/some/path/listrc as the rcfile. Then it will grep the header to check if
- Xit could be a bounced message after all (from postmaster or mailer-daemon),
- Xor if it probably is a request message. If neither applies, procmail will
- Xfilter just the header of the message through formail.
- X
- Xformail will remove any "Return-Receipt-To:" fields, and will provide plain
- Xsubstitutes for "Errors-To:" and "Sender:". Then it will look for
- Xany "Reply-To:" fields which are already in the header and rewrite them
- Xas "Old-Reply-To:"; after having done this it will add your "Reply-To:"
- Xfield. BTW, the "Return-Receipt-To:" and "Errors-To:" fields are not
- Xrecommended by the RFC-822, they are however commonly supported by most
- Xsendmails; if they are not supported however, they won't hurt, they will
- Xsimply be ignored.
- X
- XThen, the mail is piped into $SENDMAIL which receives, as command line
- Xarguments, the addresses of all subscribers. The option -f will only
- Xtake effect if sendmail is running under daemon privileges; this only
- Xoccurs if the sender of the mail is *not* a local user; if the sender
- Xis a local user, then sendmail (and procmail) runs as the local user.
- X
- X*********************************** WARNING **********************************
- X* *
- X* For this reason it might be wise to allow writing of the memberlist file *
- X* only (to a list maintainer), keep the listrc file under *root supervision* *
- X* (i.e. owned by a very reliable person (e.g. root), world readable, but NOT *
- X* world writeable). *
- X* *
- X******************************************************************************
- X
- X
- X8. The result of this exercise
- X ---------------------------
- X
- XAs you can see, we have addressed and solved every single one of the original
- Xseven problems (well, ok, except problem f, that one is left as an excercise
- Xto the reader; shouldn't be too difficult).
- X
- X
- XP.S. Any suggestions/corrections/improvements on this document are welcome.
- END_OF_FILE
- if test 11170 -ne `wc -c <'procmail/examples/mailinglist'`; then
- echo shar: \"'procmail/examples/mailinglist'\" unpacked with wrong size!
- fi
- # end of 'procmail/examples/mailinglist'
- fi
- if test -f 'procmail/regexp.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'procmail/regexp.c'\"
- else
- echo shar: Extracting \"'procmail/regexp.c'\" \(10571 characters\)
- sed "s/^X//" >'procmail/regexp.c' <<'END_OF_FILE'
- X/************************************************************************
- X * Custom regular expression library, *fully* egrep compatible *
- X * *
- X * Seems to be relatively bug free. *
- X * *
- X * Copyright (c) 1991-1992, S.R. van den Berg, The Netherlands *
- X * The sources can be freely copied for non-commercial use. *
- X * #include "README" *
- X * *
- X ************************************************************************/
- X#ifdef RCS
- Xstatic char rcsid[]="$Id: regexp.c,v 2.13 1992/03/06 12:38:31 berg Rel $";
- X#endif
- X#include "config.h"
- X#include "procmail.h"
- X#include "shell.h"
- X
- X#define R_BEG_GROUP '('
- X#define R_OR '|'
- X#define R_END_GROUP ')'
- X#define R_0_OR_MORE '*'
- X#define R_0_OR_1 '?'
- X#define R_1_OR_MORE '+'
- X#define R_DOT '.'
- X#define R_SOL '^'
- X#define R_EOL '$'
- X#define R_BEG_CLASS '['
- X#define R_NOT_CLASS '^'
- X#define R_RANGE '-'
- X#define R_END_CLASS ']'
- X#define R_ESCAPE '\\'
- X
- X#define BITS_P_CHAR 8
- X#define OPB (1<<BITS_P_CHAR)
- X#define OPC_EPS OPB
- X#define OPC_CLASS (OPB+1)
- X#define OPC_DOT (OPB+2)
- X#define OPC_FIN (OPB+3)
- X
- X#define bit_type unsigned
- X#define bit_bits (sizeof(bit_type)*8)
- X#define bit_index(which) ((unsigned)(which)/bit_bits)
- X#define bit_mask(which) ((unsigned)1<<(unsigned)(which)%bit_bits)
- X#define bit_toggle(name,which) (name[bit_index(which)]^=bit_mask(which))
- X#define bit_test(name,which) (!!(name[bit_index(which)]&bit_mask(which)))
- X#define bit_set(name,which,value) \
- X (value?(name[bit_index(which)]|=bit_mask(which)):\
- X (name[bit_index(which)]&=~bit_mask(which)))
- X#define bit_field(name,size) bit_type name[((size)+bit_bits-1)/bit_bits]
- X
- X#define SZ(x) (sizeof(struct x))
- X#define Ceps (struct eps*)
- X#define epso(to,add) (Ceps((char*)(to)+(add)))
- X#define ii (aleps.topc)
- X#define jjp (aleps.tnext)
- X
- X/* the spawn and stack members are reused in the normal opcodes as pc fields */
- Xstatic struct eps{unsigned opc;struct eps*stack,*spawn,*next;}*r;
- Xstatic struct{unsigned topc;struct eps*tnext;}aleps;
- Xstatic uchar*p;
- Xstatic ignore_case;
- X
- Xstruct chclass {unsigned opc_;struct eps*stack_,*spawn_,*next_;
- X bit_field(c,OPB);};
- X
- Xstatic puteps(spot,to,aswell)struct eps*const spot; /* epsilon transition */
- X const struct eps*const to,*const aswell;
- X{ spot->opc=OPC_EPS;spot->next=to!=spot?Ceps to:Ceps aswell;
- X spot->spawn=aswell!=spot?Ceps aswell:Ceps to;spot->stack=0;
- X}
- X
- Xstatic putneps(spot,to)struct eps*const spot;const struct eps*const to;
- X{ puteps(spot,to,spot+1);
- X}
- X
- X#define rAc (((struct chclass*)r)->c)
- X
- Xstatic bseti(i,j)unsigned i;const int j;
- X{ bit_set(rAc,i,j); /* mark 'i' as being in the class */
- X if(ignore_case) /* mark the other case too */
- X { if(i-'A'<26) /* uppercase */
- X i+='a'-'A';
- X else if(i-'a'<26) /* lowercase */
- X i-='a'-'A';
- X else return; /* no case */
- X bit_set(rAc,i,j);
- X }
- X}
- X
- Xstatic por();
- X
- Xstatic psimp(e)const struct eps*const e;
- X{ switch(*p)
- X { case R_BEG_GROUP:++p;por(e);return; /* not so simple after all */
- X case R_BEG_CLASS: /* a simple class */
- X { unsigned i,j=R_NOT_CLASS==*++p;
- X if(e)
- X { r->opc=OPC_CLASS;r->next=Ceps e;r->spawn=r->stack=0;
- X i=maxindex(rAc);
- X do rAc[i]=j?~0:0; /* preset the bit field */
- X while(i--);
- X }
- X if(j) /* skip the 'not' modifier */
- X { ++p;
- X if(e)
- X bit_toggle(rAc,'\n');
- X }
- X if(*p==R_END_CLASS) /* right at the start, cannot mean the end */
- X { ++p;
- X if(e)
- X i=R_END_CLASS,bit_toggle(rAc,R_END_CLASS);
- X }
- X else if(*p==R_RANGE) /* take it literally */
- X { ++p;
- X if(e)
- X i=R_RANGE,bit_toggle(rAc,R_RANGE);
- X }
- X for(;;++p)
- X { switch(*p)
- X { case R_END_CLASS:++p;
- X case '\0':r=epso(r,SZ(chclass));return;
- X case R_RANGE:
- X switch(*++p)
- X { default:
- X if(e)
- X while(++i<*p) /* mark all in the range */
- X bseti(i,!j);
- X break;
- X case '\0':case R_END_CLASS:--p; /* literally */
- X }
- X }
- X if(e)
- X bseti(i= *p,!j); /* a normal character, mark it */
- X }
- X }
- X case '\0':return;
- X case R_DOT: /* matches everything but a newline */
- X if(e)
- X { r->opc=OPC_DOT;goto fine;
- X }
- X goto fine2;
- X case R_EOL:case R_SOL: /* match a newline (in effect) */
- X if(e)
- X { r->opc='\n';goto fine;
- X }
- X goto fine2;
- X case R_ESCAPE: /* quote something */
- X if(!*++p) /* nothing to quote */
- X --p;
- X }
- X if(e) /* a regular character */
- X { r->opc=ignore_case&&(unsigned)*p-'A'<26?*p+'a'-'A':*p;
- Xfine:
- X r->next=Ceps e;r->spawn=r->stack=0;
- X }
- Xfine2:
- X ++p;++r;
- X}
- X
- X#define EOS(x) (jjp?jjp:(x))
- X
- Xstatic pnorm(e)const struct eps*const e;
- X{ void*pold;struct eps*rold;
- X for(;;)
- X { pold=p;rold=r;psimp(Ceps 0);ii= *p; /* skip it first */
- X jjp=p[1]==R_OR||p[1]==R_END_GROUP||!p[1]?Ceps e:Ceps 0;
- X if(e)
- X p=pold,pold=r;
- X switch(ii) /* check for any of the postfix operators */
- X { case R_0_OR_MORE:++r;
- X if(e) /* first an epsilon, then the rest */
- X putneps(rold,EOS(r)),r=rold+1,psimp(rold);
- X goto incagoon;
- X case R_1_OR_MORE: /* first the rest */
- X if(e) /* and then an epsilon */
- X puteps(r,rold,EOS(r+1)),r=rold,psimp(Ceps pold);
- X ++r;goto incagoon;
- X case R_0_OR_1:++r;
- X if(e) /* first an epsilon, then the rest */
- X putneps(rold,r=EOS(r)),pold=r,r=rold+1,psimp(Ceps pold);
- Xincagoon: switch(*++p) /* at the end of this group already? */
- X { case R_OR:case R_END_GROUP:case '\0':return;
- X }
- X continue; /* regular end of the group */
- X case R_OR:case R_END_GROUP:case '\0':
- X if(e)
- X r=rold,psimp(e);
- X return;
- X }
- X if(e) /* no fancy postfix operators, plain vanilla */
- X r=rold,psimp(Ceps pold);
- X }
- X}
- X
- Xstatic por(e)const struct eps*const e;
- X{ uchar*pold;struct eps*rold;
- X for(;;)
- X for(pold=p;;)
- X { rold=r;
- X switch(*p)
- X { default:pnorm(Ceps 0);r=rold;continue; /* still in this group */
- X case '\0':case R_END_GROUP: /* found the end of the group */
- X if(p==pold) /* empty 'or' group */
- X { if(e)
- X puteps(r,e,e); /* misused epsilon as branch, */
- X ++r; /* let the optimiser (fillout()) take it out */
- X }
- X else
- X p=pold,pnorm(e); /* normal last group */
- X if(*p)
- X ++p;
- X return;
- X case R_OR:++r;
- X if(p==pold) /* empty 'or' group */
- X { if(e)
- X putneps(rold,e); /* special epsilon */
- X }
- X else
- X { p=pold;pnorm(e); /* normal 'or' group, first an */
- X if(e) /* epsilon, then the rest */
- X putneps(rold,r);
- X }
- X ++p;
- X }
- X break;
- X }
- X}
- X
- Xstatic findandrep(old,newv)register struct eps**const old;
- X struct eps*const newv;
- X{ register struct eps*i,*t= *old; /* save the value */
- X for(i=r;i->opc!=OPC_FIN;) /* change all pointers from *old to new */
- X { if(i->next==t)
- X i->next=newv;
- X if(i->spawn==t)
- X i->spawn=newv;
- X switch(i->opc)
- X { case OPC_CLASS:i=epso(i,SZ(chclass));break;
- X default:++i;
- X }
- X }
- X *old=t;
- X}
- X
- X#define drs(m) (*(struct eps**)((char*)*stack+(ioffsetof(struct eps,m)^ofs)))
- X
- Xstatic cstack(stack,ofs)struct eps**const stack;
- X{ if(drs(next)->stack==Ceps p)
- X { findandrep(*stack,drs(next));*stack=drs(spawn);return 1;
- X }
- X return 0;
- X}
- X /* break up any closed epsilon circles, otherwise they can't be executed */
- Xstatic fillout(stack)struct eps**const stack;
- X{ if((*stack)->opc!=OPC_EPS||(*stack)->stack)
- X return 0;
- X (*stack)->stack=Ceps p; /* mark this one as used */
- X#define RECURS(nxt) \
- X do\
- X if(cstack(stack,ioffsetof(struct eps,nxt)^ioffsetof(struct eps,next)))\
- X return 1;\
- X while(fillout(&(*stack)->nxt))
- X RECURS(next);RECURS(spawn);return 0; /* recurse */
- X}
- X
- Xvoid*bregcomp(a,ign_case)char const*a;
- X{ struct eps*st;size_t i; /* first a trial run, determine memory needed */
- X p=(uchar*)a;ignore_case=ign_case;r=Ceps&aleps+1;por(Ceps 0);
- X st=malloc((i=(char*)r-(char*)&aleps)+ioffsetof(struct eps,stack)+sizeof r);
- X putneps(st,r=st+1);p=(uchar*)a;por(Ceps((char*)st+i)); /* really compile */
- X r->opc=OPC_FIN;r->stack=0; /* tack on the end */
- X for(r=st;;) /* simplify the compiled code (i.e. */
- X switch(st->opc) /* take out cyclic epsilon references) */
- X { case OPC_FIN:return r; /* finished */
- X case OPC_CLASS:st=epso(st,SZ(chclass));break; /* skip */
- X case OPC_EPS:p=(uchar*)st;fillout(&st); /* check tree */
- X default:++st; /* skip too */
- X }
- X}
- X
- X#define XOR1 \
- X (ioffsetof(struct eps,spawn)^ioffsetof(struct eps,stack))
- X#define PC(this,t) (*(struct eps**)((char*)(this)+(t)))
- X
- Xchar*bregexec(code,text,len,ign_case)struct eps*code;const uchar*text;
- X size_t len;
- X{ register struct eps*reg,*t,*stack,*other,*thiss;unsigned i,th1,ot1;
- X if(code[1].opc==OPC_EPS)
- X ++code; /* two epsilons at the start would be superfluous */
- X (thiss=code)->stack=0;th1=ioffsetof(struct eps,spawn);
- X ot1=ioffsetof(struct eps,stack);--text;++len;
- X i='\n';goto setups; /* make sure any beginning-of-line-hooks catch */
- X do
- X { i= *++text; /* get the next real-text character */
- Xlastrun: /* switch this & other pc-stack */
- X th1^=XOR1;ot1^=XOR1;thiss=other;
- Xsetups:
- X reg=(other=stack=code)->next;goto nostack;
- X do /* pop next entry off this pc-stack */
- X { reg=(t=thiss)->next;thiss=PC(t,th1);PC(t,th1)=0;goto nostack;
- X do /* pop next entry off the work-stack */
- X { stack=(t=stack)->stack;t->stack=0;reg=t->spawn;
- Xnostack: switch(reg->opc-OPB) /* push spawned branch on the work-stack */
- X { default:
- X if(ign_case&&i-'A'<26)
- X i+='a'-'A'; /* transmogrify it to lowercase */
- X if(i==reg->opc) /* regular character match */
- X goto yep;
- X break;
- X case OPC_EPS-OPB:reg->stack=stack;reg=(stack=reg)->next;
- X goto nostack;
- X case OPC_FIN-OPB: /* hurray! complete regexp match */
- X return(char*)text; /* return one past the match */
- X case OPC_CLASS-OPB:
- X if(bit_test(((struct chclass*)reg)->c,i))
- X goto yep; /* character in class */
- X break;
- X case OPC_DOT-OPB: /* dot-wildcard */
- X if(i!='\n')
- Xyep: if(!PC(reg,ot1)) /* state not yet pushed */
- X PC(reg,ot1)=other,other=reg; /* push location onto */
- X } /* other pc-stack */
- X }
- X while(stack); /* the work-stack is not empty */
- X }
- X while(thiss!=code); /* this pc-stack is not empty */
- X }
- X while(--len); /* still text to search */
- X if(ign_case!=2) /* out of text */
- X { ign_case=2;len=1;++text;goto lastrun; /* check if we just matched */
- X }
- X return 0; /* no match */
- X}
- END_OF_FILE
- if test 10571 -ne `wc -c <'procmail/regexp.c'`; then
- echo shar: \"'procmail/regexp.c'\" unpacked with wrong size!
- fi
- # end of 'procmail/regexp.c'
- fi
- if test -f 'procmail/strpbrk.h' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'procmail/strpbrk.h'\"
- else
- echo shar: Extracting \"'procmail/strpbrk.h'\" \(96 characters\)
- sed "s/^X//" >'procmail/strpbrk.h' <<'END_OF_FILE'
- X/*$Id: strpbrk.h,v 1.1 1992/04/16 12:57:55 berg Rel $*/
- X#ifdef NOstrpbrk
- Xchar*strpbrk();
- X#endif
- END_OF_FILE
- if test 96 -ne `wc -c <'procmail/strpbrk.h'`; then
- echo shar: \"'procmail/strpbrk.h'\" unpacked with wrong size!
- fi
- # end of 'procmail/strpbrk.h'
- fi
- echo shar: End of archive 3 \(of 5\).
- cp /dev/null ark3isdone
- MISSING=""
- for I in 1 2 3 4 5 ; do
- if test ! -f ark${I}isdone ; then
- MISSING="${MISSING} ${I}"
- fi
- done
- if test "${MISSING}" = "" ; then
- echo You have unpacked all 5 archives.
- rm -f ark[1-9]isdone
- else
- echo You still need to unpack the following archives:
- echo " " ${MISSING}
- fi
- ## End of shell archive.
- exit 0
- --
- Sincerely, berg@pool.informatik.rwth-aachen.de
- Stephen R. van den Berg (AKA BuGless). berg@physik.tu-muenchen.de
-
- "I have a *cunning* plan!"
-
- exit 0 # Just in case...
-