#ifdef RCS
static char rcsid[]=
"$Id: formail.c,v 1.102 2001/08/04 07:07:43 guenther Exp $";
#endif
static char rcsdate[]="$Date: 2001/08/04 07:07:43 $";
#include "includes.h"
#include <ctype.h>
#include "formail.h"
#include "acommon.h"
#include "sublib.h"
#include "shell.h"
#include "common.h"
#include "fields.h"
#include "ecommon.h"
#include "formisc.h"
#include "../patchlevel.h"
#define ssl(str) str,STRLEN(str)
#define bsl(str) {ssl(str)}
#define sslbar(str,bar1,bar2) {ssl(str),STRLEN(bar1)-1,STRLEN(bar2)-1}
static const char
#define X(name,value) name[]=value,
#include "header.h"
#undef X
From_[]= FROM,
Article_[]= "Article ",
x_[]= "X-",
old_[]= OLD_PREFIX,
xloop[]= "X-Loop:",
Resent_[]= "Resent-",
mdaemon[]="<>",unknown[]=UNKNOWN,re[]=" Re:",fmusage[]=FM_USAGE;
static const struct {const char*hedr;int lnr;}cdigest[]=
{
#define X(name,value) bsl(name),
#include "header.h"
#undef X
};
static const struct {const char*head;int len,wrepl,wrrepl;}sest[]=
{ sslbar(replyto ,"*********" ,"********" ),
sslbar(Fromm ,"**foo***" ,"**bar**" ),
sslbar(sender ,"*******" ,"******" ),
sslbar(res_replyto ,"*" ,"***********" ),
sslbar(res_from ,"*" ,"**********" ),
sslbar(res_sender ,"*" ,"*********" ),
sslbar(path ,"**" ,"*" ),
sslbar(retreceiptto ,"***" ,"**" ),
sslbar(errorsto ,"****" ,"***" ),
sslbar(returnpath ,"******" ,"*****" ),
sslbar(From_ ,"*****" ,"****" ),
};
static struct saved rex[]=
{ bsl(subject),bsl(references),bsl(messageid),bsl(date)
};
#define subj (rex+0)
#define refr (rex+1)
#define msid (rex+2)
#define hdate (rex+3)
#ifdef sMAILBOX_SEPARATOR
#define emboxsep smboxsep
#define MAILBOX_SEPARATOR
static const char smboxsep[]=sMAILBOX_SEPARATOR;
#endif
#ifdef eMAILBOX_SEPARATOR
#ifdef emboxsep
#undef emboxsep
#else
#define MAILBOX_SEPARATOR
#endif
static const char emboxsep[]=eMAILBOX_SEPARATOR;
#endif
const char binsh[]=BinSh,sfolder[]=FOLDER,
couldntw[]="Couldn't write to stdout",formailn[]=FORMAILN;
int errout,oldstdout,quiet=1,zap,buflast,lenfileno;
long initfileno;
char ffileno[LEN_FILENO_VAR+8*sizeof(initfileno)*4/10+1+1]=DEFfileno;
int lexitcode;
pid_t child= -1;
int childlimit;
unsigned long rhash;
FILE*mystdout;
int nrskip,nrtotal= -1,retval=EXIT_SUCCESS;
size_t buflen,buffilled;
long Totallen;
char*buf,*logsummary;
struct field*rdheader,*xheader,*Xheader,*uheader,*Uheader;
static struct field*iheader,*Iheader,*aheader,*Aheader,*Rheader,*nheader;
static int areply;
static void logfolder P((void))
{ size_t i;charNUM(num,Totallen);
static const char tabchar[]=TABCHAR;
if(logsummary)
{ putssn(sfolder,STRLEN(sfolder));putssn(logsummary,i=strlen(logsummary));
i+=STRLEN(sfolder);i-=i%TABWIDTH;
do putssn(tabchar,STRLEN(tabchar));
while((i+=TABWIDTH)<LENoffset);
ultstr(7,Totallen,num);putssn(num,strlen(num));putcs('\n');
}
}
static void renfield(pointer,oldl,newname,newl)struct field**const pointer;
size_t oldl;const size_t newl;const char*const newname;
{ struct field*p;size_t i;char*chp;
p= *pointer;(chp=p->fld_text)[p->Tot_len-1]='\0';
if(eqFrom_(chp))
for(;chp=strstr(chp,"\n>");*++chp=' ');
if(newl==STRLEN(From_)&&eqFrom_(newname))
{ for(chp=p->fld_text;chp=strchr(chp,'\n');)
if(*++chp==' '||*chp=='\t')
*chp='>';
for(chp=p->fld_text;chp=strstr(chp,"\n ");*++chp='>');
goto replaceall;
}
if(newname[newl-1]==HEAD_DELIMITER)
replaceall:
oldl=p->id_len;
p->id_len+=(int)newl-(int)oldl;p->fld_text[p->Tot_len-1]='\n';
p->Tot_len=(i=p->Tot_len-oldl)+newl;
if(newl>oldl)
*pointer=p=realloc(p,FLD_HEADSIZ+p->Tot_len);
chp=p->fld_text;tmemmove(chp+newl,chp+oldl,i);tmemmove(chp,newname,newl);
}
static void procfields(sareply)const int sareply;
{ struct field*fldp,**afldp;
fldp= *(afldp= &rdheader);
while(fldp)
{ struct field*fp2;
if(!sareply&&
(fp2=findf(fldp,&iheader))&&
!(areply&&fldp->id_len>=fp2->Tot_len-1))
{ renfield(afldp,(size_t)0,old_,STRLEN(old_));
goto fixfldp;
}
if((fp2=findf(fldp,&Iheader))&&
!(sareply&&fldp->id_len<fp2->Tot_len-1))
goto delfld;
if(fp2=findf(fldp,&Rheader))
{ renfield(afldp,fp2->id_len,(char*)fp2->fld_text+fp2->id_len,
fp2->Tot_len-fp2->id_len);
fixfldp:
fldp= *afldp;
}
;{ struct field*uf;
if((uf=findf(fldp,&uheader))&&!uf->fld_ref)
uf->fld_ref=afldp;
else if(fp2=findf(fldp,&Uheader))
{ if(fp2->fld_ref)
{ struct field**ch_afldp;
if(afldp==(ch_afldp= &(*fp2->fld_ref)->fld_next))
afldp=fp2->fld_ref;
for(fldp=Uheader;fldp;fldp=fldp->fld_next)
if(fldp->fld_ref==ch_afldp)
fldp->fld_ref=fp2->fld_ref;
delfield(fp2->fld_ref);
}
fp2->fld_ref=afldp;
}
else if(uf)
delfld: { fldp=delfield(afldp);
continue;
}
}
fldp= *(afldp= &(*afldp)->fld_next);
}
}
static int digheadr P((void))
{ char*chp;int i;size_t j;struct field*fp;
for(fp=rdheader;fp->fld_next;fp=fp->fld_next);
i=maxindex(cdigest);chp=fp->fld_text;j=fp->id_len;
while(chp[j-2]==' '||chp[j-2]=='\t')
j--;
while((cdigest[i].lnr!=j||strncasecmp(cdigest[i].hedr,chp,j-1))&&i--);
return i>=0||j>STRLEN(old_)&&!strncasecmp(old_,chp,STRLEN(old_))||
j>STRLEN(x_)&&!strncasecmp(x_,chp,STRLEN(x_));
}
static int artheadr P((void))
{ if(!rdheader&&!strncmp(buf,Article_,STRLEN(Article_)))
{ addbuf();rdheader->id_len=STRLEN(Article_);
return 1;
}
return 0;
}
static char*getsender(namep,fldp,headreply)char*namep;struct field*fldp;
const int headreply;
{ char*chp;int i,nowm;size_t j;static int lastm;
chp=fldp->fld_text;j=fldp->id_len;i=maxindex(sest);
while((sest[i].len!=j||strncasecmp(sest[i].head,chp,j))&&i--);
if(i>=0&&(i!=maxindex(sest)||fldp==rdheader))
{ char*saddr;char*tmp;
nowm=areply&&headreply?headreply==1?sest[i].wrepl:sest[i].wrrepl:i;chp+=j;
tmp=malloc(j=fldp->Tot_len-j);tmemmove(tmp,chp,j);(chp=tmp)[j-1]='\0';
if(sest[i].head==From_)
{ char*pastad;
if(strchr(saddr=chp,'\n'))
nowm-=2;
if(*saddr=='\n'&&(pastad=strchr(saddr,' ')))
saddr=pastad+1;
chp=saddr;
while((pastad=strchr(chp,'\n'))&&(pastad=strchr(pastad,' ')))
chp=pastad+1;
if(pastad=strchr(chp,' '))
{ char*savetmp;
savetmp=malloc(1+(j=pastad-chp)+1+1);tmemmove(savetmp,chp,j);
savetmp[j]='\0';
if(strchr(savetmp,'@'))
chp=savetmp,savetmp=tmp,tmp=chp;
else
{ static const char remf[]=" remote from ",fwdb[]=" forwarded by ";
char*p1,*p2;
chp=tmp;
for(;;)
{ int c;
p1=strstr(saddr,remf);
if(!(p2=strstr(saddr,fwdb))&&!p1)
break;
if(!p1||p2&&p2<p1)
p1=p2+STRLEN(fwdb);
else
p1+=STRLEN(remf);
for(;;)
{ switch(c= *p1++)
{ default:*chp++=c;
continue;
case '\0':case '\n':*chp++='!';
}
break;
}
saddr=p1;
}
strcpy(chp,savetmp);chp=tmp;
}
free(savetmp);savetmp=strchr(tmp,'\0');
tmemmove(tmp+1,tmp,savetmp-tmp);*tmp='<';savetmp[1]='\0';
}
}
while(*(chp=skpspace(chp))=='\n')
chp++;
for(saddr=0;;chp=skipwords(chp))
{ switch(*chp)
{ default:
if(!saddr)
saddr=chp;
continue;
case '<':skipwords(saddr=chp);
case '\0':;
}
break;
}
if(saddr)
{ if(*saddr)
{ if(!strpbrk(saddr,"@!/"))
nowm-=(maxindex(sest)+2)*4;
else if(strstr(saddr,".UUCP"))
nowm-=(maxindex(sest)+2)*3;
else if(strchr(saddr,'@')&&!strchr(saddr,'.'))
nowm-=(maxindex(sest)+2)*2;
else if(strchr(saddr,'!'))
nowm-=(maxindex(sest)+2)*1;
if(!namep||nowm>lastm)
goto pnewname;
}
else if(sest[i].head==returnpath)
{ saddr=(char*)mdaemon;nowm=maxindex(sest)+2;
pnewname: lastm=nowm;saddr=strcpy(malloc(strlen(saddr)+1),saddr);
if(namep)
free(namep);
namep=saddr;
}
}
free(tmp);
}
return namep;
}
static void elimdups(namep,idcache,maxlen,split)const char*const namep;
FILE*idcache;const long maxlen;const int split;
{ int dupid=0;char*key,*oldnewl;
key=(char*)namep;
if(!areply)
{ key=0;
if(msid->rexl)
*(oldnewl=(key=msid->rexp)+msid->rexl-1)='\0';
}
if(key)
{ long insoffs=maxlen;
while(*key==' ')
key++;
do
{ int j;char*p;
for(p=key;(j=fgetc(idcache))==*p;p++)
if(!j)
{ if(!quiet)
nlog("Duplicate key found:"),elog(key),elog("\n");
dupid=1;
goto dupfound;
}
if(!j)
{ if(p==key&&insoffs==maxlen)
{ insoffs=ftell(idcache)-1;
goto skiprest;
}
}
else
skiprest: for(;;)
{ switch(fgetc(idcache))
{ case EOF:
goto noluck;
default:
continue;
case '\0':;
}
break;
}
}
while(ftell(idcache)<maxlen);
noluck:
if(insoffs>=maxlen)
insoffs=0;
fseek(idcache,insoffs,SEEK_SET);fwrite(key,1,strlen(key)+1,idcache);
putc('\0',idcache);
dupfound:
fseek(idcache,(long)0,SEEK_SET);
if(!areply)
*oldnewl='\n';
}
if(!split)
exit(dupid?EXIT_SUCCESS:1);
if(dupid)
closemine(),opensink();
}
static PROGID;
int main(lastm,argv)int lastm;const char*const argv[];
{ int i,split=0,force=0,bogus=1,every=0,headreply=0,digest=0,nowait=0,keepb=0,
minfields=(char*)progid-(char*)progid,conctenate=0,babyl=0,babylstart,
berkeley=0,forgetclen;
long maxlen,ctlength;FILE*idcache=0;pid_t thepid;
size_t j,lnl,escaplen;char*chp,*namep,*escap=ESCAP;
struct field*fldp,*fp2,**afldp,*fdate,*fcntlength,*fsubject,*fFrom_;
if(lastm)
#define Qnext_arg() if(!*chp&&!(chp=(char*)*++argv))goto usg
while(chp=(char*)*++argv)
{ if((lastm= *chp++)==FM_SKIP)
goto number;
else if(lastm!=FM_TOTAL)
goto usg;
for(;;)
{ switch(lastm= *chp++)
{ case FM_TRUST:headreply|=1;
continue;
case FM_REPLY:areply=1;
continue;
case FM_FORCE:force=1;
continue;
case FM_EVERY:every=1;
continue;
case FM_BABYL:babyl=every=1;
case FM_DIGEST:digest=1;
continue;
case FM_NOWAIT:nowait=1;Qnext_arg();
childlimit=strtol(chp,&chp,10);
continue;
case FM_KEEPB:keepb=1;
continue;
case FM_CONCATENATE:conctenate=1;
continue;
case FM_ZAPWHITE:zap=1;
continue;
case FM_QUIET:quiet=1;
if(*chp=='-')
chp++,quiet=0;
continue;
case FM_LOGSUMMARY:Qnext_arg();
if(strlen(logsummary=chp)>MAXfoldlen)
chp[MAXfoldlen]='\0';
detab(chp);
break;
case FM_SPLIT:split=1;
if(!*chp)
{ ++argv;
goto parsedoptions;
}
goto usg;
case HELPOPT1:case HELPOPT2:elog(fmusage);elog(FM_HELP);
elog(FM_HELP2);
goto xusg;
case FM_DUPLICATE:case FM_MINFIELDS:Qnext_arg();chp++;
default:chp--;
number: if(*chp-'0'>(unsigned)9)
goto usg;
i=strtol(chp,&chp,10);
switch(lastm)
{ case FM_SKIP:nrskip=i;
break;
case FM_DUPLICATE:maxlen=i;Qnext_arg();
if(!(idcache=fopen(chp,"r+b"))&&
!(idcache=fopen(chp,"w+b")))
{ nlog("Couldn't open");logqnl(chp);
return EX_CANTCREAT;
}
goto nextarg;
case FM_MINFIELDS:minfields=i;
break;
default:nrtotal=i;
}
continue;
case FM_BOGUS:bogus=0;
continue;
case FM_BERKELEY:berkeley=1;
continue;
case FM_QPREFIX:Qnext_arg();escap=chp;
break;
case FM_VERSION:elog(formailn);elog(VERSION);
goto xusg;
case FM_ADD_IFNOT:case FM_ADD_ALWAYS:case FM_REN_INSERT:
case FM_DEL_INSERT:case FM_EXTRACT:case FM_EXTRC_KEEP:
case FM_FIRST_UNIQ:case FM_LAST_UNIQ:case FM_ReNAME:Qnext_arg();
i=breakfield(chp,lnl=strlen(chp));
switch(lastm)
{ case FM_ADD_IFNOT:
if(i>0)
break;
if(i!=-STRLEN(Resent_)||-i!=lnl||
strncasecmp(chp,Resent_,STRLEN(Resent_)+1))
goto invfield;
headreply|=2;
goto nextarg;
default:
if(-i!=lnl)
case FM_ADD_ALWAYS:
if(i<=0)
goto invfield;
case FM_ReNAME:;
}
chp[lnl]='\n';
afldp=addfield(lastm==FM_REN_INSERT?&iheader:
lastm==FM_DEL_INSERT?&Iheader:lastm==FM_ADD_IFNOT?&aheader:
lastm==FM_ADD_ALWAYS?&Aheader:lastm==FM_EXTRACT?&xheader:
lastm==FM_FIRST_UNIQ?&uheader:lastm==FM_LAST_UNIQ?&Uheader:
lastm==FM_EXTRC_KEEP?&Xheader:&Rheader,chp,++lnl);
if(lastm==FM_ReNAME)
{ int copied=0;
for(namep=(chp=(fldp= *afldp)->fld_text)+lnl,
chp+=lnl=fldp->id_len;chp<namep;++chp)
{ switch(*chp)
{ case ' ':case '\t':case '\n':
continue;
}
break;
}
lastm=i;
if((i=breakfield(chp,(size_t)(namep-chp)))<0)
if(lastm>0)
goto invfield;
else
i= -i;
if(i)
tmemmove((char*)fldp->fld_text+lnl,chp,i),copied=1;
else if(namep>chp||
!(chp=(char*)*++argv)||
(!(i=breakfield(chp,strlen(chp)))&&
*chp)||
i<=0&&(i= -i,lastm>0))
invfield: { nlog("Invalid field-name:");logqnl(chp?chp:"");
goto usg;
}
*afldp=fldp=
realloc(fldp,FLD_HEADSIZ+(fldp->Tot_len=lnl+i));
if(!copied)
tmemmove((char*)fldp->fld_text+lnl,chp,i);
}
case '\0':;
}
break;
}
nextarg:;
}
parsedoptions:
escaplen=strlen(escap);mystdout=stdout;signal(SIGPIPE,SIG_IGN);
#ifdef SIGCHLD
signal(SIGCHLD,SIG_DFL);
#endif
thepid=getpid();
if(babyl)
{ while(getchar()!=BABYL_SEP1||getchar()!=BABYL_SEP2||getchar()!='\n')
while(getchar()!='\n');
while(getchar()!='\n');
}
while((buflast=getchar())=='\n');
if(split)
{ char**ep;char**vfileno=0;
if(buflast==EOF)
return EXIT_SUCCESS;
for(ep=environ;*ep;ep++)
if(!strncmp(*ep,ffileno,LEN_FILENO_VAR))
vfileno=ep;
if(!vfileno)
{ size_t envlen;
envlen=(ep-environ+1)*sizeof*environ;
tmemmove(ep=malloc(envlen+sizeof*environ),environ,envlen);
*(vfileno=(char**)((char*)(environ=ep)+envlen))=0;*--vfileno=ffileno;
}
if((lenfileno=strlen(chp= *vfileno+LEN_FILENO_VAR))>
STRLEN(ffileno)-LEN_FILENO_VAR-1)
lenfileno=STRLEN(ffileno)-LEN_FILENO_VAR-1;
if((initfileno=strtol(chp,&chp,10))<0)
lenfileno--;
if(*chp)
lenfileno= -1;
else
*vfileno=ffileno;
oldstdout=dup(STDOUT);fclose(stdout);
if(!nrtotal)
goto onlyhead;
startprog((const char*Const*)argv);
if(!minfields)
minfields=DEFminfields;
}
else if(nrskip>0||nrtotal>=0||every||digest||minfields||nowait)
goto usg;
if((xheader||Xheader)&&logsummary||keepb&&!(areply||xheader||Xheader))
usg:
{ elog(fmusage);
xusg:
return EX_USAGE;
}
if(headreply==2)
{ chp=(char*)Resent_;
goto invfield;
}
buf=malloc(buflen=Bsize);Totallen=0;i=maxindex(rex);
do rex[i].rexp=malloc(1);
while(i--);
fdate=0;addfield(&fdate,date,STRLEN(date));
fcntlength=0;addfield(&fcntlength,cntlength,STRLEN(cntlength));
fFrom_=0;addfield(&fFrom_,From_,STRLEN(From_));
fsubject=0;addfield(&fsubject,subject,STRLEN(subject));
forgetclen=digest||
berkeley||
keepb&&
(areply||
Xheader&&
!findf(fcntlength,&Xheader));
if(areply)
addfield(&iheader,xloop,STRLEN(xloop));
if(!readhead())
{
#ifdef sMAILBOX_SEPARATOR
if(!strncmp(smboxsep,buf,STRLEN(smboxsep)))
{ buffilled=0;
goto startover;
}
#endif
if(digest&&artheadr())
goto startover;
}
else
startover:
while(readhead());
cleanheader();
;{ size_t lenparkedbuf;void*parkedbuf;int wasafrom_;
if(rdheader)
{ char*tmp,*tmp2;
if(!strncmp(tmp=(char*)rdheader->fld_text,Article_,STRLEN(Article_)))
tmp[STRLEN(Article_)-1]=HEAD_DELIMITER;
else if(babyl&&
!force&&
!strncmp(tmp,mailfrom,STRLEN(mailfrom))&&
eqFrom_(tmp2=skpspace(tmp+STRLEN(mailfrom))))
{ rdheader->id_len=STRLEN(From_);
tmemmove(tmp,tmp2,rdheader->Tot_len-=tmp2-tmp);
}
}
namep=0;Totallen=0;i=maxindex(rex);
do rex[i].rexl=0;
while(i--);
clear_uhead(uheader);clear_uhead(Uheader);
wasafrom_=!force&&rdheader&&eqFrom_(rdheader->fld_text);
procfields(areply);
for(fldp= *(afldp= &rdheader);fldp;)
{ if(zap)
{ chp=fldp->fld_text+(j=fldp->id_len);
if(chp[-1]==HEAD_DELIMITER)
if((*chp!=' '&&*chp!='\t')&&fldp->Tot_len>j+1)
{ chp=j+(*afldp=fldp=
realloc(fldp,FLD_HEADSIZ+(i=fldp->Tot_len++)+1))->fld_text;
tmemmove(chp+1,chp,i-j);*chp=' ';
}
else if(fldp->Tot_len<=j+2)
{ *afldp=fldp->fld_next;free(fldp);fldp= *afldp;
continue;
}
}
if(conctenate)
concatenate(fldp);
namep=getsender(namep,fldp,headreply);
i=maxindex(rex);chp=fldp->fld_text;j=fldp->id_len;
while((rex[i].lenr!=j||strncasecmp(rex[i].headr,chp,j))&&i--);
chp+=j;
if(i>=0&&(j=fldp->Tot_len-j)>1)
{ tmemmove(rex[i].rexp=realloc(rex[i].rexp,(rex[i].rexl=j)+1),chp,j);
rex[i].rexp[j]='\0';
}
fldp= *(afldp= &fldp->fld_next);
}
if(idcache)
elimdups(namep,idcache,maxlen,split);
ctlength=0;
if(!forgetclen&&(fldp=findf(fcntlength,&rdheader)))
{ *(chp=(char*)fldp->fld_text+fldp->Tot_len-1)='\0';
ctlength=strtol((char*)fldp->fld_text+STRLEN(cntlength),(char**)0,10);
*chp='\n';
}
tmemmove(parkedbuf=malloc(buffilled),buf,lenparkedbuf=buffilled);
buffilled=0;
if(areply)
{ for(fldp= *(afldp= &rdheader);fldp;)
if(!(fp2=findf(fldp,&iheader))||fp2->id_len<fp2->Tot_len-1)
*afldp=fldp->fld_next,free(fldp),fldp= *afldp;
else
fldp= *(afldp= &fldp->fld_next);
loadbuf(To,STRLEN(To));loadchar(' ');
if(namep)
loadbuf(namep,strlen(namep));
else
retval=EX_NOUSER,loadbuf(unknown,STRLEN(unknown));
loadchar('\n');addbuf();
if(subj->rexl)
{ loadbuf(subject,STRLEN(subject));
if(strncasecmp(skpspace(chp=subj->rexp),Re,STRLEN(Re)))
loadbuf(re,STRLEN(re));
loadsaved(subj);addbuf();
}
if(refr->rexl||msid->rexl)
{ loadbuf(references,STRLEN(references));
if(refr->rexl)
{ if(msid->rexl)
--refr->rexl;
loadsaved(refr);
}
if(msid->rexl)
loadsaved(msid);
addbuf();
}
if(msid->rexl)
loadbuf(inreplyto,STRLEN(inreplyto)),loadsaved(msid),addbuf();
procfields(0);
}
else if(!force&&
(!rdheader||!eqFrom_(rdheader->fld_text))&&
((fldp=findf(fFrom_,&aheader))&&STRLEN(From_)+1>=fldp->Tot_len||
!wasafrom_&&
!findf(fFrom_,&iheader)&&
!findf(fFrom_,&Iheader)&&
!findf(fFrom_,&Rheader)))
{ struct field*old;time_t t;
t=time((time_t*)0);old=rdheader;rdheader=0;
loadbuf(From_,STRLEN(From_));
if(namep)
loadbuf(namep,strlen(namep));
else
loadbuf(unknown,STRLEN(unknown));
loadchar(' ');
if(!hdate->rexl||!findf(fdate,&aheader))
loadchar(' '),chp=ctime(&t),loadbuf(chp,strlen(chp));
else
loadsaved(hdate);
addbuf();rdheader->fld_next=old;
}
for(fldp=aheader;fldp;fldp=fldp->fld_next)
if(!findf(fldp,&rdheader))
if(fldp->id_len+1>=fldp->Tot_len&&
(fldp->id_len==STRLEN(messageid)&&
!strncasecmp(fldp->fld_text,messageid,STRLEN(messageid))||
fldp->id_len==STRLEN(res_messageid)&&
!strncasecmp(fldp->fld_text,res_messageid,STRLEN(res_messageid))
))
{ char*p;const char*name;unsigned long h1,h2,h3;
static unsigned long h4;
h1=time((time_t*)0);h2=thepid;h3=rhash;
p=chp=malloc(fldp->id_len+2+((sizeof h1*8+5)/6+1)*4+
strlen(name=hostname())+2);
memcpy(p,fldp->fld_text,fldp->id_len);*(p+=fldp->id_len)=' ';
*++p='<';*(p=ultoan(h3,p+1))='.';*(p=ultoan(h4,p+1))='.';
*(p=ultoan(h2,p+1))='.';*(p=ultoan(h1,p+1))='@';strcpy(p+1,name);
*(p=strchr(p,'\0'))='>';*++p='\n';addfield(&nheader,chp,p-chp+1);
free(chp);h4++;
}
else
addfield(&nheader,fldp->fld_text,fldp->Tot_len);
if(logsummary)
{ if(eqFrom_(rdheader->fld_text))
putssn(rdheader->fld_text,rdheader->Tot_len);
if(fldp=findf(fsubject,&rdheader))
{ concatenate(fldp);(chp=fldp->fld_text)[i=fldp->Tot_len-1]='\0';
detab(chp);putcs(' ');
putssn(chp,i>=MAXSUBJECTSHOW?MAXSUBJECTSHOW:i);putcs('\n');
}
}
tmemmove(buf,parkedbuf,buffilled=lenparkedbuf);free(parkedbuf);
}
flushfield(&rdheader);flushfield(&nheader);dispfield(Aheader);
dispfield(iheader);dispfield(Iheader);
if(namep)
free(namep);
if(keepb||!(xheader||Xheader))
lputcs('\n');
if(!keepb&&(areply||xheader||Xheader))
{ logfolder();
if(split)
closemine();
else
goto onlyhead;
opensink();
}
lnl=1;
if(buffilled==1)
buffilled=0;
if(babyl)
{ int c,lc;
for(lc=0;c=getchar(),c!=EOF&&(c!='\n'||lc!='\n');lc=c);
buflast=c;babylstart=0;
}
if(ctlength>0)
{ if(buffilled)
lputssn(buf,buffilled),ctlength-=buffilled,buffilled=lnl=0;
;{ int tbl=buflast,lwr='\n';
while(--ctlength>=0&&tbl!=EOF)
lnl=lwr==tbl&&lwr=='\n',putcs(lwr=tbl),tbl=getchar();
if((buflast=tbl)=='\n'&&lwr!=tbl)
putcs('\n'),buflast=getchar();
}
if(!quiet&&ctlength>0)
{ charNUM(num,ctlength);
nlog(cntlength);elog(" field exceeds actual length by ");
ultstr(0,(unsigned long)ctlength,num);elog(num);elog(" bytes\n");
}
}
while(buffilled||!lnl||buflast!=EOF)
{ if(!buffilled)
readhead();
if(!babyl||babylstart)
{ if(rdheader)
{ if(eqFrom_(chp=rdheader->fld_text))
fromanyway: { register size_t k;
if(split&&
(lnl||every)&&
(k=strcspn(chp=skpspace(chp+STRLEN(From_))," \t\n"))&&
*skpspace(chp+k)!='\n')
goto accuhdr;
if(bogus)
lputssn(escap,escaplen);
}
else if(split&&digest&&(lnl||every)&&digheadr())
accuhdr: { for(i=minfields;--i&&readhead()&&digheadr(););
if(!i)
splitit: { if(!lnl)
lputcs('\n');
logfolder();
if(fclose(mystdout)==EOF||errout==EOF)
{ split= -1;
if(!quiet)
nlog(couldntw),elog(", continuing...\n");
}
if(!nowait&&*argv)
{ int excode;
if((excode=waitfor(child))!=EXIT_SUCCESS&&
retval==EXIT_SUCCESS)
retval=excode;
}
if(!nrtotal)
goto nconlyhead;
startprog((const char*Const*)argv);
goto startover;
}
}
}
else if(eqFrom_(buf))
{ addbuf();
goto fromanyway;
}
else if(split&&digest&&(lnl||every)&&artheadr())
goto accuhdr;
}
#ifdef MAILBOX_SEPARATOR
if(!strncmp(emboxsep,buf,STRLEN(emboxsep)))
{ if(split)
{ buffilled=0;
#ifdef sMAILBOX_SEPARATOR
getline();buffilled=0;
#endif
if(buflast!=EOF)
goto splitit;
break;
}
#ifdef eMAILBOX_SEPARATOR
if(buflast==EOF)
break;
#endif
if(bogus)
goto putsp;
}
else if(!strncmp(smboxsep,buf,STRLEN(smboxsep))&&bogus)
putsp: lputcs(' ');
#endif
lnl=buffilled==1;
if(babyl&&*buf==BABYL_SEP1)
babylstart=1,closemine(),opensink();
if(areply&&bogus)
if(fldp=rdheader)
{ register char*p;
rdheader=0;
do
{ fp2=fldp->fld_next;chp=fldp->fld_text;
do
{ lputssn(escap,escaplen);
if(p=memchr(chp,'\n',fldp->Tot_len))
p++;
else
p=(char*)fldp->fld_text+fldp->Tot_len;
lputssn(chp,p-chp);
}
while((chp=p)<(char*)fldp->fld_text+fldp->Tot_len);
free(fldp);
}
while(fldp=fp2);
}
else
{ if(buffilled>1)
lputssn(escap,escaplen);
goto flbuf;
}
else if(rdheader)
{ struct field*ox,*oX;
ox=xheader;oX=Xheader;xheader=Xheader=0;flushfield(&rdheader);
xheader=ox;Xheader=oX;
}
else
flbuf: lputssn(buf,buffilled),buffilled=0;
}
logfolder();
onlyhead:
closemine();
nconlyhead:
if(split)
{ int excode;
close(STDIN);
while((excode=waitfor((pid_t)0))!=NO_PROCESS)
if(retval==EXIT_SUCCESS&&excode!=EXIT_SUCCESS)
retval=excode;
}
if(retval<0)
retval=EX_UNAVAILABLE;
return retval!=EXIT_SUCCESS?retval:split<0?EX_IOERR:EXIT_SUCCESS;
}
int eqFrom_(a)const char*const a;
{ return !strncmp(a,From_,STRLEN(From_));
}
int breakfield(line,len)const char*const line;size_t len;
{ const char*p=line;
while(len)
{ switch(*p)
{ default:len--;
if(iscntrl(*p))
break;
p++;
continue;
case HEAD_DELIMITER:
len=p-line;
return len?len+1:0;
case ' ':case '\t':
if(p>line)
{ const char*q=++p;
while(--len&&(*q==' '||*q=='\t'))
q++;
if(len&&*q==HEAD_DELIMITER)
return q-line+1;
if(eqFrom_(line))
return STRLEN(From_);
}
}
break;
}
return -(int)(p-line);
}