#ifdef RCS
static char rcsid[]=
"$Id: cstdio.c,v 1.52 2000/11/22 01:29:56 guenther Exp $";
#endif
#include "procmail.h"
#include "robust.h"
#include "misc.h"
#include "lmtp.h"
#include "variables.h"
#include "shell.h"
#include "cstdio.h"
static uchar rcbuf[STDBUF],*rcbufp,*rcbufend;
static off_t blasttell;
static struct dyna_array inced;
struct dynstring*incnamed;
static void refill(offset)const int offset;
{ int ret=rread(rc,rcbuf,STDBUF);
if(ret>0)
{ rcbufend=rcbuf+ret;
rcbufp=rcbuf+offset;
}
else
{ rcbufend=rcbuf;
rcbufp=rcbuf+1;
}
}
void pushrc(name)const char*const name;
{ if(*name&&strcmp(name,devnull))
{ struct stat stbuf;
if(stat(name,&stbuf)||!S_ISREG(stbuf.st_mode))
goto rerr;
if(stbuf.st_size)
{ app_vali(inced,rcbufp?rcbufp-rcbuf:0);
app_valo(inced,blasttell);app_vali(inced,ifdepth);
app_vali(inced,rc);
ifdepth=ifstack.filled;
if(bopen(name)<0)
{ poprc();
rerr: readerr(name);
}
}
}
}
void changerc(name)const char*const name;
{ if(!*name||!strcmp(name,devnull))
pr:{ ifstack.filled=ifdepth;
rclose(rc);rcbufp=rcbufend+1;
return;
}
if(!strcmp(name,incnamed->ename))
lseek(rc,0,SEEK_SET),refill(0);
else
{ struct stat stbuf;int orc;uchar*orbp,*orbe;struct dynstring*dp;
if(stat(name,&stbuf)||!S_ISREG(stbuf.st_mode))
rerr: { readerr(name);
return;
}
if(!stbuf.st_size)
goto pr;
if(orbp=rcbufp,orbe=rcbufend,orc=rc,bopen(name)<0)
{ rcbufp=orbp;rcbufend=orbe;rc=orc;
goto rerr;
}
rclose(orc);
if(dp=incnamed->enext)
incnamed->enext=dp->enext,free(dp);
}
ifstack.filled=ifdepth;
}
void duprcs P((void))
{ size_t i;struct dynstring*dp;
dp=incnamed;rclose(rc);
if(0>(rc=ropen(dp->ename,O_RDONLY,0)))
goto dupfailed;
lseek(rc,blasttell+STDBUF,SEEK_SET);
for(i=inced.filled;dp=dp->enext,i;i-=3)
{ int fd;
rclose(acc_vali(inced,--i));
if(0>(fd=ropen(dp->ename,O_RDONLY,0)))
dupfailed:
nlog("Lost"),logqnl(dp->ename),exit(EX_NOINPUT);
acc_vali(inced,i)=fd;
}
}
static void closeonerc P((void))
{ struct dynstring*last;
if(rc>=0)
rclose(rc),rc= -1,last=incnamed,incnamed=last->enext,free(last);
}
int poprc P((void))
{ closeonerc();
if(ifstack.filled>ifdepth)
ifstack.filled=ifdepth,nlog("Missing closing brace\n");
if(!inced.filled)
return 0;
rc=acc_vali(inced,--inced.filled);
ifdepth=acc_vali(inced,--inced.filled);
blasttell=lseek(rc,acc_valo(inced,--inced.filled),SEEK_SET);
refill(acc_vali(inced,--inced.filled));
return 1;
}
void closerc P((void))
{ while(closeonerc(),inced.filled)
rc=acc_vali(inced,inced.filled-1),inced.filled-=4;
ifstack.filled=ifdepth=0;
}
int bopen(name)const char*const name;
{ rcbufp=rcbufend=0;rc=ropen(name,O_RDONLY,0);
if(rc>=0)
{ char*md;size_t len;
if(!strchr(dirsep,*name)&&
*(md=(char*)tgetenv(maildir))&&
strchr(dirsep,*md)&&
(len=strlen(md))+strlen(name)+2<linebuf)
{ strcpy(buf2,md);*(md=buf2+len)= *dirsep;strcpy(++md,name);
md=buf2;
}
else
md=(char*)name;
newdynstring(&incnamed,md);
}
return rc;
}
int getbl(p,end)char*p,*end;
{ int i,overflow=0;char*q;
for(q=p,end--;;)
{ switch(i=getb())
{ case '\n':case EOF:*q='\0';
return overflow?-1:p!=q;
}
if(q==end)
q=p,overflow=1;
*q++=i;
}
}
int getb P((void))
{ if(rcbufp==rcbufend)
blasttell=tell(rc),refill(0);
return rcbufp<rcbufend?(int)*rcbufp++:EOF;
}
void ungetb(x)const int x;
{ if(x!=EOF)
rcbufp--;
}
int testB(x)const int x;
{ int i;
if((i=getb())==x)
return 1;
ungetb(i);
return 0;
}
int sgetc P((void))
{ return *sgetcp?(int)*(uchar*)sgetcp++:EOF;
}
int skipspace P((void))
{ int any=0;
while(testB(' ')||testB('\t'))
any=1;
return any;
}
void skipline P((void))
{ for(;;)
switch(getb())
{ default:
continue;
case '\n':case EOF:
return;
}
}
int getlline(target,end)char*target,*end;
{ char*chp2;int overflow;
for(overflow=0;;*target++='\n')
switch(getbl(chp2=target,end))
{ case -1:overflow=1;
case 1:
if(*(target=strchr(target,'\0')-1)=='\\')
{ if(chp2!=target)
target++;
if(target>end-2)
target=end-linebuf,overflow=1;
continue;
}
case 0:
if(overflow)
{ nlog(exceededlb);setoverflow();
}
return overflow;
}
}
#ifdef LMTP
static int origfd= -1;
void pushfd(fd)int fd;
{ origfd=rc;rc=fd;
rcbufend=rcbufp;
}
static int popfd P((void))
{ rclose(rc);rc=origfd;
if(0>origfd)
return 0;
origfd= -1;
return 1;
}
int endoread P((void))
{ return rcbufp>=rcbufend;
}
void refillL P((void))
{ int retcode;
refill(0);
if(rcbufp>=rcbufend)
{ if(popfd())
{ refill(0);
if(rcbufp<rcbufend)
{ if((retcode=waitfor(childserverpid))==EXIT_SUCCESS)
return;
syslog(LOG_WARNING,"LMTP child failed: exit code %d",retcode);
exit(EX_SOFTWARE);
}
}
exit(EX_NOINPUT);
}
}
int getL P((void))
{ if(rcbufp==rcbufend)
refillL();
return (int)*rcbufp++;
}
int readL(p,len)char*p;const int len;
{ size_t min;
if(rcbufp==rcbufend)
refillL();
min=rcbufend-rcbufp;
if(min>len)
min=len;
tmemmove(p,rcbufp,min);
rcbufp+=min;
return min;
}
int readLe(p,len)char*p;int len;
{ long got=rcbufend-rcbufp;
if(got>0)
{ if(got>len)
got=len;
tmemmove(p,rcbufp,got);
rcbufp+=got;
p+=got;len-=got;
}
while(len)
{ if(0>(got=rread(rc,p,len)))
return -1;
if(!got&&!popfd())
return 0;
p+=got;len-=got;
}
return 1;
}
#endif