home *** CD-ROM | disk | FTP | other *** search
Text File | 1993-07-04 | 47.9 KB | 1,396 lines |
- Newsgroups: comp.sources.misc
- From: berg@pool.informatik.rwth-aachen.de (Stephen R. van den Berg)
- Subject: v38i028: procmail - mail processing package v2.90, Part09/11
- Message-ID: <1993Jul1.151348.21879@sparky.imd.sterling.com>
- X-Md4-Signature: 71ed12661abfa71ed2a54c31dab55d5a
- Sender: kent@sparky.imd.sterling.com (Kent Landfield)
- Organization: Sterling Software
- Date: Thu, 1 Jul 1993 15:13:48 GMT
- Approved: kent@sparky.imd.sterling.com
-
- Submitted-by: berg@pool.informatik.rwth-aachen.de (Stephen R. van den Berg)
- Posting-number: Volume 38, Issue 28
- Archive-name: procmail/part09
- Environment: sendmail, smail, MMDF, mailsurr, UNIX, POSIX
- Supersedes: procmail: Volume 35, Issue 21-32,124,125
-
- #! /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 9 (of 11)."
- # Contents: procmail/initmake procmail/src/formail.c
- # procmail/src/multigram.c
- # Wrapped by berg@tubastos on Thu Jul 1 14:06:18 1993
- PATH=/bin:/usr/bin:/usr/ucb ; export PATH
- if test -f 'procmail/initmake' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'procmail/initmake'\"
- else
- echo shar: Extracting \"'procmail/initmake'\" \(7781 characters\)
- sed "s/^X//" >'procmail/initmake' <<'END_OF_FILE'
- X#! /bin/sh
- X:
- X#$Id: initmake,v 1.37 1993/06/23 14:35:06 berg Exp $
- X
- XPATH=.:$PATH
- XBSHELL=$1
- Xshift; MSHELL=$1
- Xshift; RM="$1"
- Xshift; MV="$1"
- Xshift; LN="$1"
- Xshift; SEARCHLIBS="$1"
- Xshift; LIBPATHS="$1"
- Xshift; DEVNULL=$1
- Xshift; MAKE="$1"
- Xshift; O=$1
- Xshift; CC="$1"
- Xshift; CFLAGS1="$1"
- Xshift; LDFLAGS1="$1"
- Xshift; BINSS="$1"
- Xshift; MANS1S="$1"
- Xshift; MANS5S="$1"
- Xshift; SUBDIRS="$1"
- Xshift; BINDIR="$1"
- X
- Xtest 1 != $# &&
- X echo "Don't start this script directly, use \`make init'" && exit 1
- X
- Xtest -z "$MSHELL" || SHELL=$MSHELL
- Xcase "$SHELL" in
- X *sh*)
- X case "$SHELL" in
- X *csh*) echo "Warning: really perverted make detected"; SHELL="";;
- X esac;;
- X *) echo "Warning: perverted make detected"; SHELL="";;
- Xesac
- Xtest -z "$SHELL" && SHELL=$BSHELL
- X
- Xexport SHELL PATH
- X
- XFGREP="fgrep" # POSIX, or not POSIX, that is the question...
- Xif test \^hello = "`echo '^hello' | grep -F '^hello' 2>&1`"
- Xthen FGREP="grep -F" # and POSIX it is!
- Xfi
- X
- Xecho hi | $FGREP hi >$DEVNULL
- Xt=$?
- Xecho ho | $FGREP hi >$DEVNULL
- Xf=$?
- Xif test 0 != $t -o 0 = $f
- Xthen
- X echo "Your \"$FGREP\" program seems to be incapable of returning a proper"
- X echo "exitvalue depending on the success of the search. This script can"
- X echo "not work without it."
- X exit 2
- Xfi
- X
- Xif test ! -z "$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 the *'
- X echo '* the make does not finish by itself, do a: "make clean", *'
- X echo '* clear LD_LIBRARY_PATH from the environment, and start over. *'
- X echo '***************************** WARNING *********************************'
- Xfi
- X
- Xcd src # diving into the source directory ######
- Xcat >_autotst.c <<HERE
- Xmain()
- X{ return 0;
- X}
- XHERE
- X$RM _autotst.rrr _autotst.$O _autotst
- X
- Xcc=""
- X
- Xfor a in "$CC" cc gcc
- Xdo
- X echo $a $CFLAGS1 _autotst.c -o _autotst $LDFLAGS1 >>_autotst.rrr
- X test -z "$cc" -a ! -z "$a" &&
- X ($a $CFLAGS1 _autotst.c -o _autotst $LDFLAGS1) >>_autotst.rrr \
- X 2>&1 && cc="$a"
- X echo "::::" >>_autotst.rrr
- Xdone
- Xif test -z "$cc"
- Xthen
- X echo 2>&1 "Whoeaaa! There's something fishy going on here."
- X echo 2>&1 "You have a look and see if you detect anything uncanny:"
- X echo 2>&1 "-------------------------------------------------------"
- X cat 2>&1 _autotst.rrr
- X echo 2>&1 "-------------------------------------------------------"
- X echo 2>&1 "I suggest you take a look at the definition of CFLAGS* and CC"
- X echo 2>&1 "in the Makefile before you try make again."
- X exit 1
- Xfi
- X$RM _autotst.rrr _autotst.$O _autotst
- Xecho "$cc seems to work fine, using that as the C-compiler"
- X
- Xcat >_autotst.c <<HERE
- X#include <sys/types.h>
- X#include <stdio.h>
- X#include <sys/stat.h>
- Xmain()
- X{ struct stat buf;return!&buf;
- X}
- XHERE
- X
- XCFLAGS=""
- X
- Xcase "$CFLAGS1" in
- X *-D_POSIX_SOURCE*);;
- X *)
- X if $cc -c $CFLAGS1 _autotst.c >$DEVNULL 2>&1
- X then
- X :
- X else
- X $RM _autotst.$O
- X $cc -c $CFLAGS1 -D_POSIX_SOURCE _autotst.c >$DEVNULL 2>&1 &&
- X CFLAGS=" -D_POSIX_SOURCE"
- X fi;;
- Xesac
- X
- XLDFLAGSC=""
- X
- Xtest -f _autotst.$O || $cc -c $CFLAGS1 $CFLAGS _autotst.c >$DEVNULL 2>&1
- X$cc $CFLAGS1 $CFLAGS _autotst.$O -o _autotst $LDFLAGS1 -lc >_autotst.rrr 2>&1 \
- X && if grep "[\"']c['\"]" _autotst.rrr >$DEVNULL
- X then
- X :
- X else
- X LDFLAGSC=" -lc"
- X fi
- X
- XLDFLAGS="$SEARCHLIBS"
- Xfirstrun=yes
- X
- Xwhile $RM _autotst
- X $cc $CFLAGS1 $CFLAGS _autotst.$O -o _autotst $LDFLAGS1 $LDFLAGS \
- X $LDFLAGSC >_autotst.rrr 2>&1
- X test $firstrun = yes -o ! -f _autotst
- Xdo
- X firstrun=no
- X set dummy $LDFLAGS
- X shift
- X echo 2>&1 " ...scanning for $# libraries..."
- X NEWLDFLAGS=""
- X for a in $LDFLAGS dummy
- X do
- X if test dummy != $a
- X then
- X lib=`expr $a : '-l\(.*\)'`
- X if $FGREP lib$lib _autotst.rrr >$DEVNULL ||
- X $FGREP -e $a _autotst.rrr >$DEVNULL ||
- X grep "[\"']$lib['\"]" _autotst.rrr >$DEVNULL
- X then
- X :
- X else
- X OLDIFS="$IFS"; IFS=":$IFS"
- X found=no
- X for libpath in $LIBPATHS $LD_LIBRARY_PATH
- X do
- X set $libpath/*lib$lib[A-Z.]*
- X test -f $1 && found=yes
- X done
- X IFS="$OLDIFS"
- X test yes = $found && NEWLDFLAGS="$NEWLDFLAGS $a"
- X fi
- X fi
- X done
- X if test a"$LDFLAGS" = a"$NEWLDFLAGS"
- X then
- X echo 2>&1 "Whoeaaa! There's something fishy going on here."
- X echo 2>&1 "You have a look and see if you detect anything uncanny:"
- X echo 2>&1 "-------------------------------------------------------"
- X cat 2>&1 _autotst.rrr
- X echo 2>&1 "-------------------------------------------------------"
- X echo 2>&1 \
- X "I suggest you take a look at the definition of LDFLAGS* and SEARCHLIBS"
- X echo 2>&1 "in the Makefile before you try make again."
- X echo 2>&1 "Also: write me a mail showing the errorlog you just generated."
- X echo 2>&1 "The errorlog can still be found in src/_autotst.rrr"
- X echo 2>&1 "It would be helpful if you could mention what machine and OS"
- X echo 2>&1 "you are trying to compile this on (uname -a). Thanks."
- X exit 1
- X fi
- X LDFLAGS="$NEWLDFLAGS"
- Xdone
- X
- X$RM _autotst.$O _autotst.c _autotst
- Xcd .. # returning to the main procmail directory ######
- X
- XLDFLAGS="$LDFLAGS$LDFLAGSC"
- X
- Xtest -z "$CFLAGS" || echo "Added CFLAGS=$CFLAGS"
- Xtest -z "$LDFLAGS" || echo "Added LDFLAGS=$LDFLAGS"
- X
- Xfor a in $SUBDIRS
- Xdo
- X if test ! -f $a/Makefile.init
- X then
- X $LN $a/Makefile $a/Makefile.init
- X $RM $a/Makefile
- X $LN $a/Makefile.init $a/Makefile
- X fi
- Xdone
- X
- Xtest -f Makefile.0 || sed -e '/^# Makefile - mark/,$ !d' <Makefile >Makefile.0
- Xsed -e '/^# Makefile - mark/,$ d' <Makefile >_Makefile
- Xecho "# Makefile.1 - mark, don't (re)move this, a sed script needs it
- X" >>_Makefile
- X
- Xtest a$SHELL != a$MSHELL && echo "SHELL = $SHELL" >>_Makefile
- Xecho "FGREP = $FGREP" >>_Makefile
- Xtest -z "$MAKE" && echo "MAKE = make" >>_Makefile
- Xtest a"$cc" != a"$CC" && echo "CC = $cc" >>_Makefile
- X
- Xecho "CFLAGS = \$(CFLAGS1)$CFLAGS" >>_Makefile
- Xecho "LDFLAGS = \$(LDFLAGS1)$LDFLAGS" >>_Makefile
- Xecho >>_Makefile
- X
- XMANSS=""
- XMANS1=""
- XMANS5=""
- XMANS=""
- XNMANS=""
- XBINS=""
- XNBINS=""
- Xfor a in $MANS1S
- Xdo
- X MANSS="$MANSS $a.1"
- X MANS1="$MANS1 $a.\$(MAN1SUFFIX)"
- Xdone
- Xfor a in $MANS5S
- Xdo
- X MANSS="$MANSS $a.5"
- X MANS5="$MANS5 $a.\$(MAN5SUFFIX)"
- Xdone
- Xfor a in $MANSS
- Xdo
- X MANS="$MANS new/$a"
- X NMANS="$NMANS ../new/$a"
- Xdone
- Xfor a in $BINSS
- Xdo
- X BINS="$BINS new/$a"
- X NBINS="$NBINS ../new/$a"
- Xdone
- X
- Xecho "BINS=$BINS" >>_Makefile
- Xecho "MANS=$MANS" >>_Makefile
- Xecho "MANS1=$MANS1" >>_Makefile
- Xecho "MANS5=$MANS5" >>_Makefile
- Xecho "MANSS=$MANSS" >>_Makefile
- Xecho "NBINS=$NBINS" >>_Makefile
- Xecho "NMANS=$NMANS" >>_Makefile
- Xecho >>_Makefile
- X
- Xfor a in $SUBDIRS
- Xdo
- X sed -e '1,/^# Makefile.0 - mark/ d' <_Makefile >$a/_Makefile
- X cat $a/Makefile.0 >>$a/_Makefile
- Xdone
- X
- Xecho "BINDIR=$BINDIR" >>src/_Makefile
- X
- Xfor a in $BINSS
- Xdo
- X echo >>src/_Makefile
- X echo "../new/$a: $a ../config.check" >>src/_Makefile
- X echo " @\$(RM) \$@" >>src/_Makefile
- X echo " \$(LN) $a \$@" >>src/_Makefile
- Xdone
- X
- Xfor a in $MANSS
- Xdo
- X echo >>man/_Makefile
- X echo "../new/$a: $a ../config.check" >>man/_Makefile
- X echo " @\$(RM) \$@" >>man/_Makefile
- X echo " \$(LN) $a \$@" >>man/_Makefile
- Xdone
- X
- Xfor a in $MANS1S
- Xdo
- X echo >>man/_Makefile
- X echo "$a.1: $a.man man.sed mansed" >>man/_Makefile
- X echo \
- X " \$(SHELL) ./mansed \$(SHELL) $a.man \$@ \"\$(RM)\" \$(DEVNULL)" \
- X >>man/_Makefile
- Xdone
- X
- Xfor a in $MANS5S
- Xdo
- X echo >>man/_Makefile
- X echo "$a.5: $a.man man.sed mansed" >>man/_Makefile
- X echo \
- X " \$(SHELL) ./mansed \$(SHELL) $a.man \$@ \"\$(RM)\" \$(DEVNULL)" \
- X >>man/_Makefile
- Xdone
- X
- Xcat Makefile.1 >>_Makefile
- X$MV _Makefile Makefile
- X
- Xsleep 1 # Some machines are just too speedy, make gets confused
- X
- Xfor a in $SUBDIRS
- Xdo
- X echo "#" >>$a/_Makefile
- X $MV $a/_Makefile $a/Makefile
- Xdone
- END_OF_FILE
- if test 7781 -ne `wc -c <'procmail/initmake'`; then
- echo shar: \"'procmail/initmake'\" unpacked with wrong size!
- fi
- chmod +x 'procmail/initmake'
- # end of 'procmail/initmake'
- fi
- if test -f 'procmail/src/formail.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'procmail/src/formail.c'\"
- else
- echo shar: Extracting \"'procmail/src/formail.c'\" \(18606 characters\)
- sed "s/^X//" >'procmail/src/formail.c' <<'END_OF_FILE'
- X/************************************************************************
- X * formail - The mail (re)formatter *
- X * *
- X * Seems to be relatively bug free. *
- X * *
- X * Copyright (c) 1990-1992, S.R. van den Berg, The Netherlands *
- X * #include "README" *
- X ************************************************************************/
- X#ifdef RCS
- Xstatic /*const*/char rcsid[]=
- X "$Id: formail.c,v 1.24 1993/06/23 12:56:01 berg Exp $";
- X#endif
- Xstatic /*const*/char rcsdate[]="$Date: 1993/06/23 12:56:01 $";
- X#include "includes.h"
- X#include <ctype.h> /* iscntrl() */
- X#include "formail.h"
- X#include "sublib.h"
- X#include "shell.h"
- X#include "common.h"
- X#include "fields.h"
- X#include "ecommon.h"
- X#include "formisc.h"
- X
- Xstatic const char unknown[]=UNKNOWN,re[]=" Re:",fmusage[]=FM_USAGE,
- X From_[]= FROM, /* VNIX 'From ' line */
- X Article_[]= "Article ", /* USENET 'Article ' line */
- X x_[]= "X-", /* general extension */
- X old_[]= OLD_PREFIX; /* my extension */
- X#define ssl(str) str,STRLEN(str)
- X#define bsl(str) {ssl(str)}
- X#define sslbar(str,bar1,bar2) {ssl(str),STRLEN(bar1)-1,STRLEN(bar2)-1}
- X#include "header.h"
- X/*
- X * sender determination fields in order of importance/reliability
- X * reply-address determination fields (wrepl specifies the weight for
- X * for regular replies, wtrepl specifies the weight for trusted users)
- X *
- X * I bet this is the first time you see a bar graph in C-source-code :-)
- X */
- Xstatic const struct {const char*head;int len,wrepl,wtrepl;}sest[]=
- X{ sslbar(replyto ,"******" ,"********" ),
- X sslbar(Fromm ,"*" ,"****" ),
- X sslbar(retreceiptto ,"********" ,"*******" ),
- X sslbar(sender ,"*****" ,"******" ),
- X sslbar(res_replyto ,"***********" ,"***********" ),
- X sslbar(res_from ,"***foo***" ,"***bar***" ),
- X sslbar(res_sender ,"**********" ,"**********" ),
- X sslbar(errorsto ,"*******" ,"*****" ),
- X sslbar(path ,"**" ,"*" ),
- X sslbar(returnpath ,"***" ,"***" ),
- X sslbar(From_ ,"****" ,"**" )
- X};
- X
- Xstatic struct saved rex[]=
- X{ bsl(subject),bsl(references),bsl(messageid),bsl(date)
- X};
- X#define subj (rex+0)
- X#define refr (rex+1)
- X#define msid (rex+2)
- X#define hdate (rex+3)
- X
- X#ifdef sMAILBOX_SEPARATOR
- X#define emboxsep smboxsep
- X#define MAILBOX_SEPARATOR
- Xstatic const char smboxsep[]=sMAILBOX_SEPARATOR;
- X#endif /* sMAILBOX_SEPARATOR */
- X#ifdef eMAILBOX_SEPARATOR
- X#ifdef emboxsep
- X#undef emboxsep
- X#else
- X#define MAILBOX_SEPARATOR
- X#endif
- Xstatic const char emboxsep[]=eMAILBOX_SEPARATOR;
- X#endif /* eMAILBOX_SEPARATOR */
- X
- Xconst char binsh[]=BinSh,sfolder[]=FOLDER,
- X couldntw[]="Couldn't write to stdout";
- Xint errout,oldstdout,quiet,buflast;
- Xpid_t child= -1;
- XFILE*mystdout;
- Xsize_t nrskip,nrtotal= -1,buflen,buffilled;
- Xlong totallen;
- Xchar*buf,*logsummary;
- Xstruct field*rdheader,*xheader,*Xheader;
- Xstatic struct field*iheader,*Iheader,*aheader,*Aheader,*Rheader,*nheader;
- X
- Xstatic void logfolder P((void)) /* estimate the no. of characters needed to */
- X{ size_t i;char num[8*sizeof totallen*4/10+1]; /* represent totallen */
- X static const char tabchar[]=TABCHAR;
- X if(logsummary)
- X { putssn(sfolder,STRLEN(sfolder));i=strlen(logsummary)+STRLEN(sfolder);
- X i-=i%TABWIDTH;
- X do putssn(tabchar,STRLEN(tabchar));
- X while((i+=TABWIDTH)<LENoffset);
- X ultstr(7,totallen,num);putssn(num,strlen(num));putcs('\n');
- X }
- X}
- X /* checks if the last field in rdheader looks like a known digest header */
- Xstatic digheadr P((void))
- X{ char*chp;int i;size_t j;struct field*fp;
- X for(fp=rdheader;fp->fld_next;fp=fp->fld_next); /* skip to the last */
- X i=maxindex(cdigest);chp=fp->fld_text;j=fp->id_len;
- X while((cdigest[i].lnr!=j||strnIcmp(cdigest[i].hedr,chp,j))&&i--);
- X return i>=0||j>STRLEN(old_)&&!strnIcmp(old_,chp,STRLEN(old_))||
- X j>STRLEN(x_)&&!strnIcmp(x_,chp,STRLEN(x_));
- X}
- X
- Xstatic artheadr P((void)) /* could it be the start of an article? */
- X{ if(!rdheader&&!strncmp(buf,Article_,STRLEN(Article_)))
- X { addbuf();rdheader->id_len=STRLEN(Article_);return 1;
- X }
- X return 0;
- X}
- X
- Xstatic PROGID;
- X
- Xmain(lastm,argv)const char*const argv[];
- X{ int i,split=0,force=0,bogus=1,every=0,areply=0,trust=0,digest=0,nowait=0,
- X keepb=0,minfields=(char*)progid-(char*)progid,conctenate=0;
- X size_t j,lnl,escaplen;char*chp,*namep,*escap=ESCAP;
- X struct field*fldp,*fp2,**afldp,*fdate;
- X if(lastm) /* sanity check, any argument at all? */
- X#define Qnext_arg() if(!*chp&&!(chp=(char*)*++argv))goto usg
- X while(chp=(char*)*++argv)
- X { if((lastm= *chp++)==FM_SKIP)
- X goto number;
- X else if(lastm!=FM_TOTAL)
- X goto usg;
- X for(;;)
- X { switch(lastm= *chp++)
- X { case FM_TRUST:trust=1;continue;
- X case FM_REPLY:areply=1;continue;
- X case FM_FORCE:force=1;continue;
- X case FM_EVERY:every=1;continue;
- X case FM_DIGEST:digest=1;continue;
- X case FM_NOWAIT:nowait=1;continue;
- X case FM_KEEPB:keepb=1;continue;
- X case FM_CONCATENATE:conctenate=1;continue;
- X case FM_QUIET:quiet=1;continue;
- X case FM_LOGSUMMARY:Qnext_arg();
- X if(strlen(logsummary=chp)>MAXfoldlen)
- X chp[MAXfoldlen]='\0';
- X detab(chp);break;
- X case FM_SPLIT:split=1;
- X if(!*chp&&*++argv)
- X goto parsedoptions;
- X goto usg;
- X case HELPOPT1:case HELPOPT2:elog(fmusage);elog(FM_HELP);
- X goto xusg;
- X case FM_MINFIELDS:Qnext_arg();chp++;
- X default:chp--;
- Xnumber: if(*chp-'0'>(unsigned)9) /* the number is not >=0 */
- X goto usg;
- X i=strtol(chp,&chp,10);
- X switch(lastm) /* where does the number go? */
- X { case FM_SKIP:nrskip=i;break;
- X case FM_MINFIELDS:minfields=i;break;
- X default:nrtotal=i;
- X }
- X continue;
- X case FM_BOGUS:bogus=0;continue;
- X case FM_QPREFIX:Qnext_arg();escap=chp;break;
- X case FM_ADD_IFNOT:case FM_ADD_ALWAYS:case FM_REN_INSERT:
- X case FM_DEL_INSERT:case FM_EXTRACT:case FM_EXTRC_KEEP:
- X case FM_ReNAME:Qnext_arg();
- X if(!breakfield(chp,lnl=strlen(chp)))
- X goto invfield;
- X chp[lnl]='\n'; /* terminate the line */
- X afldp=addfield(lastm==FM_REN_INSERT?&iheader:
- X lastm==FM_DEL_INSERT?&Iheader:lastm==FM_ADD_IFNOT?&aheader:
- X lastm==FM_ADD_ALWAYS?&Aheader:lastm==FM_EXTRACT?&xheader:
- X lastm==FM_EXTRC_KEEP?&Xheader:&Rheader,chp,++lnl);
- X if(lastm==FM_ReNAME) /* then we need a second field */
- X { int copied=0;
- X for(namep=(chp=(fldp= *afldp)->fld_text)+lnl,
- X chp+=lnl=fldp->id_len;chp<namep;++chp)
- X { switch(*chp) /* skip whitespace */
- X { case ' ':case '\t':case '\n':continue;
- X }
- X break;
- X } /* second field attached? */
- X if(i=breakfield(chp,(size_t)(namep-chp))) /* squeeze on */
- X tmemmove(fldp->fld_text+lnl,chp,i),copied=1;
- X else if(!(chp=(char*)*++argv)|| /* look at next arg */
- X !(i=breakfield(chp,strlen(chp)))) /* no field? */
- Xinvfield: { nlog("Invalid field-name:");logqnl(chp?chp:"");
- X goto usg;
- X }
- X *afldp=fldp=
- X realloc(fldp,FLD_HEADSIZ+(fldp->tot_len=lnl+i));
- X if(!copied) /* if not squeezed on yet */
- X tmemmove(fldp->fld_text+lnl,chp,i); /* squeeze now */
- X }
- X case '\0':;
- X }
- X break;
- X }
- X }
- Xparsedoptions:
- X escaplen=strlen(escap);mystdout=stdout;signal(SIGPIPE,SIG_IGN);
- X if(split)
- X { oldstdout=dup(STDOUT);fclose(stdout);startprog((const char*Const*)argv);
- X if(!minfields) /* no user specified minimum? */
- X minfields=DEFminfields; /* take our default */
- X }
- X else if(every||digest||minfields) /* these combinations are only */
- X goto usg; /* valid in combination with split */
- X if((xheader||Xheader)&&logsummary||keepb&&!(areply||xheader))
- Xusg: /* options sanity check */
- X { elog(fmusage); /* impossible mix */
- Xxusg:
- X return EX_USAGE;
- X }
- X buf=malloc(buflen=BSIZE);totallen=0;i=maxindex(rex); /* prime some buffers */
- X do rex[i].rexp=malloc(1);
- X while(i--);
- X fdate=0;addfield(&fdate,date,STRLEN(date)); /* fdate is only for searching */
- X while((buflast=getchar())=='\n'); /* skip leading garbage */
- X if(!readhead()) /* start looking */
- X {
- X#ifdef sMAILBOX_SEPARATOR /* check for a leading */
- X if(!strncmp(smboxsep,buf,STRLEN(smboxsep))) /* mailbox separator */
- X { buffilled=0;goto startover; /* skip it */
- X }
- X#endif
- X if(digest&&artheadr())
- X goto startover;
- X }
- X else
- Xstartover:
- X while(readhead()); /* read in the whole header */
- X ;{ size_t lenparkedbuf;void*parkedbuf;
- X if(rdheader&&!strncmp(rdheader->fld_text,Article_,STRLEN(Article_)))
- X rdheader->fld_text[STRLEN(Article_)-1]=HEAD_DELIMITER; /* proper */
- X namep=0;totallen=0;i=maxindex(rex); /* field */
- X do rex[i].rexl=0;
- X while(i--); /* all state has been reset */
- X for(fldp=rdheader;fldp;fldp=fldp->fld_next) /* go through the linked */
- X { int nowm; /* list of header-fields */
- X if(conctenate)
- X concatenate(fldp); /* look for `sender' fields */
- X chp=fldp->fld_text;j=fldp->id_len;i=maxindex(sest);
- X while((sest[i].len!=j||strnIcmp(sest[i].head,chp,j))&&i--);
- X if(i>=0&&(i!=maxindex(sest)||fldp==rdheader)) /* found anything? */
- X { char*saddr;char*tmp; /* determine the weight */
- X nowm=trust?sest[i].wtrepl:areply?i:sest[i].wrepl;chp+=j;
- X tmp=malloc(j=fldp->tot_len-j);tmemmove(tmp,chp,j);
- X tmp[j-1]='\0';chp=pstrspn(tmp," \t\n");
- X for(saddr=0;;chp=skipwords(chp)) /* skip RFC 822 wise */
- X { switch(*chp)
- X { default:
- X if(!saddr) /* if we haven't got anything yet */
- X saddr=chp; /* this might be the address */
- X continue;
- X case '<':skipwords(saddr=chp); /* hurray, machine useable */
- X case '\0':;
- X }
- X break;
- X }
- X if(saddr) /* any useful mailaddress found? */
- X { if(*saddr) /* did it have any length? */
- X { if(strstr(saddr,".UUCP"))
- X nowm-=(maxindex(sest)+2)*3; /* depreciate .UUCP address */
- X else if(!strpbrk(saddr,"@!/"))
- X nowm-=(maxindex(sest)+2)*2; /* depreciate "user" */
- X else if(strchr(saddr,'@')&&!strchr(saddr,'.'))
- X nowm-=maxindex(sest)+2; /* depreciate user@host */
- X if(!namep||nowm>lastm) /* better than previous ones */
- X { saddr=strcpy(malloc(strlen(saddr)+1),saddr);lastm=nowm;
- X goto newnamep;
- X }
- X }
- X else if(sest[i].head==returnpath) /* nill Return-Path: */
- X { saddr=0;lastm=maxindex(sest)+2; /* override */
- Xnewnamep: if(namep)
- X free(namep);
- X namep=saddr;
- X }
- X }
- X free(tmp);
- X } /* save headers for later perusal */
- X i=maxindex(rex);chp=fldp->fld_text;j=fldp->id_len; /* e.g. areply */
- X while((rex[i].lenr!=j||strnIcmp(rex[i].headr,chp,j))&&i--);
- X chp+=j;
- X if(i>=0&&(j=fldp->tot_len-j)>1) /* found anything? */
- X tmemmove(rex[i].rexp=realloc(rex[i].rexp,rex[i].rexl=j),chp,j);
- X }
- X tmemmove(parkedbuf=malloc(buffilled),buf,lenparkedbuf=buffilled);
- X buffilled=0; /* moved the contents of buf out of the way temporarily */
- X if(areply) /* autoreply requested, we clean up the header */
- X { for(fldp= *(afldp= &rdheader);fldp;)
- X if(!(fp2=findf(fldp,iheader))||fp2->id_len<fp2->tot_len-1)
- X *afldp=fldp->fld_next,free(fldp),fldp= *afldp; /* remove all */
- X else /* except the ones mentioned */
- X fldp= *(afldp= &fldp->fld_next); /* as -i ...: */
- X loadbuf(to,STRLEN(to));loadchar(' '); /* generate the To: field */
- X if(namep) /* did we find a valid return address at all? */
- X loadbuf(namep,strlen(namep)); /* then insert it here */
- X else
- X loadbuf(unknown,STRLEN(unknown)); /* or insert our default */
- X loadchar('\n');addbuf(); /* add it to rdheader */
- X if(subj->rexl) /* any Subject: found? */
- X { loadbuf(subject,STRLEN(subject)); /* sure, check for leading */
- X if(strnIcmp(pstrspn(chp=subj->rexp," \t"),Re,STRLEN(Re))) /* Re: */
- X loadbuf(re,STRLEN(re)); /* no Re: , add one ourselves */
- X loadsaved(subj);addbuf();
- X }
- X if(refr->rexl||msid->rexl) /* any References: or Message-ID: */
- X { loadbuf(references,STRLEN(references)); /* yes insert References: */
- X if(refr->rexl)
- X { if(msid->rexl) /* if we're going to append a Message-ID */
- X --refr->rexl; /* suppress the trailing newline */
- X loadsaved(refr);
- X }
- X if(msid->rexl)
- X loadsaved(msid); /* here's our missing newline */
- X addbuf();
- X }
- X if(msid->rexl) /* do we add an In-Reply-To: field? */
- X loadbuf(inreplyto,STRLEN(inreplyto)),loadsaved(msid),addbuf();
- X } /* are we allowed to add From_ lines? */
- X else if(!force&&(!rdheader||!eqFrom_(rdheader->fld_text))) /* missing? */
- X { struct field*old;time_t t; /* insert a From_ line up front */
- X t=time((time_t*)0);old=rdheader;rdheader=0;
- X loadbuf(From_,STRLEN(From_));
- X if(namep) /* we found a valid return address */
- X loadbuf(namep,strlen(namep));
- X else
- X loadbuf(unknown,STRLEN(unknown)); /* Date: */
- X if(!hdate->rexl||!findf(fdate,aheader))
- X loadchar(' '),chp=ctime(&t),loadbuf(chp,strlen(chp)); /* no Date: */
- X else /* we generate it ourselves */
- X loadsaved(hdate); /* yes, found Date:, then copy from it */
- X addbuf();rdheader->fld_next=old;
- X }
- X for(fldp=aheader;fldp;fldp=fldp->fld_next)
- X if(!findf(fldp,rdheader)) /* only add what didn't exist */
- X addfield(&nheader,fldp->fld_text,fldp->tot_len);
- X if((fldp= *(afldp= &rdheader))&&logsummary&&eqFrom_(fldp->fld_text))
- X concatenate(fldp),putssn(fldp->fld_text,fldp->tot_len);
- X while(fldp)
- X { lnl=fldp->id_len;chp=fldp->fld_text;
- X if(logsummary)
- X { if(lnl==STRLEN(subject)&&!strnIcmp(chp,subject,lnl))
- X { concatenate(fldp);chp[i=fldp->tot_len-1]='\0';detab(chp);
- X putcs(' ');putssn(chp,i>=MAXSUBJECTSHOW?MAXSUBJECTSHOW:i);
- X putcs('\n');
- X }
- X }
- X if(findf(fldp,Iheader)) /* delete fields */
- X { *afldp=fldp->fld_next,free(fldp);fldp= *afldp;continue;
- X }
- X else if(fp2=findf(fldp,Rheader)) /* explicitly rename field */
- X renfield(afldp,lnl,fp2->fld_text+lnl,fp2->tot_len-lnl);
- X else if((fp2=findf(fldp,iheader))&&!(areply&&lnl==fp2->tot_len-1))
- X renfield(afldp,(size_t)0,old_,STRLEN(old_)); /* implicitly rename */
- X fldp= *(afldp= &(*afldp)->fld_next);
- X } /* restore the saved contents of buf */
- X tmemmove(buf,parkedbuf,buffilled=lenparkedbuf);free(parkedbuf);
- X }
- X flushfield(&rdheader);flushfield(&nheader);dispfield(Aheader);
- X dispfield(iheader);dispfield(Iheader);
- X if(namep)
- X free(namep);
- X if(!(xheader||Xheader)) /* we're not just extracting fields */
- X lputcs('\n'); /* make sure it is followed by an empty line */
- X if(!keepb&&(areply||xheader||Xheader)) /* decision time */
- X { logfolder(); /* we throw away the rest */
- X if(split)
- X closemine();
- X opensink(); /* discard the body */
- X }
- X lnl=1; /* last line was a newline */
- X if(buffilled==1) /* the header really ended with a newline */
- X buffilled=0; /* throw it away, since we already inserted it */
- X while(buffilled||!lnl||buflast!=EOF) /* continue the quest, line by line */
- X { if(!buffilled) /* is it really empty? */
- X readhead(); /* read the next field */
- X if(rdheader) /* anything looking like a header found? */
- X { if(eqFrom_(chp=rdheader->fld_text)) /* check if it's From_ */
- Xfromanyway:
- X { register size_t k;
- X if(split&&(lnl||every)&& /* more thorough check for a postmark */
- X (k=strcspn(chp=pstrspn(chp+STRLEN(From_)," \t")," \t\n"))&&
- X *pstrspn(chp+k," \t")!='\n')
- X goto accuhdr; /* ok, postmark found, split it */
- X if(bogus) /* disarm */
- X lputssn(escap,escaplen);
- X }
- X else if(split&&digest&&(lnl||every)&&digheadr()) /* digest? */
- Xaccuhdr: { for(i=minfields;--i&&readhead()&&digheadr();); /* found enough? */
- X if(!i) /* then split it! */
- Xsplitit: { if(!lnl) /* did the previous mail end with an empty line? */
- X lputcs('\n'); /* but now it does :-) */
- X logfolder();
- X if((fclose(mystdout)==EOF||errout==EOF)&&!quiet)
- X nlog(couldntw),elog(", continuing...\n"),split= -1;
- X if(!nowait)
- X waitforit(); /* wait till the child has finished */
- X startprog((const char*Const*)argv);goto startover;
- X } /* and there we go again */
- X }
- X }
- X else if(eqFrom_(buf)) /* special case, From_ line */
- X { addbuf();goto fromanyway; /* add it manually, readhead() didn't */
- X }
- X else if(split&&digest&&(lnl||every)&&artheadr())
- X goto accuhdr;
- X#ifdef MAILBOX_SEPARATOR
- X if(!strncmp(emboxsep,buf,STRLEN(emboxsep))) /* end of mail? */
- X { if(split) /* gobble up the next start separator */
- X { buffilled=0;
- X#ifdef sMAILBOX_SEPARATOR
- X getline();buffilled=0; /* but only if it's defined */
- X#endif
- X if(buflast!=EOF) /* if any */
- X goto splitit;
- X break;
- X }
- X else if(bogus)
- X goto putsp; /* escape it with a space */
- X }
- X else if(!strncmp(smboxsep,buf,STRLEN(smboxsep)&&bogus))
- Xputsp: lputcs(' ');
- X#endif /* MAILBOX_SEPARATOR */
- X lnl=buffilled==1; /* check if we just read an empty line */
- X if(areply&&bogus) /* escape the body */
- X if(fldp=rdheader) /* we already read some "valid" fields */
- X { register char*p;
- X rdheader=0;
- X do /* careful, they can contain newlines */
- X { fp2=fldp->fld_next;chp=fldp->fld_text;
- X do
- X { lputssn(escap,escaplen);
- X lputssn(chp,(p=strchr(chp,'\n')+1)-chp);
- X }
- X while((chp=p)<fldp->fld_text+fldp->tot_len);
- X free(fldp); /* delete it */
- X }
- X while(fldp=fp2); /* escape all fields we found */
- X }
- X else
- X { if(buffilled>1) /* we don't escape empty lines, looks neat */
- X lputssn(escap,escaplen);
- X goto flbuf;
- X }
- X else if(rdheader)
- X flushfield(&rdheader); /* beware, after this buf can still be filled */
- X else
- Xflbuf: lputssn(buf,buffilled),buffilled=0;
- X } /* make sure the mail ends with an empty line */
- X logfolder();closemine();child= -1;waitforit(); /* wait for everyone */
- X return split<0?EX_IOERR:EX_OK;
- X}
- X
- XeqFrom_(a)const char*const a;
- X{ return!strncmp(a,From_,STRLEN(From_));
- X}
- X
- Xbreakfield(line,len)const char*const line;size_t len; /* look where the */
- X{ const char*p=line; /* fieldname ends (RFC 822 specs) */
- X if(eqFrom_(line)) /* special case, From_ */
- X return STRLEN(From_);
- X while(len--&&!iscntrl(*p)) /* no control characters allowed */
- X { switch(*p++)
- X { default:continue;
- X case HEAD_DELIMITER:len=p-line;return len==1?0:len; /* eureka! */
- X case ' ':; /* no spaces allowed */
- X }
- X break;
- X }
- X return 0; /* sorry, does not seem to be a legitimate field */
- X}
- END_OF_FILE
- if test 18606 -ne `wc -c <'procmail/src/formail.c'`; then
- echo shar: \"'procmail/src/formail.c'\" unpacked with wrong size!
- fi
- # end of 'procmail/src/formail.c'
- fi
- if test -f 'procmail/src/multigram.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'procmail/src/multigram.c'\"
- else
- echo shar: Extracting \"'procmail/src/multigram.c'\" \(18039 characters\)
- sed "s/^X//" >'procmail/src/multigram.c' <<'END_OF_FILE'
- X/************************************************************************
- X * multigram - The human mail address reader *
- X * *
- X * It uses multigrams to intelligently filter out mail addresses *
- X * from the garbage in any arbitrary mail. *
- X * Multigram is currently unable to pick out addresses that *
- X * contain embedded whitespace. *
- X * This program also contains some swiss-army-knife mailinglist *
- X * support features. *
- X * *
- X * Most notably: flist A program that should be setuid root. *
- X * *
- X * Seems to be relatively bug free. *
- X * *
- X * Copyright (c) 1990-1992, S.R. van den Berg, The Netherlands *
- X * #include "README" *
- X ************************************************************************/
- X#ifdef RCS
- Xstatic /*const*/char rcsid[]=
- X "$Id: multigram.c,v 1.30 1993/06/07 12:37:18 berg Exp $";
- X#endif
- Xstatic /*const*/char rcsdate[]="$Date: 1993/06/07 12:37:18 $";
- X#include "includes.h"
- X#include "sublib.h"
- X#include "shell.h"
- X#include "ecommon.h"
- X
- X#include "targetdir.h" /* see ../mailinglist/install.sh2 for more details */
- X
- X#define BUFSTEP 16
- X#define COPYBUF 16384
- X/*#define SPEEDBUF COPYBUF /* uncomment to get a speed increase? */
- X#define SCALE_WEIGHT 0x7fff
- X#define EXCL_THRESHOLD 30730
- X
- X#define DEFmaxgram 4
- X#define DEFminweight (SCALE_WEIGHT/4) /* sanity cutoff value */
- X#define DEFbest_matches 2
- X
- X#define DEFAULTS_DIR ".etc" /* some configurable paths */
- X#define GLOCKFILE "../.etc/rc.lock"
- X#define RCMAIN "./.etc/rc.main"
- X#define LLOCKFILE "rc.lock"
- X#define REQUEST "-request"
- X#define RCSUBMIT "./rc.submit"
- X#define RCREQUEST "./rc.request"
- X#define RCPOST "./../.etc/rc.post"
- X#define RCINIT "RC_INIT=rc.init"
- X#define XENVELOPETO "X_ENVELOPE_TO="
- X#define LIST "list="
- X
- X#define metoo_SENDMAIL "-om"
- X#define nometoo_SENDMAIL "-omF"
- X#define REMOV1_DELIM "(Only"
- X#define REMOV2_DELIM "addresses below this line can be automatically removed)"
- X#define NOT_METOO "(-n)"
- X
- Xstruct string{char*text,*itext;size_t textlen,buflen;};
- X
- Xstatic remov_delim,maxgram;
- X
- XstrnIcmp(a,b,l)const char*a,*b;size_t l; /* stub */
- X{ return strncmp(a,b,l);
- X}
- X /* read a string from a file into a struct string buffer */
- Xstatic size_t readstr(file,p,linewise)FILE*const file;struct string*p;
- X const int linewise;
- X{ size_t len;int i,firstspc;
- X static const char rem1str[]=REMOV1_DELIM,rem2str[]=REMOV2_DELIM;
- X for(len=firstspc=0;;)
- X { switch(i=getc(file))
- X { case ' ':case '\t':case '\n':
- X if(!len) /* only skip leading space */
- X continue;
- X if(!linewise) /* do we need a complete line? */
- X break; /* no, a word will do */
- X if(!firstspc) /* already seen spaces? */
- X { if(i=='\n') /* no, so check for EOL */
- X { p->text[len]='\0'; /* terminate the first word, split */
- X if(++len==p->buflen) /* still buffer space left? */
- X p->text=realloc(p->text,p->buflen+=BUFSTEP);
- X break;
- X }
- X i='\0';firstspc=1;
- X } /* not the first word on the line, continue */
- X if(i=='\n')
- X break;
- X default:p->text[len]=i; /* regular character, store it */
- X if(++len==p->buflen) /* watch our buffer space */
- X p->text=realloc(p->text,p->buflen+=BUFSTEP);
- X continue; /* next character */
- X case EOF:;
- X }
- X p->text[len]='\0'; /* terminate the buffer in any case */
- X if(linewise&&!remov_delim&&!strcmp(p->text,rem1str)&&
- X !strcmp(p->text+sizeof rem1str,rem2str)) /* special delimiter? */
- X remov_delim=1;
- X return len;
- X }
- X}
- X
- Xstatic char*tstrdup(p)const char*const p;
- X{ return strcpy(malloc(strlen(p)+1),p);
- X}
- X
- Xstatic void lowcase(str)struct string*const str; /* make lowercase */
- X{ register char*p;
- X for(p=str->itext=tstrdup(str->text);*p;p++)
- X if((unsigned)*p-'A'<'Z'-'A')
- X *p+='a'-'A';
- X}
- X
- Xstatic void elog(a)const char*const a;
- X{ fputs(a,stderr);
- X}
- X /* the program names */
- Xstatic const char idhash[]="idhash",flist[]="flist",senddigest[]="senddigest",
- X dirsep[]=DIRSEP;
- Xstatic const char*progname="multigram";
- X
- Xvoid nlog(a)const char*const a; /* log error with identification */
- X{ elog(progname);elog(": ");elog(a);
- X}
- X /* finds the next character */
- Xstatic char*lastdirsep(filename)const char*filename;
- X{ const char*p; /* following the last DIRSEP */
- X while(p=strpbrk(filename,dirsep))
- X filename=p+1;
- X return(char*)filename;
- X}
- X /* check rc.lock file age */
- Xstatic rclock(file,stbuf)const char*const file;struct stat*const stbuf;
- X{ int waited=0;
- X while(!stat(file,stbuf)&&time((time_t*)0)-stbuf->st_mtime<DEFlocktimeout)
- X waited=1,sleep(DEFlocksleep); /* wait, if appropriate */
- X return waited;
- X}
- X
- Xstatic char*argstr(first,last)const char*first,*last; /* construct */
- X{ char*chp;size_t i; /* an argument assignment */
- X strcpy(chp=malloc((i=strlen(first))+strlen(last)+1),first);
- X strcpy(chp+i,last);return chp;
- X}
- X
- Xstatic PROGID;
- X
- Xstatic matchgram(fuzzstr,hardstr)
- Xconst struct string*const fuzzstr;struct string*const hardstr;
- X{ size_t minlen,maxlen;unsigned maxweight;int meter;
- X register size_t gramsize;
- X if((minlen=hardstr->textlen=strlen(hardstr->text))>(maxlen=fuzzstr->textlen))
- X minlen=fuzzstr->textlen,maxlen=hardstr->textlen;
- X if((gramsize=minlen-1)>maxgram)
- X gramsize=maxgram;
- X maxweight=SCALE_WEIGHT/(gramsize+1);
- X meter=(int)((unsigned long)SCALE_WEIGHT/2*minlen/maxlen)-SCALE_WEIGHT/2;
- X do /* reset local multigram counter */
- X { register lmeter=0;size_t cmaxlen=maxlen;
- X ;{ register const char*fzz,*hrd;
- X fzz=fuzzstr->itext;
- X do
- X { for(hrd=fzz+1;hrd=strchr(hrd,*fzz);) /* is it present in */
- X if(!strncmp(++hrd,fzz+1,gramsize)) /* own string? */
- X { if(cmaxlen>gramsize+1)
- X cmaxlen--;
- X goto dble_gram; /* skip until it's last */
- X }
- X for(hrd=hardstr->itext;hrd=strchr(hrd,*fzz);) /* otherwise */
- X if(!strncmp(++hrd,fzz+1,gramsize)) /* search it in the */
- X { lmeter++;break; /* dist entry */
- X }
- Xdble_gram:;
- X }
- X while(*(++fzz+gramsize)); /* next gram */
- X }
- X if(lmeter)
- X { unsigned weight;
- X if(cmaxlen>minlen)
- X cmaxlen=minlen;
- X meter+=lmeter*(weight=maxweight/(unsigned)(cmaxlen-gramsize));
- X meter-=weight*
- X (unsigned long)((lmeter+=gramsize-cmaxlen)<0?-lmeter:lmeter)/cmaxlen;
- X }
- X }
- X while(gramsize--); /* search all gramsizes down to one */
- X return meter;
- X}
- X
- Xmain(minweight,argv)char*argv[];
- X{ struct string fuzzstr,hardstr,excstr,exc2str;FILE*hardfile;
- X const char*addit=0;
- X struct match{char*fuzz,*hard;int metric;long lentry;off_t offs1,offs2;}
- X **best,*curmatch=0;
- X unsigned best_matches,charoffs=0,remov=0,renam=0,
- X chkmetoo=(char*)progid-(char*)progid;
- X int lastfrom;
- X static const char usage[]=
- X"Usage: multigram [-cdmr] [-b nnn] [-l nnn] [-w nnn] [-ax address] filename\n";
- X if(minweight) /* sanity check, any arguments at all? */
- X { char*chp;
- X if(!strcmp(chp=lastdirsep(argv[0]),flist)) /* suid flist prog? */
- X { struct stat stbuf;char*arg;
- X static const char request[]=REQUEST,listid[]=LISTID,
- X rcrequest[]=RCREQUEST,rcpost[]=RCPOST,list[]=LIST,
- X defdir[]=DEFAULTS_DIR,targetdir[]=TARGETDIR,
- X *pmexec[]={PROCMAIL,RCSUBMIT,RCINIT,0,0,0,rcrequest,rcpost,0};
- X#define Endpmexec(i) (pmexec[maxindex(pmexec)-(i)])
- X progname=flist;*chp='\0';
- X if(chdir(targetdir))
- X { nlog("Couldn't chdir to \"");elog(targetdir);elog("\"\n");
- X return EX_NOPERM;
- X }
- X if(stat(defdir,&stbuf))
- X { nlog("Can't find \"");elog(defdir);elog("\" in \"");
- X elog(targetdir);elog("\"\n");return EX_NOINPUT;
- X }
- X if(minweight!=2) /* wrong number of arguments? */
- X { elog("Usage: flist listname[-request]\n");return EX_USAGE;
- X }
- X chp=strchr(arg=argv[1],'\0'); /* check for -request */
- X if(chp-arg>STRLEN(request)&&!strcmp(chp-=STRLEN(request),request))
- X *chp='\0',pmexec[1]=rcrequest,Endpmexec(1)=0,Endpmexec(2)=rcpost;
- X else
- X chp=0;
- X if(!strcmp(arg,chPARDIR)||strpbrk(arg,dirsep))
- X { nlog("Bogus listname\n");return EX_NOPERM;
- X }
- X if(geteuid()==ROOT_uid) /* continue as the list maintainer */
- X { struct passwd*pass;
- X if(!(pass=getpwnam(listid)))
- X { nlog("User \");elog(listid);elog(\" unknown\n");
- X return EX_NOUSER;
- X }
- X setgid(pass->pw_gid);initgroups(listid,pass->pw_gid);
- X setuid(pass->pw_uid);endpwent();
- X }
- X else
- X setgid(stbuf.st_gid),setuid(stbuf.st_uid);
- X if(chdir(arg)) /* goto the list's subdirectory */
- X pmexec[1]=RCMAIN,Endpmexec(2)=0,chdir(defdir);
- X Endpmexec(5)=INIT_PATH;
- X Endpmexec(4)=argstr(list,arg); /* pass on the list name */
- X if(chp) /* was it a -request list? */
- X *chp= *request; /* then restore the leading '-' */
- X Endpmexec(3)=argstr(XENVELOPETO,arg);
- X while(rclock(GLOCKFILE,&stbuf)||rclock(LLOCKFILE,&stbuf)); /* stall */
- X execve(pmexec[0],(char*const*)pmexec,environ);nlog("Couldn't exec \"");
- X elog(pmexec[0]);elog("\"\n");return EX_UNAVAILABLE; /* panic */
- X }
- X setgid(getgid());setuid(getuid()); /* revoke suid permissions */
- X if(!strcmp(chp,idhash)) /* idhash program? */
- X { unsigned long hash=0;int i;
- X progname=idhash;
- X if(minweight!=1)
- X { elog("Usage: idhash\n");return EX_USAGE;
- X }
- X while(i=fgetc(stdin),!feof(stdin)) /* hash away! */
- X hash=hash*67067L+i;
- X printf("%lx",hash);return EX_OK;
- X }
- X if(!strcmp(chp,senddigest)) /* senddigest program? */
- X { struct stat stbuf;
- X progname=senddigest;
- X if(minweight<5)
- X { elog(
- X "Usage: senddigest maxage maxsize bodyfile trailerfile [file] ...\n");
- X return EX_USAGE;
- X }
- X if(!stat(argv[3],&stbuf))
- X { time_t newt;off_t size;
- X newt=stbuf.st_mtime;size=stbuf.st_size;
- X if(!stat(argv[minweight=4],&stbuf))
- X { off_t maxsize;
- X if(stbuf.st_mtime+strtol(argv[1],(char**)0,10)<newt)
- X return EX_OK; /* digest too old */
- X maxsize=strtol(argv[2],(char**)0,10);goto statd;
- X do
- X { if(!stat(argv[minweight],&stbuf))
- Xstatd: if((size+=stbuf.st_size)>maxsize) /* digest too big? */
- X return EX_OK;
- X }
- X while(argv[++minweight]);
- X }
- X }
- X return 1;
- X }
- X minweight=SCALE_WEIGHT;best_matches=maxgram=0;exc2str.text=excstr.text=0;
- X while((chp= *++argv)&&*chp=='-')
- X for(chp++;;)
- X { int c;
- X switch(c= *chp++)
- X { case 'c':charoffs=1;continue;
- X case 'd':remov=1;continue;
- X case 'r':renam=1;continue;
- X case 'm':chkmetoo=1;continue;
- X case 'a':
- X if(!*chp&&!(chp= *++argv))
- X goto usg;
- X addit=chp;break;
- X case 'x':
- X if(!*chp&&!(chp= *++argv))
- X goto usg;
- X if(excstr.text)
- X exc2str.text=chp;
- X else
- X excstr.text=chp;
- X break;
- X case 'b':case 'l':case 'w':
- X { int i;
- X ;{ const char*ochp;
- X if(!*chp&&!(chp= *++argv)||
- X (i=strtol(ochp=chp,(char**)&chp,10),chp==ochp))
- X goto usg;
- X }
- X switch(c)
- X { case 'b':best_matches=i;continue;
- X case 'l':minweight=i;continue;
- X case 'w':maxgram=i;continue;
- X }
- X }
- X case HELPOPT1:case HELPOPT2:elog(usage);
- X elog(
- X "\t-a address\tadd this address to the list\
- X\n\t-b nnn\t\tmaximum no. of best matches shown\
- X\n\t-c\t\tdisplay offsets in characters\
- X\n\t-d\t\tdelete address from list\
- X\n\t-m\t\tcheck for metoo\
- X\n\t-l nnn\t\tlower bound metric\
- X\n\t-r\t\trename address on list\
- X\n\t-x address\texclude this address from the search (max. 2)\
- X\n\t-w nnn\t\twindow width used when matching\n");return EX_USAGE;
- X case '-':
- X if(!*chp)
- X { chp= *++argv;goto lastopt;
- X }
- X default:goto usg;
- X case '\0':;
- X }
- X break;
- X }
- Xlastopt:
- X if(!chp||*++argv||renam+remov+!!addit>1)
- X goto usg;
- X if(excstr.text)
- X { excstr.textlen=strlen(excstr.text);lowcase(&excstr);
- X if(exc2str.text)
- X exc2str.textlen=strlen(exc2str.text),lowcase(&exc2str);
- X }
- X if(!(hardfile=fopen(chp,remov||renam||addit?"r+":"r")))
- X { nlog("Couldn't open \"");elog(chp);elog("\"\n");return EX_IOERR;
- X }
- X#ifdef SPEEDBUF /* allocate a bigger stdio buffer */
- X setvbuf(hardfile,malloc(SPEEDBUF),_IOFBF,(size_t)SPEEDBUF);
- X#endif
- X }
- X else
- Xusg:
- X { elog(usage);return EX_USAGE;
- X }
- X if(addit) /* special subfunction, to add entries */
- X { int lnl;off_t lasttell; /* to the dist file */
- X for(lnl=1,lasttell=0;;)
- X { switch(getc(hardfile)) /* step through the file */
- X { case '\n':
- X if(!lnl) /* looking for trailing newlines */
- X lnl=1,lasttell=ftell(hardfile);
- X continue;
- X default:lnl=0;continue;
- X case EOF:; /* or the end of the file */
- X }
- X break;
- X } /* go back there, and add the new entry */
- X fseek(hardfile,lasttell,SEEK_SET);fprintf(hardfile,"%s\n",addit);
- X printf("Added: %s\n",addit);fclose(hardfile);return EX_OK;
- X }
- X if(!maxgram)
- X maxgram=DEFmaxgram;
- X maxgram--;
- X if(minweight==SCALE_WEIGHT)
- X minweight=DEFminweight;
- X if(!best_matches)
- X best_matches=DEFbest_matches;
- X fuzzstr.text=malloc(fuzzstr.buflen=BUFSTEP);
- X hardstr.text=malloc(hardstr.buflen=BUFSTEP);
- X ;{ int i;
- X best=malloc(best_matches--*sizeof*best);i=best_matches;
- X do
- X { best[i]=malloc(sizeof**best);best[i]->hard=malloc(1);
- X best[i]->fuzz=malloc(1);best[i]->metric= -SCALE_WEIGHT;
- X }
- X while(i--);
- X }
- X for(lastfrom= -1;readstr(stdin,&fuzzstr,0);)
- X { int meter,maxmetric;long linentry;off_t offs1,offs2;
- X ;{ char*chp,*echp;int parens;
- X echp=strchr(chp=fuzzstr.text,'\0')-1;
- X do
- X { switch(*echp)
- X { case '.':case ',':case ';':case ':':case '?':case '!':*echp='\0';
- X continue;
- X }
- X break;
- X }
- X while(--echp>chp); /* roughly check if it could be a mail address */
- X if(lastfrom<=0&&!strpbrk(chp,"@/")&&(!strchr(chp,'!')||
- X strchr(chp,'|')||strchr(chp,',')||strstr(chp,"..")))
- X { if(lastfrom<0)
- X lastfrom=!strcmp(SHFROM,chp);
- X continue; /* apparently not an email address */
- X }
- X lastfrom=0;
- X for(parens=0;chp=strchr(chp,'(');chp++,parens++);
- X for(chp=fuzzstr.text;chp=strchr(chp,')');chp++,parens--);
- X if(*(chp=fuzzstr.text)=='(')
- X { if(!parens&&*echp==')')
- X { *echp='\0';goto shftleft;
- X }
- X if(parens>0)
- Xshftleft: tmemmove(chp,chp+1,strlen(chp));
- X }
- X else if(parens<0&&*echp==')')
- X *echp='\0';
- X if(*(chp=fuzzstr.text)=='<'&&*(echp=strchr(chp,'\0')-1)=='>'
- X &&!strchr(chp,',')) /* strip '<' and '>' ? */
- X *echp='\0',tmemmove(chp,chp+1,echp-chp);
- X if(!(fuzzstr.textlen=strlen(chp)))
- X continue;
- X lowcase(&fuzzstr);
- X if(excstr.text&&matchgram(&fuzzstr,&excstr)>=EXCL_THRESHOLD||
- X exc2str.text&&matchgram(&fuzzstr,&exc2str)>=EXCL_THRESHOLD)
- X { free(fuzzstr.itext);continue;
- X }
- X ;{ int i=0;
- X do
- X { if(best[i]->metric==-SCALE_WEIGHT&&!strcmp(best[i]->fuzz,chp))
- X break;
- X if(!strcmp(best[i]->fuzz,chp)) /* already matched this one? */
- X goto dupl_addr;
- X }
- X while(++i<=best_matches);
- X }
- X if(!curmatch)
- X curmatch=malloc(sizeof*curmatch);
- X curmatch->fuzz=tstrdup(chp);curmatch->hard=malloc(1);
- X curmatch->metric= -SCALE_WEIGHT;
- X }
- X fseek(hardfile,(off_t)0,SEEK_SET);maxmetric=best[best_matches]->metric;
- X for(remov_delim=offs2=linentry=0;
- X offs1=offs2,readstr(hardfile,&hardstr,1);)
- X { offs2=ftell(hardfile);linentry++;
- X if(*hardstr.text=='(')
- X continue; /* unsuitable for matches */
- X lowcase(&hardstr);meter=matchgram(&fuzzstr,&hardstr);
- X free(hardstr.itext); /* check if we had any luck */
- X if(meter>maxmetric&&(remov_delim||!renam&&!remov))
- X { size_t hardlen;
- X curmatch->metric=maxmetric=meter;curmatch->lentry=linentry;
- X free(curmatch->hard);hardlen=hardstr.textlen+1;
- X hardlen+=strlen(hardstr.text+hardlen)+1;
- X curmatch->hard=malloc(hardlen+=strlen(hardstr.text+hardlen)+1);
- X tmemmove(curmatch->hard,hardstr.text,hardlen);
- X curmatch->offs1=offs1;curmatch->offs2=offs2;
- X }
- X }
- X free(fuzzstr.itext); /* maybe this match can be put in the array */
- X if(curmatch->metric>-SCALE_WEIGHT) /* of best matches so far */
- X { struct match*mp,**mmp;
- X free((mp= *(mmp=best+best_matches))->fuzz);free(mp->hard);free(mp);
- X while(--mmp>=best&&(mp= *mmp)->metric<curmatch->metric)
- X mmp[1]=mp; /* keep it sorted */
- X mmp[1]=curmatch;curmatch=0;
- X }
- X else
- X free(curmatch->fuzz),free(curmatch->hard);
- Xdupl_addr:;
- X }
- X ;{ int i;struct match*mp;
- X for(i=0;i<=best_matches&&(mp=best[i++])->metric>=minweight;)
- X if(chkmetoo)
- X printf("%s\n",strcmp(mp->hard+strlen(mp->hard)+1,NOT_METOO)
- X ?metoo_SENDMAIL:nometoo_SENDMAIL);
- X else
- X printf("%3ld %-34s %5d %-34s\n",
- X charoffs?mp->offs1:mp->lentry,mp->hard,mp->metric,mp->fuzz);
- X if((mp= *best)->metric>=minweight)
- X { struct match*worse;
- X if(renam)
- X { long line;int i,w1;unsigned maxweight;
- X maxweight=SCALE_WEIGHT/(maxgram+1)>>1;;
- X for(i=1,line=mp->lentry,w1=mp->metric,worse=0;
- X i<=best_matches&&(mp=best[i++])->metric>=minweight;)
- X if(mp->lentry==line&&mp->metric+maxweight<w1)
- X { goto remv1;
- X }
- X for(i=1;i<=best_matches&&(mp=best[i++])->metric>=minweight;)
- X if(mp->metric+maxweight<w1)
- Xremv1: { worse=mp;mp= *best;goto remv;
- X }
- X nlog("Couldn't find a proper address pair\n");goto norenam;
- X }
- X if(remov)
- Xremv: { char*buf;off_t offs1,offs2;size_t readin;
- X buf=malloc(COPYBUF);offs1=mp->offs1;offs2=mp->offs2;
- X while(fseek(hardfile,offs2,SEEK_SET),
- X readin=fread(buf,1,COPYBUF,hardfile))
- X { offs2=ftell(hardfile);fseek(hardfile,offs1,SEEK_SET);
- X if(buf[readin-1]=='\n') /* try and remove some empty lines */
- X while(readin>1&&buf[readin-2]=='\n') /* at the end, since */
- X readin--; /* every time could be the last */
- X fwrite(buf,1,readin,hardfile);offs1=ftell(hardfile);
- X }
- X free(buf);fseek(hardfile,offs1,SEEK_SET);
- X printf("Removed: %s\n",mp->hard);
- X if(renam)
- X fputs(worse->fuzz,hardfile),printf("Added: %s\n",worse->fuzz);
- X do putc('\n',hardfile); /* erase the tail */
- X while(ftell(hardfile)<offs2);
- X fclose(hardfile);
- X }
- X return EX_OK;
- X }
- X }
- X if(remov||renam)
- X { nlog("Couldn't even find a single address\n");
- X }
- Xnorenam:
- X return 1;
- X}
- END_OF_FILE
- if test 18039 -ne `wc -c <'procmail/src/multigram.c'`; then
- echo shar: \"'procmail/src/multigram.c'\" unpacked with wrong size!
- fi
- # end of 'procmail/src/multigram.c'
- fi
- echo shar: End of archive 9 \(of 11\).
- cp /dev/null ark9isdone
- MISSING=""
- for I in 1 2 3 4 5 6 7 8 9 10 11 ; do
- if test ! -f ark${I}isdone ; then
- MISSING="${MISSING} ${I}"
- fi
- done
- if test "${MISSING}" = "" ; then
- echo You have unpacked all 11 archives.
- rm -f ark[1-9]isdone ark[1-9][0-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
-
- "Always look on the bright side of life!"
-
- exit 0 # Just in case...
-