home *** CD-ROM | disk | FTP | other *** search
Text File | 1991-11-03 | 54.1 KB | 1,681 lines |
- Newsgroups: comp.sources.misc
- From: berg@messua.informatik.rwth-aachen.de (Stephen R. van den Berg)
- Subject: v25i002: procmail - mail processing program v2.31, Part02/04
- Message-ID: <1991Nov3.230004.9816@sparky.imd.sterling.com>
- X-Md4-Signature: 7bdbc968ca0a90061d1344ebc28bccb8
- Date: Sun, 3 Nov 1991 23:00:04 GMT
- Approved: kent@sparky.imd.sterling.com
-
- Submitted-by: berg@messua.informatik.rwth-aachen.de (Stephen R. van den Berg)
- Posting-number: Volume 25, Issue 2
- Archive-name: procmail/part02
- Environment: UNIX, sendmail, smail, MMDF
- Supersedes: procmail2.10: Volume 20, Issue 89-91
-
- #! /bin/sh
- # This is a shell archive. Remove anything before this line, then feed it
- # into a shell via "sh file" or similar. To overwrite existing files,
- # type "sh file -c".
- # The tool that generated this appeared in the comp.sources.unix newsgroup;
- # send mail to comp-sources-unix@uunet.uu.net if you want that tool.
- # Contents: procmail/README procmail/examples/mailinglist
- # procmail/formail.c procmail/regexp.c procmail/retint.c
- # Wrapped by kent@sparky on Sun Nov 3 16:50:05 1991
- PATH=/bin:/usr/bin:/usr/ucb ; export PATH
- echo If this archive is complete, you will see the following message:
- echo ' "shar: End of archive 2 (of 4)."'
- if test -f 'procmail/README' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'procmail/README'\"
- else
- echo shar: Extracting \"'procmail/README'\" \(3992 characters\)
- sed "s/^X//" >'procmail/README' <<'END_OF_FILE'
- XProcmail & formail mail processing package.
- XCopyright (c) 1990-1991, S.R.van den Berg, The Netherlands.
- X
- XSome legal stuff:
- X
- XUse this software package at your own risk. The programmer can not
- Xbe held liable for any incurred damages, directly or indirectly due to
- Xthe use of this software.
- X
- XYou are encouraged to distribute this package freely. This package is
- Xhowever not to be sold (minor transfer costs excepted) or included in
- Xany commercially sold software package (if you want to do this anyway,
- Xcontact me (address below), and we'll work something out).
- X
- XIf you distribute it, please leave the package intact. You are allowed to
- Xtake parts from this distribution and distribute these separately as long
- Xas you retain the copyright messages. If you redistribute any part of this
- Xpackage in a modified form, be sure to mark the parts you changed.
- XIf you have some important changes that might be usefull to the rest of the
- Xworld, contact me instead.
- X
- X-------------------------- SYSTEM REQUIREMENTS -------------------------------
- X
- XAny *NIX-alike system.
- X
- XSendmail, smail, MMDF or compatible mailers.
- X
- XThe most important system calls that need to be supported (among others):
- Xdup(),wait(),getpwent(),fork(),pipe()
- X
- XFor a more complete list of all library references see "includes.h"
- X
- X------------------------------ DESCRIPTION -----------------------------------
- X
- XThe procmail mail processing program. (v2.31 1991/10/22)
- X
- XCan be used to create mail-servers, mailing lists, sort your incoming mail
- Xinto separate folders/files (real convenient when subscribing to one or more
- Xmailing lists), preprocess your mail, or selectively forward certain incoming
- Xmail automatically to someone.
- X
- XThe accompanying formail program enables you to generate autoreplies, split up
- Xdigests/mailboxes into the original messages, do some very simple
- Xheader-munging, or force mail into mail-format (with leading From line).
- X
- XFor installation instructions see the INSTALL file.
- X
- X----------------------
- X
- XI made the utmost effort to make procmail as robust as any program can be
- X(every conceivable system error is caught *and* handled).
- X
- XProcmail was designed to deliver the mail under the worst conditions
- X(file system full, out of swap space, process table full, file table full,
- Xmissing support files, unavailable executables; it all doesn't matter).
- XShould (in the unlikely event) procmail be unable to deliver your mail
- Xsomewhere, the mail will bounce back to the sender or reenter the mailqueue
- X(your choice).
- X
- XFor a more extensive list of features see the FEATURES file.
- X
- X----------------------
- X
- XHowever, as with any program, bugs can not be completely ruled out.
- XI tested the program extensively, and believe it should be relatively
- Xbug free (no known bug at the time). Should, however, anyone find any
- Xbugs (highly unlikely :-), I would be pleased (well, sort of :-) to hear
- Xabout it. Please send me the patches or bug report.
- XI'll look at them and will try to fix it in a future release.
- X(BTW, if you should find any spelling or grammar errors in these files,
- Xit's not priority one, but if you were sending me mail anyway, don't hesitate
- Xto point them out to me; I like correct English just as much as you do).
- X
- XPlease note that this program essentially is supposed to be static, that
- Xmeans no extra features (honouring the VNIX spirit) are supposed to be
- Xadded (though any usefull suggestions will be appreciated and evaluated if
- Xtime permits).
- X
- XCheers,
- X Stephen R. van den Berg at RWTH-Aachen, Germany.
- X
- XInternet E-mail: berg@messua.informatik.rwth-aachen.de
- X berg@physik.tu-muenchen.de
- X
- XOr: P.O.Box 21074
- X 6369 ZG Simpelveld
- X The Netherlands
- X
- X----------------------
- XA recent version can be picked up at various comp.sources.misc archives.
- XThe latest version can be obtained directly from the ftp-archive at:
- X
- X amaru.informatik.rwth-aachen.de (137.226.112.31)
- X
- X as compressed tar file: pub/unix/procmail.tar.Z
- X or in compressed shar format: pub/unix/procmail.0?.Z
- X----------------------
- END_OF_FILE
- if test 3992 -ne `wc -c <'procmail/README'`; then
- echo shar: \"'procmail/README'\" unpacked with wrong size!
- fi
- # end of 'procmail/README'
- 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'\" \(11152 characters\)
- sed "s/^X//" >'procmail/examples/mailinglist' <<'END_OF_FILE'
- X$Id: mailinglist,v 2.3 1991/10/18 15:39:20 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 can not exceed 1000 bytes (on most sendmails).
- Xb. The subscriber list can not be changed on-the-fly (/usr/lib/aliases needs
- X to be edited, and newaliases has to be run).
- Xc. People can not be prevented from submitting messages like "Please remove
- X me from this mailinglist" to mylist (and thereby annoying all subscribers).
- Xd. People can not 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 can not 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: :input:/path/to/the/memberfile
- X The memberfile should contain:
- X fred,john,wilma,barney@bedrock,pebbles
- X You can not avoid using newaliases however, and *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 strongly would recommend
- Xagainst this approach however, since this will be too much of a customizing
- 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
- 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 you 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 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 11152 -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/formail.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'procmail/formail.c'\"
- else
- echo shar: Extracting \"'procmail/formail.c'\" \(12561 characters\)
- sed "s/^X//" >'procmail/formail.c' <<'END_OF_FILE'
- X/************************************************************************
- X * formail.c a mail (re)formatter *
- X * *
- X * Seems to be relatively bug free. *
- X * *
- X * Copyright (c) 1990-1991, S.R.van den Berg, The Netherlands *
- X * The sources can be freely copied for non-commercial use. *
- X * #include "README" *
- X * *
- X ************************************************************************/
- X#ifdef RCS
- Xstatic char rcsid[]="$Id: formail.c,v 2.11 1991/10/18 15:33:23 berg Rel $";
- X#endif
- Xstatic char rcsdate[]="$Date: 1991/10/18 15:33:23 $";
- X#include "config.h" /* slight overkill */
- X#include "includes.h"
- X
- Xchar*pstrspn();
- X
- X#define BSIZE 4096
- X
- X#define NAMEPREFIX "formail: "
- X#define HEAD_DELIMITER ':'
- X
- X#define Re (re+1)
- X#define Nextchar(x) do{x=getchar();if(feof(stdin))goto foundeof;}while(0)
- X#define putssn(a,l) tputssn(a,(size_t)(l))
- X#define putcs(a) (errout=putc(a,mystdout))
- X#define PRDO poutfd[0]
- X#define PWRO poutfd[1]
- X
- Xstatic const char From[]=FROM,replyto[]="Reply-To:",Fromm[]="From:",
- X returnpath[]="Return-Path",sender[]="Sender:",outofmem[]="Out of memory\n",
- X subject[]="Subject:",re[]=" Re:",couldntw[]="Couldn't write to stdout",
- X references[]="References:",messageid[]="Message-ID:",Date[]="Date:",
- X article[]="Article ",Path[]="Path:",Received[]="Received:",To[]="To: ",
- X OldP[]=OLD_PREFIX,inreplyto[]="In-Reply-To:",errorsto[]="Errors-To",
- X retreceiptto[]="Return-Receipt-To";
- Xconst char binsh[]=BinSh;
- X/*
- X * sender determination fields in order of importance reliability
- X * reply-address determination fields (wrepl specifies the weight)
- X */
- Xstatic const struct {const char*head;int len,wrepl;}sest[]=
- X{ {errorsto,STRLEN(errorsto),5},{retreceiptto,STRLEN(retreceiptto),6},
- X {sender,STRLEN(sender),0},{replyto,STRLEN(replyto),4},
- X {Fromm,STRLEN(Fromm),2},{returnpath,STRLEN(returnpath),1}
- X};
- X/*
- X * digest splitting fields
- X */
- Xstatic const struct {const char*hedr;int lnr;}cdigest[]=
- X{ {Fromm,STRLEN(Fromm)},{Date,STRLEN(Date)},{subject,STRLEN(subject)},
- X {article,STRLEN(article)},{Path,STRLEN(Path)},{Received,STRLEN(Received)}
- X};
- X
- Xstatic struct {const char*const headr;const int lenr;char*rexp;}rex[]=
- X{ {subject,STRLEN(subject)},{references,STRLEN(references)},
- X {messageid,STRLEN(messageid)}
- X};
- X#define subj rex[0]
- X#define refr rex[1]
- X#define msid rex[2]
- X#define mxl(a,b) mx(STRLEN(a),STRLEN(b))
- X#ifndef MAILBOX_SEPARATOR
- X#define dig_HDR_LEN mx(mxl(From,Fromm),mxl(Date,subject))
- X#define mboxseparator From
- X#define flushseparator(i,p)
- X#else
- Xstatic const char mboxseparator[]=MAILBOX_SEPARATOR;
- X#define flushseparator(i,p) \
- X do{i=p;p=0;do{int x;Nextchar(x);}while(--i);}while(0)
- X#define dig_HDR_LEN \
- X mx(mx(mxl(From,Fromm),mxl(Date,subject)),STRLEN(mboxseparator))
- X#endif
- Xstatic struct hedit{char*hline;long hlen;struct hedit*next;}*hlist;
- Xstatic errout,oldstdout,quiet;
- Xstatic pid_t child= -1;
- Xstatic FILE*mystdout;
- Xstatic size_t nrskip,nrtotal= -1;
- X
- X#ifdef NOstrstr
- Xchar*strstr(whole,part)const char*whole,*const part;
- X{ register const char*w,*p;
- X do
- X { w=whole;p=part;
- X do
- X if(!*p)
- X return(char*)whole;
- X while(*w++==*p++);}
- X while(*whole++);
- X return(char*)0;
- X}
- X#endif
- X
- Xvoid*tmalloc(len)const size_t len;
- X{ void*p;
- X if(p=malloc(len))
- X return p;
- X nlog(outofmem);exit(EX_OSERR);
- X}
- X
- Xvoid*trealloc(old,len)void*old;const size_t len;
- X{ if(old=realloc(old,len))
- X return old;
- X nlog(outofmem);exit(EX_OSERR);
- X}
- X
- X#include "shell.h"
- X
- Xstruct hedit*overrideh(target)const char*const target;
- X{ const struct hedit*hlp;size_t len;
- X for(hlp=hlist;hlp;hlp=hlp->next)
- X { len=hlp->hlen;
- X if(hlp->hlen<0)
- X len= -hlp->hlen; /* absolute */
- X if(!strnicmp(hlp->hline,target,len)) /* header found */
- X return (struct hedit*)hlp;
- X }
- X return(struct hedit*)0; /* no header found */
- X}
- X
- Xmain(lastm,argv)const char*const argv[];
- X{ int i,ch,nowm,split=0,force=0,bogus=1,every=0,areply=0,trust=0,digest=0,
- X nowait=0,keepb=0;
- X size_t buflen,p=0,lnl=0,ll;time_t t;char*buf,*chp,*namep;struct hedit*hlp;
- 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;bogus=0;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_QUIET:quiet=1;continue;
- X case FM_SPLIT:split=1;
- X if(!*chp&&*++argv)
- X goto parsedoptions;
- X goto usg;
- Xnumber: default:
- X if(*chp-'0'>(unsigned)9)
- X {
- Xusg: log(FM_USAGE);return EX_USAGE;
- X }
- X ll=strtol(chp,(char**)0,10);
- X if(lastm==FM_SKIP)
- X nrskip=ll;
- X else
- X nrtotal=ll;
- X break;
- X case FM_BOGUS:bogus=0;continue;
- X case FM_REN_INSERT:case FM_DEL_INSERT:hlp=hlist;
- X (hlist=malloc(sizeof*hlist))->next=hlp;
- X if(!*chp&&!(chp=(char*)*++argv)) /* concatenated or seperate? */
- X goto usg;
- X hlist->hline=chp; /* add header string */
- X if(!(buf=strchr(chp,HEAD_DELIMITER)))
- X { nlog("Invalid field-name:");logqnl(chp);goto usg;
- X }
- X buflen=buf-chp+1;
- X hlist->hlen=lastm==FM_REN_INSERT?buflen:-(long)buflen;
- X case '\0':;
- X }
- X break;
- X }
- X }
- Xparsedoptions:
- X#ifdef MAILBOX_SEPARATOR
- X if(split)
- X { bogus=0;every=1;
- X }
- X#endif
- X mystdout=stdout;signal(SIGPIPE,SIG_IGN);
- X if(split)
- X { oldstdout=dup(STDOUT);fclose(stdout);startprog(argv);
- X }
- X else if(every)
- X goto usg;
- X *(namep=malloc(1))='\0';buf=malloc(buflen=BSIZE);t=time((time_t*)0);
- X i=maxindex(rex);
- X do *(rex[i].rexp=malloc(1))='\0';
- X while(i--);
- X while('\n'==(ch=getchar()));
- X for(;;) /* start parsing the header */
- X { if((buf[p++]=ch)=='\n')
- X { if(lnl==p-1) /* end of header reached */
- X break;
- X switch(ch=getchar()) /* concatenate continued lines */
- X { case ' ':case '\t':p--;continue;
- X }
- X chp=buf+lnl;
- X#ifdef MAILBOX_SEPARATOR
- X if(!strncmp(mboxseparator,chp,STRLEN(mboxseparator)))
- X { if(!lnl)
- X { if(split)
- X { p=0;goto redigest;
- X }
- X force=1; /* separator up front, don't add a 'From ' line */
- X }
- X else if(bogus)
- X *chp=' ';
- X }
- X#endif
- X i=maxindex(rex);
- X while(strnicmp(rex[i].headr,chp,ll=rex[i].lenr)&&i--);
- X if(i>=0) /* found anything already? */
- X { ll=p-lnl-ll;
- X ((char*)tmemmove(rex[i].rexp=realloc(rex[i].rexp,ll),
- X buf+lnl+rex[i].lenr,ll))[ll-1]='\0';
- X }
- X else if(!strncmp(From,chp,STRLEN(From)))
- X { if(!lnl) /* was the real "From " line */
- X { nowm=trust?1:3/*wreply*/;ll=lnl+STRLEN(From);goto foundfrom;
- X }
- X#ifndef MAILBOX_SEPARATOR
- X if(bogus)
- X { tmemmove(chp+1,chp,p++-lnl);*chp=ESCAP; /* disarm */
- X }
- X#endif
- X }
- X else
- X { i=maxindex(sest);
- X do
- X if(!strnicmp(sest[i].head,chp,sest[i].len))
- X { nowm=areply?keepb&&sest[i].head==replyto?
- X maxindex(sest)+1:sest[i].wrepl:i;
- X ll=lnl+sest[i].len;
- Xfoundfrom: buf[p]='\0';
- X if(chp=strchr(buf+ll,'<')) /* extract the address */
- X ll=chp-buf+1;
- X if((i=strcspn(chp=pstrspn(buf+ll," \t"),">(\n \t"))&&
- X (!*namep||nowm>lastm))
- X { ((char*)tmemmove(namep=realloc(namep,i+1),chp,i))[i]='\0';
- X lastm=strstr(chp,".UUCP")?nowm-maxindex(sest)-1:nowm;
- X }
- X break;
- X }
- X while(i--);
- X }
- X if(hlp=overrideh(buf+lnl)) /* replace or delete header? */
- X { if(hlp->hlen<0) /* just delete it */
- X { p=lnl;continue;
- X }
- X if(p+2>=buflen) /* trouble if BSIZE<STRLEN(OldP) */
- X buf=realloc(buf,buflen+=BSIZE);
- X tmemmove(buf+lnl+STRLEN(OldP),buf+lnl,p-lnl);
- X tmemmove(buf+lnl,OldP,STRLEN(OldP));p+=STRLEN(OldP);
- X }
- X lnl=p;continue;
- X }
- X if(p>=buflen-2)
- X buf=realloc(buf,buflen+=BSIZE);
- Xredigest:
- X ch=getchar();
- X if(feof(stdin))
- X ch='\n'; /* make sure the header ends with 2 newlines */
- X }
- X if(areply||!force&&strncmp(buf,From,STRLEN(From)))
- X { if(!areply||!overrideh(To))
- X { putss(areply?(areply=2),To:From);
- X if(*namep) /* found any sender address? */
- X putss(namep);
- X else
- X putss(UNKNOWN);}
- X if(areply)
- X { if(areply==2)
- X putnl();
- X if(*subj.rexp&&!overrideh(subject)) /* any Subject: ? */
- X { putss(subject);chp=subj.rexp;
- X if(strnicmp(pstrspn(chp," "),Re,STRLEN(Re)))
- X putss(re); /* no Re: , add one ourselves */
- X putss(chp);putnl();
- X }
- X if(*refr.rexp||*msid.rexp) /* any Message-ID: or References: ? */
- X { if(!overrideh(references))
- X { putss(references);
- X if(*refr.rexp)
- X { putss(refr.rexp);
- X if(*msid.rexp)
- X putnl();
- X }
- X if(*msid.rexp)
- X { putss(msid.rexp);putnl();
- X }
- X }
- X if(*msid.rexp&&!overrideh(inreplyto))
- X { putss(inreplyto);putss(msid.rexp);putnl();
- X }
- X }
- X }
- X else
- X { putcs(' ');putss(ctime(&t));
- X }
- X }
- X if(!areply)
- X putssn(buf,p-1);
- X for(hlp=hlist;hlp;hlp=hlp->next)
- X { ll=hlp->hlen;
- X if(hlp->hlen<0)
- X ll= -hlp->hlen;
- X if(hlp->hline[ll])
- X { putss(hlp->hline);putnl(); /* inject our new headers */
- X }
- X }
- X putnl();
- X if(areply)
- X { if(!keepb)
- X { if(mystdout!=stdout)
- X closemine();
- X opensink(); /* discard the body */
- X }
- X }
- X p=0;lnl=1; /* clear buffer, important! */
- X if(!bogus&&!split)
- X for(;;putcs(i))
- X Nextchar(i);
- X for(;;) /* continue the quest */
- X {
- X do /* read line until not From */
- X { if(p==buflen-1)
- X buf=realloc(buf,++buflen);
- X Nextchar(i=buf[p]);
- X if(++p==STRLEN(mboxseparator))
- X if(!strncmp(mboxseparator,buf,STRLEN(mboxseparator)))
- X { if(every)
- X { flushseparator(i,p);goto splitit; /* optionally flush */
- X }
- X else if(split&&lnl)
- X lnl=2; /* mark line as possible postmark */
- X else if(bogus) /* disarm */
- X {
- X#ifndef MAILBOX_SEPARATOR
- X putcs(ESCAP);break;
- X#else
- X Nextchar(i);*buf=' ';putssn(buf,p);*buf=i;p=1;continue;
- X#endif
- X }
- X }
- X if((i=='\n'||p!=1)&&areply)
- X { if(bogus)
- X putcs(ESCAP);
- X break;
- X }
- X if(lnl==1&&digest)
- X { ll=maxindex(cdigest);
- X do /* check for new digest header */
- X if(p==cdigest[ll].lnr&&!strncmp(buf,cdigest[ll].hedr,p))
- X { *namep=lnl=0;goto splitit; /* pretend we started over */
- X }
- X while(ll--);
- X }
- X }
- X while(i!='\n'&&(lnl==2||p<dig_HDR_LEN));
- X if(lnl==2)
- X { buf[p]='\0'; /* perform more thorough check for postmark */
- X if((ll=strcspn(chp=pstrspn(buf+STRLEN(From)," ")," \t\n"))&&
- X *(chp+=ll)==' '&&(ll= *(chp=pstrspn(chp," ")))!='\t'&&ll!='\n')
- X {
- Xsplitit: if((fclose(mystdout)==EOF||errout==EOF)&&!quiet)
- X { nlog(couldntw);log(", continuing...\n");split= -1;
- X }
- X if(!nowait)
- X waitforit();
- X startprog(argv);
- X if(!lnl) /* digest split? */
- X goto redigest;
- X i='\n';
- X }
- X }
- X lnl=p==1;putssn(buf,p);p=0;
- X if(i!='\n')
- X do Nextchar(i);
- X while(putcs(i),i!='\n');
- X }
- Xfoundeof:
- X putssn(buf,p);closemine();child= -1;waitforit(); /* wait for everyone */
- X return split<0?EX_IOERR:EX_OK;
- X}
- X
- Xlog(a)const char*const a;
- X{ fputs(a,stderr);
- X}
- X
- Xlogqnl(a)const char*a;
- X{ log(" \"");log(a);log("\"\n");
- X}
- X
- Xputss(a)const char*a;
- X{ while(*a)
- X putcs(*a++);
- X}
- X
- Xtputssn(a,l)const char*a;size_t l;
- X{ while(l--)
- X putcs(*a++);
- X}
- X
- Xstartprog(argv)const char*const*const argv;
- X{ int poutfd[2];
- X if(!nrtotal)
- X goto squelch;
- X if(nrskip)
- X { --nrskip;
- Xsquelch:
- X opensink();return;
- X }
- X if(nrtotal>0)
- X --nrtotal;
- X dup(oldstdout);pipe(poutfd);
- X if(!(child=fork()))
- X { close(oldstdout);close(PWRO);fclose(stdin);dup(PRDO);close(PRDO);
- X shexec(argv);
- X }
- X close(STDOUT);close(PRDO);
- X if(STDOUT!=dup(PWRO)||!(mystdout=fdopen(STDOUT,"a")))
- X nofild();
- X close(PWRO);
- X if(-1==child)
- X { nlog("Can't fork\n");exit(EX_OSERR);
- X }
- X}
- X
- Xnofild()
- X{ nlog("File table full\n");exit(EX_OSERR);
- X}
- X
- Xwaitforit()
- X{ int i;pid_t j;
- X while(child!=(j=wait(&i))||(i&127)==127)
- X if(-1==j)
- X return;
- X}
- X
- Xnlog(a)const char*const a;
- X{ log(NAMEPREFIX);log(a);
- X}
- X
- Xclosemine()
- X{ if((fclose(mystdout)==EOF||errout==EOF)&&!quiet)
- X { nlog(couldntw);log("\n");;exit(EX_IOERR);
- X }
- X}
- X
- Xopensink()
- X{ if(!(mystdout=fopen(DevNull,"a")))
- X nofild();
- X}
- X
- Xputnl()
- X{ putcs('\n');
- X}
- X
- Xstrnicmp(a,b,l)register const char*a,*b;register unsigned l;
- X{ int i,j;
- X if(l) /* case insensitive strncmp */
- X do
- X { while(*a&&*a==*b&&--l)
- X ++a,++b;
- X if(!l)
- X break;
- X if((i= *a++)>='A'&&i<='Z')
- X i+='a'-'A';
- X if((j= *b++)>='A'&&j<='Z')
- X j+='a'-'A';
- X if(j!=i)
- X return i>j?1:-1;
- X }
- X while(i&&j&&--l);
- X return 0;
- X}
- END_OF_FILE
- if test 12561 -ne `wc -c <'procmail/formail.c'`; then
- echo shar: \"'procmail/formail.c'\" unpacked with wrong size!
- fi
- # end of 'procmail/formail.c'
- 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'\" \(10952 characters\)
- sed "s/^X//" >'procmail/regexp.c' <<'END_OF_FILE'
- X/************************************************************************
- X * Custom regular expression library, *fully* egrep compatible *
- X * *
- X * Copyright (c) 1990-1991, S.R.van den Berg, The Netherlands *
- X * The sources can be freely copied for non-commercial use. *
- X * #include "README" *
- X * *
- X ************************************************************************/
- X#ifdef RCS
- Xstatic char rcsid[]="$Id: regexp.c,v 2.4 1991/10/18 15:34:23 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_END_GROUP ')'
- X#define R_OR '|'
- 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 OPB 256
- Xenum opcode {OPC_EPS=OPB,OPC_CLASS,OPC_DOT,OPC_FIN};
- 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
- X/* the spawn and stack members are reused in the normal opcodes as pc fields */
- Xstatic struct eps{int opc;struct eps*next,*spawn,*stack;}*r,aleps;
- Xstatic uchar*p;
- Xstatic ignore_case;
- X
- Xstruct chclass {int opc_;struct eps*next_,*spawn_,*stack_;bit_field(c,256);};
- 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)struct eps const*const e;
- X{ switch(*p)
- X { case R_BEG_GROUP: /* not so simple after all */
- X ++p;por(e);return;
- X case R_BEG_CLASS: /* a simple class */
- X { uchar i,j=R_NOT_CLASS==*++p; /* char to save space */
- 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;bit_toggle(rAc,'\n');
- X }
- X if(*p==R_END_CLASS) /* right at the start, can not mean the end */
- X { ++p;
- X if(e)
- X { i=R_END_CLASS;bit_toggle(rAc,R_END_CLASS);
- X }
- 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 }
- X for(;;++p)
- X { switch(*p)
- X { case R_END_CLASS:++p;
- X case '\0':r=Ceps((char*)r+SZ(chclass));return;
- X /* add code here to take care of special escapes */
- 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_SOL:case R_EOL: /* 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 /* add code here to take care of special escapes */
- 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
- Xstatic skipent()
- X{ switch(*p++)
- X { case '\0':p--;break;
- X case R_ESCAPE: /* something is quoted */
- X /* add code here to take care of special escapes */
- X if(*p)
- X ++p;
- X break;
- X case R_BEG_GROUP: /* something big lies ahead */
- X for(;;)
- X { switch(*p)
- X { case R_END_GROUP:++p; /* back in the civilised world */
- X case '\0':return;
- X }
- X skipent(); /* skip it one entity at a time */
- X }
- X case R_BEG_CLASS: /* skip class :-) */
- X if(*p==R_NOT_CLASS)
- X ++p;
- X if(*p==R_END_CLASS)
- X ++p;
- X for(;;)
- X switch(*p++)
- X { case '\0':--p;
- X case R_END_CLASS:return;
- X /* add code here to take care of special escapes */
- X }
- X }
- X}
- X /* EOS is needed to save stack space */
- X#define EOS(x) (p[1]==R_OR||p[1]==R_END_GROUP||!p[1]?Ceps e:(x))
- X
- Xstatic pnorm(e)struct eps const*const e;
- X{ void*pold;struct eps*rold;
- X for(;;)
- X { pold=p;skipent();rold=r; /* skip it first, so we can look if it is */
- X switch(*p) /* followed by any of the postfix operators */
- X { case R_0_OR_MORE:p=pold;++r;
- X if(e) /* first an epsilon, then the rest */
- X { psimp(rold);putneps(rold,EOS(r));
- X }
- X else
- X psimp((struct eps*)0);
- X goto incagoon;
- X case R_1_OR_MORE:p=pold;psimp((struct eps*)0); /* first the rest */
- X if(e) /* and then an epsilon */
- X { puteps(r,rold,EOS(r+1));p=pold;pold=r;r=rold;psimp(pold);
- X }
- X ++r;goto incagoon;
- X case R_0_OR_1:p=pold;++r;psimp((struct eps*)0);
- X if(e) /* first an epsilon, then the rest */
- X { putneps(rold,r=EOS(r));p=pold;pold=r;r=rold+1;psimp(pold);
- X }
- 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':p=pold;psimp(e);return;
- X }
- X p=pold;psimp((struct eps*)0);
- X if(e) /* no fancy postfix operators, plain vanilla */
- X { p=pold;pold=r;r=rold;psimp(pold);
- X }
- X }
- X}
- X
- Xstatic por(e)struct eps const*const e;
- X{ uchar*pold;struct eps*rold;
- X for(;;)
- X for(pold=p;;)
- X { switch(*p)
- X { default:skipent();continue; /* still in this 'or' 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;
- X }
- X else
- X { p=pold;pnorm(e); /* normal last group */
- X }
- X if(*p)
- X ++p;
- X return;
- X case R_OR:rold=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,new)register struct eps*const*const old;
- X struct eps*const new;
- X{ register struct eps*i;
- X for(i=r;;++i) /* change all pointers from *old to new */
- X { if(&i->next!=old&&i->next==*old)
- X i->next=new;
- X if(&i->spawn!=old&&i->spawn==*old)
- X i->spawn=new;
- X switch(i->opc)
- X { case OPC_FIN:return; /* last one, ready */
- X case OPC_CLASS:i=Ceps((char*)(i-1)+SZ(chclass));
- X }
- X }
- 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=(struct eps*)p; /* mark this one as used */
- X#define RECURS(nxt,spwn) \
- X do\
- X if((*stack)->nxt->stack==(struct eps*)p)\
- X { findandrep(*stack,(*stack)->nxt);*stack=(*stack)->spwn;return 1;\
- X }\
- X while(fillout(&(*stack)->nxt));
- X RECURS(next,spawn);RECURS(spawn,next);return 0; /* recurse */
- X}
- X
- Xvoid*regcomp(a,ign_case)char const*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= &aleps+2;por((struct eps*)0);p=(uchar*)a;
- X st=malloc(i=(char*)r-(char*)&aleps);putneps(st,r=st+1); /* really compile */
- X por(Ceps((char*)st+i-SZ(eps)));r->opc=OPC_FIN;r->stack=0; /* add end */
- X for(r=st;;++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_EPS:p=(uchar*)st;fillout(&st);break; /* check tree */
- X case OPC_CLASS:st=Ceps((char*)(st-1)+SZ(chclass)); /* skip */
- X }
- X}
- X
- Xchar*regexec(code,text,len,ign_case)struct eps*code;const uchar*text;
- X long len;const int ign_case;
- X{ register struct eps*reg,*t,*stack,*other,*this;int i,th1,ot1;
- X if(code[1].opc==OPC_EPS)
- X ++code;
- X (this=code)->stack=0;th1=offsetof(struct eps,spawn);
- X ot1=offsetof(struct eps,stack);
- X#define XOR1 (offsetof(struct eps,spawn)^offsetof(struct eps,stack))
- X#define PC(this,t) (*(struct eps**)((char*)(this)+(t)))
- 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;this=other;
- Xsetups:
- X reg=(other=stack=code)->next;goto nostack;
- X do /* pop next entry off this pc-stack */
- X { reg=(t=this)->next;this=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&&(unsigned)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-1; /* 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 }
- X while(stack); /* the work-stack is not empty */
- X }
- X while(this!=code); /* this pc-stack is not empty */
- X }
- X while(--len>=0); /* still text to search */
- X if(i>=0)
- X { ++text;i= -1;goto lastrun; /* out of text, check if we just matched */
- X }
- X return 0; /* no match */
- X}
- END_OF_FILE
- if test 10952 -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/retint.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'procmail/retint.c'\"
- else
- echo shar: Extracting \"'procmail/retint.c'\" \(11077 characters\)
- sed "s/^X//" >'procmail/retint.c' <<'END_OF_FILE'
- X/************************************************************************
- X * Collection of routines that return an int (sort of anyway :-) *
- X * *
- X * Copyright (c) 1990-1991, S.R.van den Berg, The Netherlands *
- X * The sources can be freely copied for non-commercial use. *
- X * #include "README" *
- X * *
- X ************************************************************************/
- X#ifdef RCS
- Xstatic char rcsid[]="$Id: retint.c,v 2.12 1991/10/22 15:31:26 berg Rel $";
- X#endif
- X#include "config.h"
- X#include "procmail.h"
- X#include "shell.h"
- X
- Xsetdef(name,contents)const char*const name,*const contents;
- X{ strcat(strcat(strcpy(sgetcp=buf2,name),"="),contents);
- X readparse(buf,sgetc,0);sputenv(buf);
- X}
- X
- Xchar*lastexec,*backblock;
- Xlong backlen; /* length of backblock, filter recovery block */
- Xpid_t pidfilt,pidchild;
- Xint pbackfd[2]; /* the emergency backpipe :-) */
- X
- Xpipthrough(line,source,len)char*line,*source;const long len;
- X{ int pinfd[2],poutfd[2];
- X rpipe(pbackfd);rpipe(pinfd); /* main pipes setup */
- X if(!(pidchild=sfork())) /* create a sending procmail */
- X { backblock=source;backlen=len;signal(SIGTERM,stermchild);
- X signal(SIGINT,stermchild);signal(SIGHUP,stermchild);
- X signal(SIGQUIT,stermchild);rclose(rc);rclose(PRDI);rclose(PRDB);
- X rpipe(poutfd);rclose(STDOUT);
- X if(!(pidfilt=sfork())) /* create the filter */
- X { rclose(PWRO);rclose(PWRB);rdup(PWRI);rclose(PWRI);getstdin(PRDO);
- X callnewprog(line);
- X }
- X rclose(PWRI);rclose(PRDO);
- X if(forkerr(pidfilt,line))
- X { rclose(PWRO);stermchild();
- X }
- X if(dump(PWRO,source,len)) /* send in the text to be filtered */
- X { writeerr(line);stermchild();
- X }
- X if(pwait&&waitfor(pidfilt)!=EX_OK) /* check the exitcode of the filter */
- X { progerr(line);stermchild();
- X }
- X rclose(PWRB);exit(EX_OK); /* allow parent to proceed */
- X }
- X rclose(PWRI);rclose(PWRB);getstdin(PRDI);
- X if(forkerr(pidchild,procmailn))
- X return 1;
- X return 0; /* we stay behind to read back the filtered text */
- X}
- X
- Xwaitfor(pid)const pid_t pid; /* wait for a specific process */
- X{ int i;pid_t j;
- X while(pid!=(j=wait(&i))||(i&127)==127)
- X if(-1==j)
- X return EX_UNAVAILABLE;
- X return i>>8&255;
- X}
- X
- Xgetstdin(pip)const int pip;
- X{ rclose(STDIN);rdup(pip);rclose(pip);
- X}
- X
- Xcallnewprog(newname)const char*const newname;
- X{ if(sh) /* should we start a shell? */
- X { const char*newargv[4];
- X yell(executing,newname);newargv[3]=0;newargv[2]=newname;
- X newargv[1]=tgetenv(shellflags);*newargv=tgetenv(shell);shexec(newargv);
- X }
- X {register const char*p;int argc;const char**newargv;
- X argc=1;p=newname; /* If no shell, chop up the arguments ourselves */
- X if(verbose)
- X { log(executing);log(oquote);goto no_1st_comma;
- X }
- X do /* show chopped up command line */
- X { if(verbose)
- X { log(",");
- Xno_1st_comma:
- X log(p);
- X }
- X while(*p++);
- X }
- X while(argc++,*p!=TMNATE);
- X if(verbose)
- X log(cquote);
- X newargv=malloc(argc*sizeof*newargv);p=newname;argc=0; /* alloc argv array */
- X do
- X { newargv[argc++]=p;
- X while(*p++);
- X }
- X while(*p!=TMNATE);
- X newargv[argc]=0;shexec(newargv);
- X }
- X}
- X
- Xwriteerr(line)const char*const line;
- X{ log("Error while writing to");logqnl(line);
- X}
- X
- Xforkerr(pid,a)const pid_t pid;const char*const a;
- X{ if(pid==-1)
- X { log("Failed forking");logqnl(a);return 1;
- X }
- X return 0;
- X}
- X
- Xprogerr(line)const char*const line;
- X{ log("Program failure of");logqnl(line);
- X}
- X
- Xopena(a)const char*const a;
- X{ lastfolder=cstr(lastfolder,a);yell("Opening",a);
- X#ifdef O_CREAT
- X return ropen(a,O_WRONLY|O_APPEND|O_CREAT,0666);
- X#else
- X {int fd;
- X return(fd=ropen(a,O_WRONLY))<0?creat(a,0666):fd;
- X }
- X#endif
- X}
- X
- Xyell(a,b)const char*const a,*const b; /* log if -d option set */
- X{ if(verbose)
- X { log(a);logqnl(b);
- X }
- X}
- X
- Xunlock(lockp)const char**const lockp;
- X{ lcking=1;
- X if(*lockp)
- X { yell("Unlocking",*lockp);
- X if(unlink(*lockp))
- X { log("Couldn't unlock");logqnl(*lockp);
- X }
- X free(*lockp);*lockp=0;
- X }
- X lcking=0;
- X if(nextexit==1) /* make sure we are not inside terminate already */
- X { log(newline);terminate();
- X }
- X}
- X
- Xnomemerr()
- X{ log("Out of memory\nbuffer 0: \"");buf[linebuf-1]=buf2[linebuf-1]='\0';
- X log(buf);log("\"\nbuffer 1:");logqnl(buf2);retval=EX_OSERR;terminate();
- X}
- X
- Xlogqnl(a)const char*const a;
- X{ log(oquote);log(a);log(cquote);
- X}
- X
- Xnextrcfile() /* next rcfile specified on the command line */
- X{ const char*p;
- X while(p= *gargv)
- X { gargv++;
- X if(!strchr(p,'='))
- X { rcfile=p;return 1;
- X }
- X }
- X return 0;
- X}
- X
- Xrclose(fd)const int fd; /* a sysV secure close (signal immune) */
- X{ int i;
- X while((i=close(fd))&&errno==EINTR);
- X return i;
- X}
- X
- Xrwrite(fd,a,len)const int fd,len;void*const a; /* a sysV secure write */
- X{ int i;
- X while(0>(i=write(fd,a,(size_t)len))&&errno==EINTR);
- X return i;
- X}
- X
- Xrread(fd,a,len)const int fd,len;void*const a; /* a sysV secure read */
- X{ int i;
- X while(0>(i=read(fd,a,(size_t)len))&&errno==EINTR);
- X return i;
- X}
- X
- Xropen(name,mode,mask)const char*const name;const int mode;const mode_t mask;
- X{ int i,r; /* a sysV secure open */
- X for(lcking=4,r=noresretry;0>(i=open(name,mode,mask));)
- X if(errno!=EINTR&&!((errno==EMFILE||errno==ENFILE)&&(r<0||r--)))
- X break; /* survives a temporary "file table full" condition */
- X lcking=0;return i;
- X}
- X
- Xrdup(p)const int p;
- X{ int i,r;
- X for(lcking=4,r=noresretry;0>(i=dup(p));) /* catch "file table full" */
- X if(!((errno==EMFILE||errno==ENFILE)&&(r<0||r--)))
- X break;
- X lcking=0;return i;
- X}
- X
- Xrpipe(fd)int fd[2];
- X{ int i,r;
- X for(lcking=4,r=noresretry;0>(i=pipe(fd));) /* catch "file table full" */
- X if(!((errno==EMFILE||errno==ENFILE)&&(r<0||r--)))
- X { *fd=fd[1]= -1;break;
- X }
- X lcking=0;return i;
- X}
- X
- Xlockit(name,lockp)char*name;const char**const lockp;
- X{ int i;struct stat stbuf;
- X unlock(lockp); /* unlock any previous lockfile FIRST */
- X if(!*name)
- X return;
- X for(lcking=1;;) /* to prevent deadlocks (I hate deadlocks) */
- X { yell("Locking",name);
- X if(!NFSxopen(name))
- X { *lockp=tstrdup(name); /* lock acquired, hurray! */
- Xterm: lcking=0;
- X if(nextexit)
- X { log(whilstwfor);log("lockfile");logqnl(name);terminate();
- X }
- X return; /* check if it's time for a lock override */
- X }
- X if(errno==EEXIST&&!stat(name,&stbuf)&&!stbuf.st_size)
- X { time_t t;
- X if(locktimeout&&(t=time((time_t*)0),!stat(name,&stbuf))) /* stat */
- X if(locktimeout<t-stbuf.st_mtime) /* till unlink should be atomic */
- X { if(unlink(name)) /* but can't guarantee that */
- X { log("Forced unlock denied on");logqnl(name);
- X }
- X else
- X { log("Forcing lock on");logqnl(name);suspend();
- X }
- X }
- X }
- X else /* maybe filename too long, shorten and retry */
- X { if(errno!=ENOTDIR&&0<(i=strlen(name)-1)&&!strchr(dirsep,name[i-1]))
- X { name[i]='\0';continue;
- X }
- X log("Lockfailure on");logqnl(name);return;
- X }
- X sleep((unsigned)locksleep);
- X if(nextexit)
- X goto term;
- X }
- X}
- X
- Xlcllock() /* lock a local file (if need be) */
- X{ if(locknext)
- X if(tolock)
- X lockit(tolock,&loclock);
- X else
- X lockit(strcat(buf2,tgetenv(lockext)),&loclock);
- X}
- X
- Xterminate()
- X{ nextexit=2; /* prevent multiple invocations of terminate */
- X if(getpid()==thepid)
- X { if(retval!=EX_OK)
- X { log(Mail);
- X log(fakedelivery?"lost\n":
- X retval==EX_TEMPFAIL?"requeued\n":"bounced\n");
- X }
- X unlock(&loclock);unlock(&globlock);unlockfd();
- X }
- X exit(retval);
- X}
- X
- Xignoreterm()
- X{ signal(SIGTERM,SIG_IGN);signal(SIGHUP,SIG_IGN);signal(SIGINT,SIG_IGN);
- X signal(SIGQUIT,SIG_IGN);
- X}
- X
- Xsuspend()
- X{ long t;
- X sleep((unsigned)suspendv);
- X if(alrmtime)
- X if((t=alrmtime-time((time_t*)0))<=1) /* if less than 1s timeout */
- X ftimeout(); /* activate it by hand now */
- X else /* set it manually again, to avoid problems with */
- X alarm((unsigned)t); /* badly implemented sleep library functions */
- X}
- X
- Xinittmout(progname)const char*const progname;
- X{ lastexec=cstr(lastexec,progname);
- X alrmtime=timeoutv?time((time_t*)0)+(unsigned)timeoutv:0;
- X alarm((unsigned)timeoutv);
- X}
- X
- Xskipspace()
- X{ while(testb(' ')||testb('\t'));
- X}
- X
- Xsgetc() /* a fake fgetc for a string */
- X{ return *sgetcp?*(uchar*)sgetcp++:EOF;
- X}
- X
- Xskipped(x)const char*const x;
- X{ log("Skipped");logqnl(x);
- X}
- X
- Xconcatenate(old)char*const old;
- X{ register char*p=old;
- X while(*p!=TMNATE) /* concatenate all other arguments */
- X { while(*p++);
- X p[-1]=' ';
- X }
- X *p=p[-1]='\0';return*old;
- X}
- X
- Xdetab(p)char*p;
- X{ while(p=strchr(p,'\t'))
- X *p=' '; /* take out all tabs */
- X}
- X
- Xstatic uchar rcbuf[STDBUF],*rcbufp,*rcbufend; /* buffers for custom stdio */
- Xstatic ungetb; /* pushed back char */
- X
- Xbopen(name)const char*const name; /* my fopen */
- X{ rcbufp=rcbufend=0;ungetb= -1;yell("Rcfile:",name);
- X return rc=ropen(name,O_RDONLY);
- X}
- X
- Xgetbl(p)char*p; /* my gets */
- X{ int i;char*q;
- X for(q=p;;)
- X { switch(i=getb())
- X { case '\n':case EOF:
- X *p='\0';return p!=q; /* did we read anything at all? */
- X }
- X *p++=i;
- X }
- X}
- X
- Xgetb() /* my fgetc */
- X{ if(ungetb>=0) /* anything pushed back? */
- X { int i;
- X i=ungetb;ungetb= -1;return i;
- X }
- X if(rcbufp==rcbufend)
- X { rcbufend=rcbuf+rread(rc,rcbufp=rcbuf,STDBUF); /* refill */
- X }
- X return rcbufp<rcbufend?*rcbufp++:EOF;
- X}
- X
- Xtestb(x)const int x; /* fgetc that only succeeds if it matches */
- X{ int i;
- X if((i=getb())==x)
- X return 1;
- X ungetb=i;return 0;
- X}
- X
- Xalphanum(c)const int c;
- X{ return c>='0'&&c<='9'||c>='a'&&c<='z'||c>='A'&&c<='Z'||c=='_';
- X}
- X /* open file or new file in directory */
- Xdeliver(boxname)char*const boxname;
- X{ struct stat stbuf;
- X strcpy(buf,boxname); /* boxname can be found back in buf */
- X return stat(buf,&stbuf)||!S_ISDIR(stbuf.st_mode)?
- X (tofolder=1,opena(buf)):dirmail();
- X}
- X
- X#ifndef lockfd
- Xstatic oldlockfd; /* the fd we locked last */
- X#ifdef F_SETLKW
- Xstatic struct flock flck; /* why can't it be a local variable? */
- X
- Xlockfd(fd) /* the POSIX-fcntl() lock */
- X{ flck.l_type=F_WRLCK;flck.l_whence=SEEK_SET;flck.l_len=0;
- X flck.l_start=tell(fd);lcking=5;fd=fcntl(oldlockfd=fd,F_SETLKW,&flck);
- X lcking=0;return fd;
- X}
- X
- Xunlockfd()
- X{ flck.l_type=F_UNLCK;return fcntl(oldlockfd,F_SETLK,&flck);
- X}
- X#else
- X#ifdef F_LOCK
- Xstatic long oldlockoffset;
- X
- Xlockfd(fd) /* the sysV-lockf() */
- X{ oldlockoffset=tell(fd);lcking=5;fd=lockf(oldlockfd=fd,F_LOCK,0L);lcking=0;
- X return fd;
- X}
- X
- Xunlockfd()
- X{ lseek(oldlockfd,oldlockoffset,SEEK_SET);return lockf(oldlockfd,F_ULOCK,0L);
- X}
- X#else
- X#ifdef LOCK_EX
- Xlockfd(fd) /* the BSD-flock() */
- X{ lcking=5;fd=flock(oldlockfd=fd,LOCK_EX);lcking=0;return fd;
- X}
- X
- Xunlockfd()
- X{ return flock(oldlockfd,LOCK_UN);
- X}
- X#endif
- X#endif
- X#endif
- X#endif
- X
- X#include "exopen.h"
- X
- XNFSxopen(name)char*name; /* an NFS secure exclusive file open */
- X{char*p,*q;int j= -2,i;
- X for(q=name;p=strpbrk(q,dirsep);q=p+1); /* find last DIRSEP */
- X i=q-name;strncpy(p=malloc(i+UNIQnamelen),name,i);
- X if(unique(p,p+i,0))
- X j=myrename(p,name); /* try and rename it, fails if nonexclusive */
- X free(p);return j;
- X}
- END_OF_FILE
- if test 11077 -ne `wc -c <'procmail/retint.c'`; then
- echo shar: \"'procmail/retint.c'\" unpacked with wrong size!
- fi
- # end of 'procmail/retint.c'
- fi
- echo shar: End of archive 2 \(of 4\).
- cp /dev/null ark2isdone
- MISSING=""
- for I in 1 2 3 4 ; do
- if test ! -f ark${I}isdone ; then
- MISSING="${MISSING} ${I}"
- fi
- done
- if test "${MISSING}" = "" ; then
- echo You have unpacked all 4 archives.
- rm -f ark[1-9]isdone
- else
- echo You still must unpack the following archives:
- echo " " ${MISSING}
- fi
- exit 0
- exit 0 # Just in case...
- --
- Kent Landfield INTERNET: kent@sparky.IMD.Sterling.COM
- Sterling Software, IMD UUCP: uunet!sparky!kent
- Phone: (402) 291-8300 FAX: (402) 291-4362
- Please send comp.sources.misc-related mail to kent@uunet.uu.net.
-