home *** CD-ROM | disk | FTP | other *** search
Text File | 1993-02-04 | 45.2 KB | 1,187 lines |
- Newsgroups: comp.sources.misc
- From: berg@pool.informatik.rwth-aachen.de (Stephen R. van den Berg)
- Subject: v35i031: procmail - mail processing package v2.80, Part10/11
- Message-ID: <1993Feb5.020733.16935@sparky.imd.sterling.com>
- X-Md4-Signature: a4a052d61af3e1757a814cf94d4f1c76
- Date: Fri, 5 Feb 1993 02:07:33 GMT
- Approved: kent@sparky.imd.sterling.com
-
- Submitted-by: berg@pool.informatik.rwth-aachen.de (Stephen R. van den Berg)
- Posting-number: Volume 35, Issue 31
- Archive-name: procmail/part10
- Environment: sendmail, smail, MMDF, mailsurr, UNIX, POSIX
- Supersedes: procmail: Volume 31, Issue 40-44
-
- #! /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 10 (of 11)."
- # Contents: procmail280/src/formail.c procmail280/src/procmail.c
- # Wrapped by berg@hathi on Thu Feb 4 15:28:01 1993
- PATH=/bin:/usr/bin:/usr/ucb ; export PATH
- if test -f 'procmail280/src/formail.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'procmail280/src/formail.c'\"
- else
- echo shar: Extracting \"'procmail280/src/formail.c'\" \(18801 characters\)
- sed "s/^X//" >'procmail280/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.21 1993/02/02 15:27:07 berg Exp $";
- X#endif
- Xstatic /*const*/char rcsdate[]="$Date: 1993/02/02 15:27:07 $";
- 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;
- Xstatic struct field*iheader,*Iheader,*aheader,*Aheader,*xheader,*Xheader,
- X *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;char*chp,*namep;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_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 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 saddr=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;nowm=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 else if(findf(fldp,xheader)) /* extract field contents */
- X putssn(chp+lnl,fldp->tot_len-lnl);
- X else if(findf(fldp,Xheader)) /* extract fields */
- X putssn(chp,fldp->tot_len);
- 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 if(xheader||Xheader) /* we're just extracting fields */
- X clearfield(&rdheader),clearfield(&nheader); /* throw it away */
- X else /* otherwise, display the new & improved header */
- X { flushfield(&rdheader);flushfield(&nheader);dispfield(Aheader);
- X dispfield(iheader);dispfield(Iheader);lputcs('\n'); /* make sure it is */
- X } /* followed by an empty line */
- X if(namep)
- X free(namep);
- 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 lputcs(ESCAP);
- 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 lputcs(ESCAP),lputssn(chp,(p=strchr(chp,'\n')+1)-chp);
- 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 lputcs(ESCAP);
- 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 18801 -ne `wc -c <'procmail280/src/formail.c'`; then
- echo shar: \"'procmail280/src/formail.c'\" unpacked with wrong size!
- fi
- # end of 'procmail280/src/formail.c'
- fi
- if test -f 'procmail280/src/procmail.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'procmail280/src/procmail.c'\"
- else
- echo shar: Extracting \"'procmail280/src/procmail.c'\" \(23640 characters\)
- sed "s/^X//" >'procmail280/src/procmail.c' <<'END_OF_FILE'
- X/************************************************************************
- X * procmail - The autonomous mail processor *
- X * *
- X * It has been designed to be able to be run suid root and (in *
- X * case your mail spool area is *not* world writeable) sgid *
- X * mail (or daemon), without creating security holes. *
- X * *
- X * Seems to be perfect. *
- 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: procmail.c,v 1.25 1993/02/02 15:27:23 berg Exp $";
- X#endif
- X#include "../patchlevel.h"
- X#include "procmail.h"
- X#include "sublib.h"
- X#include "robust.h"
- X#include "shell.h"
- X#include "misc.h"
- X#include "pipes.h"
- X#include "common.h"
- X#include "cstdio.h"
- X#include "exopen.h"
- X#include "goodies.h"
- X#include "locking.h"
- X#include "mailfold.h"
- X
- Xstatic const char fdefault[]="DEFAULT",orgmail[]="ORGMAIL",
- X sendmail[]="SENDMAIL",From_[]=FROM,exflags[]=RECFLAGS,
- X systm_mbox[]=SYSTEM_MBOX,pmusage[]=PM_USAGE;
- Xchar*buf,*buf2,*globlock,*loclock,*tolock,*lastfolder;
- Xconst char shellflags[]="SHELLFLAGS",shell[]="SHELL",lockfile[]="LOCKFILE",
- X shellmetas[]="SHELLMETAS",lockext[]="LOCKEXT",newline[]="\n",binsh[]=BinSh,
- X unexpeof[]="Unexpected EOL\n",*const*gargv,*sgetcp,*rcfile=PROCMAILRC,
- X dirsep[]=DIRSEP,msgprefix[]="MSGPREFIX",devnull[]=DevNull,lgname[]="LOGNAME",
- X executing[]="Executing",oquote[]=" \"",cquote[]="\"\n",procmailn[]="procmail",
- X whilstwfor[]=" whilst waiting for ",home[]="HOME",maildir[]="MAILDIR";
- Xchar*Stdout;
- Xint retval=EX_CANTCREAT,retvl2=EX_OK,sh,pwait,lcking,rc=rc_INIT,
- X ignwerr,lexitcode=EX_OK,asgnlastf;
- Xsize_t linebuf=mx(DEFlinebuf+XTRAlinebuf,STRLEN(systm_mbox)<<1);
- Xvolatile int nextexit; /* if termination is imminent */
- Xpid_t thepid;
- Xlong filled; /* the length of the mail */
- Xchar*themail,*thebody; /* the head and body of the mail */
- Xuid_t uid;
- Xgid_t gid,sgid;
- X
- Xmain(argc,argv)const char*const argv[];
- X{ static char flags[maxindex(exflags)];
- X static const char*const keepenv[]=KEEPENV,*const prestenv[]=PRESTENV,
- X *const trusted_ids[]=TRUSTED_IDS;
- X char*chp,*startchar,*chp2,*fromwhom=0;long tobesent;
- X int i,lastcond,succeed,suppmunreadable;
- X#define Deliverymode lastcond
- X#define Presenviron i
- X#define Privileged succeed
- X Deliverymode=0;
- X if(argc) /* sanity check, any argument at all? */
- X { Deliverymode=strcmp(lastdirsep(argv[0]),procmailn);
- X for(Presenviron=argc=0;(chp2=(char*)argv[++argc])&&*chp2=='-';)
- X for(;;) /* processing options */
- X { switch(*++chp2)
- X { case VERSIONOPT:elog(VERSION);return EX_OK;
- X case HELPOPT1:case HELPOPT2:elog(pmusage);elog(PM_HELP);
- X elog(PM_QREFERENCE);return EX_USAGE;
- X case PRESERVOPT:Presenviron=1;continue;
- X case TEMPFAILOPT:retval=EX_TEMPFAIL;continue;
- X case FROMWHOPT:case ALTFROMWHOPT:
- X if(*++chp2)
- X fromwhom=chp2;
- X else if(chp2=(char*)argv[argc+1])
- X argc++,fromwhom=chp2;
- X else
- X nlog("Missing name\n");
- X break;
- X case DELIVEROPT:
- X if(!*(chp= ++chp2)&&!(chp=(char*)argv[++argc]))
- X { nlog("Missing recipient\n");break;
- X }
- X else
- X { Deliverymode=1;goto last_option;
- X }
- X case '-':
- X if(!*chp2)
- X { argc++;goto last_option;
- X }
- X default:nlog("Unrecognised options:");logqnl(chp2);
- X elog(pmusage);elog("Processing continued\n");
- X case '\0':;
- X }
- X break;
- X }
- X }
- Xlast_option:
- X if(!Presenviron) /* drop the environment */
- X { const char**emax=(const char**)environ,*const*ep,*const*kp;
- X for(kp=keepenv;*kp;kp++) /* preserve a happy few */
- X for(i=strlen(*kp),ep=emax;chp2=(char*)*ep;ep++)
- X if(!strncmp(*kp,chp2,i)&&(chp2[i]=='='||chp2[i-1]=='_'))
- X { *emax++=chp2;break;
- X }
- X *emax=0; /* drop the rest */
- X }
- X#ifdef LD_ENV_FIX
- X ;{ const char**emax=(const char**)environ,**ep;static const char ld_[]="LD_";
- X for(ep=emax;*emax;emax++); /* find the end of the environment */
- X while(*ep)
- X if(!strncmp(ld_,*ep++,STRLEN(ld_))) /* it starts with LD_ */
- X *--ep= *--emax,*emax=0; /* copy from the end */
- X }
- X#endif /* LD_ENV_FIX */
- X ;{ struct passwd*pass,*passinvk,spassinvk;uid_t euid=geteuid();
- X if(passinvk=getpwuid(uid=getuid())) /* save it by copying it */
- X tmemmove(&spassinvk,passinvk,sizeof spassinvk),passinvk= &spassinvk;
- X Privileged=1;gid=getgid();
- X if(*trusted_ids&&uid!=euid)
- X { struct group*grp;const char*const*kp;
- X if(passinvk) /* check out the invoker's uid */
- X for(chp2=passinvk->pw_name,kp=trusted_ids;*kp;)
- X if(!strcmp(chp2,*kp++)) /* is it among the privileged? */
- X goto privileged;
- X if(grp=getgrgid(gid)) /* check out the invoker's gid */
- X for(chp2=grp->gr_name,kp=trusted_ids;*kp;)
- X if(!strcmp(chp2,*kp++)) /* is it among the privileged? */
- X goto privileged;
- X Privileged=0;
- X if(Deliverymode)
- X fromwhom=0;
- X }
- Xprivileged:
- X endgrent();endpwent();umask(INIT_UMASK);fclose(stdout);rclose(STDOUT);
- X if(0>opena(devnull))
- X { writeerr(devnull);return EX_OSFILE; /* couldn't open stdout */
- X }
- X#ifdef console
- X openlog(console);
- X#endif
- X setbuf(stdin,(char*)0);buf=malloc(linebuf);buf2=malloc(linebuf);
- X lastfolder=cstr(lastfolder,"");thepid=getpid();
- X#ifdef SIGXCPU
- X signal(SIGXCPU,SIG_IGN);signal(SIGXFSZ,SIG_IGN);
- X#endif
- X#ifdef SIGLOST
- X signal(SIGLOST,SIG_IGN);
- X#endif
- X signal(SIGPIPE,SIG_IGN);signal(SIGTERM,(void(*)())srequeue);
- X signal(SIGINT,(void(*)())sbounce);signal(SIGHUP,(void(*)())sbounce);
- X signal(SIGQUIT,(void(*)())slose);signal(SIGALRM,(void(*)())ftimeout);
- X ultstr(0,(unsigned long)uid,buf);
- X chp2=fromwhom?
- X fromwhom:!passinvk||!*passinvk->pw_name?buf:passinvk->pw_name;
- X ;{ time_t t;
- X t=time((time_t*)0);startchar=ctime(&t); /* the current time */
- X }
- X strncpy(buf2,chp2,i=linebuf-strlen(startchar)-2);buf2[i]='\0';
- X strcat(strcat(buf2," "),startchar);
- X thebody=themail=
- X malloc((tobesent=STRLEN(From_)+strlen(buf2))+STRLEN(From_));
- X filled=0;
- X if(Deliverymode||fromwhom) /* do we need to peek for a leading From_ ? */
- X { int r; /* skip garbage */
- X while(1==(r=rread(STDIN,themail,1))&&*themail=='\n');
- X if(STRLEN(From_)-1==(i=rread(STDIN,themail+1,STRLEN(From_)-1))&&
- X eqFrom_(themail)) /* is it a From_ line? */
- X { if(fromwhom||!Privileged)
- X { char a;
- X while(1==rread(STDIN,&a,1)&&a!='\n'); /* discard From_ line */
- X i=0;goto Frominserted;
- X }
- X filled=STRLEN(From_); /* leave the From_ line alone */
- X }
- X else /* move the read-ahead text beyond our From_ line */
- X { tmemmove(themail+tobesent,themail,i=r<=0?0:i>0?i+1:1);
- X strcpy(themail,From_); /* insert From_ of our own */
- XFrominserted:
- X tmemmove(themail+STRLEN(From_),buf2,tobesent-STRLEN(From_));
- X filled=tobesent+i;
- X }
- X }
- X readmail(0,0L); /* read in the mail completely */
- X if(Deliverymode)
- X do
- X { chp2=chp;
- X#ifndef NO_USER_TO_LOWERCASE_HACK
- X for(;*chp;chp++) /* kludge recipient into lowercase */
- X if((unsigned)*chp-'A'<='Z'-'A')
- X *chp+='a'-'A'; /* because getpwnam might be case sensitive */
- X#endif
- X if(argv[++argc]) /* more than one recipient */
- X if(pidchild=sfork())
- X { if(forkerr(pidchild,procmailn)||waitfor(pidchild)!=EX_OK)
- X retvl2=retval;
- X pidchild=0; /* loop for the next recipient */
- X }
- X else
- X { thepid=getpid();
- X while(argv[++argc]); /* skip till end of command line */
- X }
- X }
- X while(chp=(char*)argv[argc]);
- X gargv=argv+argc; /* save it for nextrcfile() */
- X if(Deliverymode)
- X { if(!(pass=getpwnam(chp2)))
- X { nlog("Unknown user");logqnl(chp2);return EX_NOUSER;
- X }
- X if(passinvk&&passinvk->pw_uid==pass->pw_uid||euid==ROOT_uid)
- X goto Setuser;
- X }
- X if(pass=passinvk)
- XSetuser:
- X /*
- X * set preferred uid to the intended recipient
- X */
- X { gid=pass->pw_gid;uid=pass->pw_uid;setdef(home,pass->pw_dir);
- X setdef(lgname,chp= *pass->pw_name?pass->pw_name:buf);
- X if(euid==ROOT_uid)
- X initgroups(chp,gid);
- X endgrent();setdef(shell,*pass->pw_shell?pass->pw_shell:binsh);
- X }
- X else /* user could not be found, set reasonable defaults */
- X /*
- X * to prevent security holes, drop any privileges now
- X */
- X { setdef(home,RootDir);setdef(lgname,buf);setdef(shell,binsh);
- X setgid(gid);setuid(uid);
- X }
- X endpwent();
- X }
- X setdef(orgmail,systm_mbox);setdef(shellmetas,DEFshellmetas);
- X setdef(shellflags,DEFshellflags);setdef(maildir,DEFmaildir);
- X setdef(fdefault,DEFdefault);setdef(sendmail,DEFsendmail);
- X setdef(lockext,DEFlockext);setdef(msgprefix,DEFmsgprefix);
- X ;{ const char*const*kp;
- X for(kp=prestenv;*kp;) /* preset or wipe selected environment variables */
- X strcpy((char*)(sgetcp=buf2),*kp++),readparse(buf,sgetc,2),sputenv(buf);
- X }
- X strcpy(buf2,strcpy(buf,chp=(char*)getenv(orgmail)));
- X buf[i=lastdirsep(chp)-chp]='\0'; /* strip off the basename */
- X ;{ struct stat stbuf;
- X sgid=gid; /* presumed innocent */
- X /*
- X * do we need sgidness to access the mail-spool directory/files?
- X */
- X if(!stat(buf,&stbuf))
- X { if((uid!=stbuf.st_uid&&stbuf.st_gid==getegid()||(rc=rc_NOSGID,0))&&
- X (stbuf.st_mode&(S_IWGRP|S_IXGRP|S_IWOTH))==(S_IWGRP|S_IXGRP))
- X { umask(INIT_UMASK&~S_IRWXG);goto keepgid; /* group-writeable */
- X }
- X else if(stbuf.st_mode&S_ISGID)
- Xkeepgid: sgid=stbuf.st_gid; /* keep the gid from the parent directory */
- X }
- X /*
- X * check if the default-mailbox-lockfile is owned by the recipient, if
- X * not, mark it for further investigation, it might need to be removed
- X */
- X if(!(Privileged=lstat(strcat(buf2,getenv(lockext)),&stbuf)||
- X stbuf.st_uid==uid)) /* check for bogus lockfiles */
- X ultoan((unsigned long)stbuf.st_ino, /* i-node numbered */
- X strchr(strcpy(buf+i,BOGUSprefix),'\0'));
- X /*
- X * check if the original/default mailbox of the recipient exists, if it
- X * does, perform some security checks on it (check if it's a regular
- X * file, check if it's owned by the recipient), if something is wrong
- X * try and move the bogus mailbox out of the way, create the
- X * original/default mailbox file, and chown it to the recipient
- X */
- X if(lstat(chp,&stbuf)) /* stat the mailbox */
- X { succeed= -(errno==EACCES);goto boglock;
- X }
- X if(!Privileged&&!(stbuf.st_mode&S_IWGRP)) /* lockfile unrightful owner */
- X { succeed=1;
- Xboglock:
- X if(!Privileged) /* try to rename the bogus lockfile out of the way */
- X rename(buf2,buf);
- X }
- X else
- X succeed=1; /* mailbox a symbolic link? */
- X if(succeed>0||succeed<0&&(setgid(gid),setuid(uid),!lstat(chp,&stbuf)))
- X if(!(stbuf.st_mode&S_IWUSR)||S_ISLNK(stbuf.st_mode)||
- X (S_ISDIR(stbuf.st_mode)?!(stbuf.st_mode&S_IXUSR):stbuf.st_nlink!=1))
- X goto bogusbox; /* we only deliver to real files (security) */
- X else if(stbuf.st_uid!=uid) /* the recipient doesn't own it */
- Xbogusbox: /* bogus mailbox found! */
- X { ultoan((unsigned long)stbuf.st_ino, /* i-node numbered */
- X strchr(strcpy(buf+i,BOGUSprefix),'\0'));
- X if(rename(chp,buf)) /* try and move it out of the way */
- X goto fishy; /* couldn't rename, something is fishy here */
- X } /* SysV type autoforwarding? */
- X else if(Deliverymode&&stbuf.st_mode&(S_ISGID|S_ISUID))
- X { nlog("Autoforwarding mailbox found\n");return EX_NOUSER;
- X }
- X else
- X goto notfishy; /* everything is fine */
- X if(!xcreat(chp,NORMperm,(time_t*)0,&i)) /* try and create the mailbox */
- X if(i) /* could we chown it? */
- X unlink(chp); /* no we couldn't, NFS-mount or not root */
- X else
- X goto notfishy; /* yes we could, fine, proceed */
- X setgid(gid);setuid(uid); /* try some magic */
- X if(xcreat(chp,NORMperm,(time_t*)0,(int*)0)) /* try to create it again */
- Xfishy: /* bad news, be conservative */
- X nlog("Couldn't create"),logqnl(chp),sputenv(orgmail),sputenv(fdefault);
- Xnotfishy:
- X umask(INIT_UMASK);
- X }
- X suppmunreadable=!verbose;
- X if(!Deliverymode) /* not explicit delivery mode */
- X /*
- X * really change the uid now, since we are not in explicit
- X * delivery mode
- X */
- X { setgid(gid);setuid(uid);
- X if(suppmunreadable=nextrcfile()) /* any rcfile on the command-line? */
- X#ifndef NO_COMSAT
- X if(!getenv(scomsat))
- X setdef(scomsat,DEFcomsat) /* turn off comsat by default */
- X#endif
- X ;
- X while(chp=(char*)argv[argc]) /* interpret command line specs first */
- X argc++,asenvcpy(chp);
- X }
- X do /* main rcfile interpreter loop */
- X { alarm((unsigned)(alrmtime=0)); /* reset timeout */
- X if(rc<0) /* open new rc file */
- X { struct stat stbuf;
- X /*
- X * if we happen to be still running as root, and the rcfile
- X * is mounted on a secure NFS-partition, we might not be able
- X * to access it, so check if we can stat it or don't need any
- X * sgid privileges, if yes, drop all privs and set uid to
- X * the recipient beforehand
- X */
- X goto findrc;
- X do
- X { if(suppmunreadable) /* should we supress this message? */
- Xfake_rc: readerr(buf);
- X if(!nextrcfile()) /* not available? try the next */
- X goto nomore_rc;
- Xfindrc: suppmunreadable=i=0; /* should we keep the current directory? */
- X if(strchr(dirsep,*rcfile)|| /* absolute path? */
- X *rcfile==chCURDIR&&strchr(dirsep,rcfile[1])&&(i=1)) /* ./ prefix */
- X *buf='\0'; /* do not put anything in front then */
- X else
- X cat(tgetenv(home),MCDIRSEP); /* prepend $HOME directory */
- X if(stat(strcat(buf,rcfile),&stbuf)? /* accessible? */
- X rc==rc_NOSGID:stbuf.st_mode&S_IRUSR) /* and owner-readable? */
- X setgid(gid),setuid(uid); /* then transmogrify */
- X }
- X while(0>bopen(buf)); /* try opening the rcfile */
- X if(i&&!didchd) /* opened rcfile in the current directory? */
- X { didchd=1;*(chp=strcpy(buf2,maildir)+STRLEN(maildir))='=';
- X *++chp=chCURDIR;*++chp='\0';sputenv(buf2);
- X }
- X /*
- X * OK, so now we have opened an rcfile, but for security reasons
- X * we only accept it if it is owned by the recipient or if the
- X * the directory it is in, is not world writeable
- X */
- X i= *(chp=lastdirsep(buf));
- X if(lstat(buf,&stbuf)||
- X (stbuf.st_uid!=uid&&(*chp='\0',stat(buf,&stbuf)||
- X (stbuf.st_mode&(S_IWOTH|S_IXOTH))==(S_IWOTH|S_IXOTH))))
- X { *chp=i;rclose(rc);nlog("Suspicious rcfile\n");goto fake_rc;
- X }
- X /*
- X * set uid back to recipient in any case, since we might just
- X * have opened his/her .procmailrc (don't remove these, since
- X * the rcfile might have been created after the first stat)
- X */
- X *chp=i;yell("Rcfile:",buf);succeed=lastcond=0;setgid(gid);setuid(uid);
- X firstchd();
- X }
- X unlock(&loclock); /* unlock any local lockfile */
- X do skipspace(); /* skip whitespace */
- X while(testb('\n'));
- X if(testb(':')) /* check for a recipe */
- X { int locknext;
- X ;{ int nrcond;
- X readparse(buf,getb,0);nrcond=strtol(buf,&chp,10);
- X if(chp==buf) /* no number parsed */
- X nrcond= -1;
- X if(tolock) /* clear temporary buffer for lockfile name */
- X free(tolock);
- X for(i=maxindex(flags);flags[i]=0,i--;); /* clear the flags */
- X for(tolock=0,locknext=0;;)
- X { chp=skpspace(chp);
- X switch(i= *chp++)
- X { default:
- X if(!(chp2=strchr(exflags,i))) /* check for a valid flag */
- X { chp--;break;
- X }
- X flags[chp2-exflags]=1; /* set the flag */
- X case '\0':
- X if(*chp!=TMNATE) /* if not the real end, skip */
- X continue;
- X break;
- X case ':':locknext=1; /* yep, local lockfile specified */
- X if(*chp||*++chp!=TMNATE)
- X tolock=tstrdup(chp),chp=strchr(chp,'\0')+1;
- X }
- X concatenate(chp);skipped(chp);break; /* display any leftovers */
- X }
- X if(nrcond<0) /* assume the appropriate default nr of conditions */
- X nrcond=!flags[ALSO_NEXT_RECIPE]&&!flags[ALSO_N_IF_SUCC];
- X startchar=themail;tobesent=thebody-themail;
- X if(flags[BODY_GREP]) /* what needs to be egrepped? */
- X if(flags[HEAD_GREP])
- X tobesent=filled;
- X else
- X { startchar=thebody;tobesent=filled-tobesent;goto noconcat;
- X }
- X concon(' ');
- Xnoconcat: i=flags[ALSO_NEXT_RECIPE]?lastcond:1; /* init test value */
- X if(flags[ALSO_N_IF_SUCC])
- X i=lastcond&&succeed; /* only if the last recipe succeeded */
- X while(nrcond--) /* any conditions (left) */
- X { skipspace();getlline(buf2);
- X for(chp=strchr(buf2,'\0');--chp>=buf2;)
- X { switch(*chp) /* strip off whitespace at the end */
- X { case ' ':case '\t':*chp='\0';continue;
- X }
- X break;
- X }
- X if(i) /* check out all conditions */
- X { int negate=0;
- X for(chp=buf2+1;;strcpy(buf2,buf))
- X { switch(*(sgetcp=buf2))
- X { default:chp--; /* no special character, backup */
- X case '\\':
- X { int or_nocase; /* case-distinction override */
- X static const struct {const char*regkey,*regsubst;}
- X *regsp,regs[]=
- X { {FROMDkey,FROMDsubstitute},
- X {TOkey,TOsubstitute},
- X {0,0}
- X };
- X ;{ char*tg;
- X for(or_nocase=0,tg=chp2=chp;;tg++,chp2++)
- X { switch(*tg= *chp2)
- X { case '\n':
- X if(or_nocase==1)
- X tg-=2; /* throw out \ \n pairs */
- X or_nocase=2;continue;
- X case '\\':or_nocase=1;continue;
- X case ' ':case '\t':
- X if(or_nocase==2) /* skip leading */
- X { tg--;continue; /* whitespace */
- X }
- X default:or_nocase=0;continue;
- X case '\0':;
- X }
- X break;
- X }
- X }
- X or_nocase=0;goto jinregs;
- X do /* find special keyword in regexp */
- X if((chp2=strstr(chp,regsp->regkey))&&
- X (chp2==buf2||chp2[-1]!='\\')) /* not escaped? */
- X { size_t lregs,lregk;
- X lregk=strlen(regsp->regkey); /* shove it in */
- X tmemmove(chp2+(lregs=strlen(regsp->regsubst)),
- X chp2+lregk,strlen(chp2)-lregk+1);
- X tmemmove(chp2,regsp->regsubst,lregs);
- X if(regsp==regs) /* check for daemon regexp */
- X or_nocase=1; /* no case sensitivity! */
- Xjinregs: regsp=regs; /* start over and look again */
- X }
- X else
- X regsp++; /* next keyword */
- X while(regsp->regkey);
- X i=!!egrepin(chp,startchar,tobesent, /* egrep it */
- X or_nocase?0:flags[DISTINGUISH_CASE]);
- X break;
- X }
- X case '$':*buf2='"';readparse(buf,sgetc,2);continue;
- X case '!':negate^=1;strcpy(buf,chp);continue;
- X case '?':pwait=2;metaparse(chp);inittmout(buf);
- X ignwerr=1;i=!pipin(buf,startchar,tobesent);
- X strcpy(buf2,buf);break;
- X case '>':case '<':readparse(buf,sgetc,2);
- X i=strtol(buf+1,&chp,10);
- X i='<'==*buf?filled<i:filled>i;skipped(skpspace(chp));
- X strcpy(buf2,buf); /* leftovers */
- X }
- X break;
- X }
- X i^=negate;
- X if(verbose) /* not entirely correct, but it will do */
- X { nlog(i?"M":"No m");elog("atch on");
- X if(negate)
- X elog(" !");
- X logqnl(buf2);
- X }
- X }
- X }
- X }
- X if(!flags[ALSO_NEXT_RECIPE]&&!flags[ALSO_N_IF_SUCC])
- X lastcond=i; /* save the outcome for posterity */
- X startchar=themail;tobesent=filled; /* body, header or both? */
- X if(flags[PASS_HEAD])
- X { if(!flags[PASS_BODY])
- X tobesent=thebody-themail;
- X }
- X else if(flags[PASS_BODY])
- X tobesent-=(startchar=thebody)-themail;
- X chp=strchr(strcpy(buf,tgetenv(sendmail)),'\0');succeed=sh=0;
- X pwait=flags[WAIT_EXIT]|flags[WAIT_EXIT_QUIET]<<1;asgnlastf=1;
- X ignwerr=flags[IGNORE_WRITERR];Stdout=0;skipspace();
- X if(i)
- X concon('\n');
- Xprogrm: if(testb('!')) /* forward the mail */
- X { readparse(chp+1,getb,0);
- X if(i)
- X goto forward;
- X }
- X else if(testb('|')) /* pipe the mail */
- X { getlline(buf2); /* get the command to start */
- X if(i)
- X { metaparse(buf2);
- Xforward: if(locknext)
- X { if(!tolock) /* an explicit lockfile specified already */
- X { *buf2='\0'; /* find the implicit lockfile ('>>name') */
- X for(chp=buf;i= *chp++;)
- X if(i=='>'&&*chp=='>')
- X { chp=pstrspn(chp+1," \t");
- X tmemmove(buf2,chp,i=strcspn(chp,EOFName));
- X buf2[i]='\0';
- X if(sh) /* expand any environment variables */
- X { chp=tstrdup(buf);sgetcp=buf2;
- X readparse(buf,sgetc,0);strcpy(buf2,buf);
- X strcpy(buf,chp);free(chp);
- X }
- X break;
- X }
- X if(!*buf2)
- X { nlog("Couldn't determine implicit lockfile from");
- X logqnl(buf);
- X }
- X }
- X lcllock();
- X if(!pwait) /* try and protect the user from his */
- X pwait=2; /* blissful ignorance :-) */
- X }
- X inittmout(buf);
- X if(flags[FILTER])
- X { if(startchar==themail&&tobesent!=filled) /* if only 'h' */
- X { if(!pipthrough(buf,startchar,tobesent))
- X succeed=1,readmail(1,tobesent);
- X }
- X else if(!pipthrough(buf,startchar,tobesent))
- X succeed=1,filled=startchar-themail,readmail(0,0L);
- X }
- X else if(Stdout) /* capturing stdout again? */
- X { if(!pipthrough(buf,startchar,tobesent))
- X succeed=1,postStdout(); /* only parse if no errors */
- X }
- X else if(!pipin(buf,startchar,tobesent)&& /* regular program */
- X (succeed=1,!flags[CONTINUE]))
- X goto mailed;
- X }
- X }
- X else /* dump the mail into a mailbox file or directory */
- X { if(flags[FILTER])
- X flags[FILTER]=0,nlog("Extraneous filter-flag ignored\n");
- X if(chp=gobenv(buf)) /* can it be an environment name? */
- X { if(skipspace())
- X chp++; /* keep pace with argument breaks */
- X if(testb('=')) /* is it really an assignment? */
- X { int c;
- X *chp++='=';*chp='\0';
- X if(skipspace())
- X chp++;
- X ungetb(c=getb());
- X switch(c)
- X { case '!':case '|': /* ok, it's a pipe */
- X if(i)
- X primeStdout();
- X goto progrm;
- X }
- X }
- X }
- X else
- X chp=strchr(buf,'\0'); /* find the end */
- X readparse(chp,getb,0);concatenate(chp=strchr(buf,'\0')+1);
- X skipped(chp); /* report any leftovers */
- X if(i)
- X { strcpy(buf2,buf);
- X if(locknext)
- X lcllock();
- X strcpy(buf2,buf); /* write to a file or directory */
- X if(dump(deliver(buf2),startchar,tobesent)&&!ignwerr)
- X writeerr(buf);
- X else if(succeed=1,!flags[CONTINUE])
- X goto mailed;
- X }
- X }
- X }
- X else if(testb('#')) /* no comment :-) */
- X getbl(buf);
- X else /* then it must be an assignment */
- X { if(!(chp=gobenv(buf)))
- X { if(!*buf) /* skip a word first */
- X getbl(buf); /* then a line */
- X skipped(buf);continue; /* display leftovers */
- X }
- X skipspace();
- X if(testb('=')) /* removal or assignment? */
- X *chp='=',readparse(++chp,getb,1);
- X else
- X *++chp='\0'; /* throw in a second terminator */
- X sputenv(buf);chp[-1]='\0';asenv(chp);
- X }
- X }
- X while(rc<0||!testb(EOF)||poprc()); /* main interpreter loop */
- Xnomore_rc:
- X concon('\n');succeed=0;
- X if(*(chp=(char*)tgetenv(fdefault))) /* DEFAULT set? */
- X { setuid(uid);firstchd();asenvcpy(DEFdefaultlock); /* implicit lock */
- X if(dump(deliver(chp),themail,filled)) /* default */
- X writeerr(buf);
- X else
- X succeed=1;
- X }
- X if(!succeed&&*(chp=(char*)tgetenv(orgmail))) /* if all else failed */
- X if(dump(deliver(chp),themail,filled)) /* don't panic, try the last */
- X writeerr(buf); /* resort */
- X else
- X succeed=1;
- X if(succeed) /* should we panic now? */
- Xmailed:
- X retval=EX_OK; /* we're home free, mail delivered */
- X unlock(&loclock);terminate();
- X}
- X
- XeqFrom_(a)const char*const a;
- X{ return!strncmp(a,From_,STRLEN(From_));
- X}
- END_OF_FILE
- if test 23640 -ne `wc -c <'procmail280/src/procmail.c'`; then
- echo shar: \"'procmail280/src/procmail.c'\" unpacked with wrong size!
- fi
- # end of 'procmail280/src/procmail.c'
- fi
- echo shar: End of archive 10 \(of 11\).
- cp /dev/null ark10isdone
- 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
-
- "Be spontaneous!"
-
- exit 0 # Just in case...
-