#ifdef RCS
static char rcsid[]=
"$Id: variables.c,v 1.22 2001/08/27 08:53:15 guenther Exp $";
#endif
#include "procmail.h"
#include "acommon.h"
#include "common.h"
#include "cstdio.h"
#include "robust.h"
#include "shell.h"
#include "authenticate.h"
#include "goodies.h"
#include "misc.h"
#include "locking.h"
#include "comsat.h"
#include "sublib.h"
#include "variables.h"
struct varval strenvvar[]={{"LOCKSLEEP",DEFlocksleep},
{"LOCKTIMEOUT",DEFlocktimeout},{"SUSPEND",DEFsuspend},
{"NORESRETRY",DEFnoresretry},{"TIMEOUT",DEFtimeout},{"VERBOSE",DEFverbose},
{"LOGABSTRACT",DEFlogabstract}};
struct varstr strenstr[]={{"SHELLMETAS",DEFshellmetas},{"LOCKEXT",DEFlockext},
{"MSGPREFIX",DEFmsgprefix},{"TRAP",empty},
{"SHELLFLAGS",DEFshellflags},{"DEFAULT",DEFdefault},{"SENDMAIL",DEFsendmail},
{"SENDMAILFLAGS",DEFflagsendmail},{"PROCMAIL_VERSION",PM_VERSION}};
#define MAXvarvals maxindex(strenvvar)
#define MAXvarstrs maxindex(strenstr)
const char lastfolder[]="LASTFOLDER",maildir[]="MAILDIR",scomsat[]="COMSAT",
offvalue[]="no";
int didchd;
long Stdfilled;
char*Stdout;
static void asenvtext P((const char*const chp));
static const char slinebuf[]="LINEBUF",pmoverflow[]="PROCMAIL_OVERFLOW=yes",
exitcode[]="EXITCODE";
static int setxit;
static struct dynstring*myenv;
static char**lastenv;
const char*sputenv(a)const char*const a;
{ static int alloced;size_t eq,i;int remove;const char*split;char**preenv;
struct dynstring*curr,**last;
yell("Assigning",a);remove=0;
if(!(split=strchr(a,'=')))
remove=1,split=strchr(a,'\0');
eq=split-a;
for(curr= *(last= &myenv);curr;curr= *(last= &curr->enext))
if(!strncmp(a,curr->ename,eq)&&((char*)curr->ename)[eq]=='=')
{ split=curr->ename;*last=curr->enext;free(curr);
for(preenv=environ;*preenv!=split;preenv++);
goto wipenv;
}
for(preenv=environ;*preenv;preenv++)
if(!strncmp(a,*preenv,eq)&&(*preenv)[eq]=='=')
wipenv:
{ while(*preenv=preenv[1])
preenv++;
break;
}
i=(preenv-environ+2)*sizeof*environ;
if(alloced)
environ=realloc(environ,i);
else
alloced=1,environ=tmemmove(malloc(i),environ,i-sizeof*environ);
if(!remove)
{ for(preenv=environ;*preenv;preenv++);
preenv[1]=0;*(lastenv=preenv)=(char*)(split=newdynstring(&myenv,a));
return split+eq+1;
}
return empty;
}
void primeStdout(varname)const char*const varname;
{ if(!Stdout)
sputenv(varname);
Stdout=(char*)myenv;
Stdfilled=ioffsetof(struct dynstring,ename[0])+strlen(varname);
}
void retStdout(newmyenv,fail,unset)
char*const newmyenv;const int fail,unset;
{ char*var,*p;
if(fail&&unset)
{ myenv=((struct dynstring*)newmyenv)->enext;
free(newmyenv);*lastenv=Stdout=0;
return;
}
else if(!fail&&newmyenv[Stdfilled-1]=='\n')
Stdfilled--;
retbStdout(newmyenv);
var=newmyenv+ioffsetof(struct dynstring,ename[0]);
p=strchr(var,'=');
tmemmove(buf,var,p-var);
buf[p-var]='\0';
if(fail)
asenvtext(p+1);
else
asenv(p+1);
}
void retbStdout(newmyenv)char*const newmyenv;
{ newmyenv[Stdfilled]='\0';*lastenv=(myenv=(struct dynstring*)newmyenv)->ename;
Stdout=0;
}
void appendlastvar(value)const char*const value;
{ size_t len;char*p;
Stdout=(char*)value;primeStdout(empty);
len=Stdfilled+strlen(Stdout+Stdfilled);
p=realloc(Stdout,(Stdfilled=len+1+strlen(value))+1);
p[len]=' ';strcpy(p+len+1,buf);retbStdout(p);
}
const char*eputenv(src,dst)const char*const src;char*const dst;
{ sgetcp=src;
return readparse(dst,sgetc,2,0)?0:sputenv(buf);
}
void setdef(name,value)const char*const name,*const value;
{ char*p;
strcpy(buf,name);
p=strchr(buf,'\0');
*p++='=';
eputenv(value,p);
}
const char*tgetenv(a)const char*const a;
{ const char*b;
return (b=getenv(a))?b:empty;
}
void setoverflow P((void))
{ sputenv(pmoverflow);
}
void cleanupenv(preserve)int preserve;
{ static const char*const keepenv[]=KEEPENV,*const ld_[]=LDENV;
const char**emax=(const char**)environ,**ep,*const*pp;
register const char*p;
size_t len;
if(!preserve)
{ for(pp=keepenv;*pp;pp++)
{ len=strlen(*pp);
for(ep=emax;p= *ep;ep++)
if(!strncmp(*pp,p,len)&&(p[len]=='='||p[len-1]=='_'))
{ *ep= *emax;
*emax++=p;
if(p[len-1]!='_')
break;
}
}
*emax=0;
}
else
{ while(*emax)
emax++;
}
ep=(const char**)environ;
while(*ep)
{ p=strchr(*ep,'=');
if(!p)
drop: { *ep= *--emax;*emax=0;
continue;
}
len=p-*ep+1;
for(pp=(const char*const*)environ;pp!=ep;pp++)
if(!strncmp(*ep,*pp,len))
goto drop;
for(pp=ld_;p= *pp;pp++)
if(!strncmp(*ep,p,strlen(p)))
goto drop;
ep++;
}
}
void initdefenv(pass,fallback,do_presets)auth_identity*pass;
const char*fallback;int do_presets;
{ const char*p;
if(pass)
{ p=auth_username(pass);
if(!p||!*p)
p=fallback;
setdef(lgname,p);
p=auth_shell(pass);
if(!p||!*p)
p=binsh;
setdef(shell,p);
setdef(home,auth_homedir(pass));setdef(orgmail,auth_mailboxname(pass));
}
else
{ setdef(lgname,fallback);setdef(shell,binsh);
setdef(home,ROOT_DIR);setdef(orgmail,DEAD_LETTER);
}
setlgcs(tgetenv(lgname));
if(do_presets)
{ static const char*const prestenv[]=PRESTENV;
const char*const*pp;
int i=MAXvarstrs;
do
if(*strenstr[i].sval)
setdef(strenstr[i].sname,strenstr[i].sval);
while(i--);
setdef(host,hostname());
sputenv(lastfolder);
sputenv(exitcode);
eputenv(defpath,buf);
for(pp=prestenv;*pp;pp++)
eputenv(*pp,buf);
}
}
int alphanum(c)const unsigned c;
{ switch(c)
{ case '0':case '1':case '2':case '3':case '4':
case '5':case '6':case '7':case '8':case '9':
return 2;
case 'A':case 'B':case 'C':case 'D':case 'E':case 'F':case 'G':case 'H':
case 'I':case 'J':case 'K':case 'L':case 'M':case 'N':case 'O':case 'P':
case 'Q':case 'R':case 'S':case 'T':case 'U':case 'V':case 'W':case 'X':
case 'Y':case 'Z':
case 'a':case 'b':case 'c':case 'd':case 'e':case 'f':case 'g':case 'h':
case 'i':case 'j':case 'k':case 'l':case 'm':case 'n':case 'o':case 'p':
case 'q':case 'r':case 's':case 't':case 'u':case 'v':case 'w':case 'x':
case 'y':case 'z':
case '_':
return 1;
default:
return 0;
}
}
void setmaildir(newdir)const char*const newdir;
{ char*chp;
didchd=1;*(chp=strcpy(buf2,maildir)+STRLEN(maildir))='=';
strcpy(++chp,newdir);sputenv(buf2);
}
void setlastfolder(folder)const char*const folder;
{ char*chp;size_t len;
setlfcs(folder);
len=STRLEN(lastfolder)+2+strlen(folder);
strcpy(chp=malloc(len),lastfolder);
strlcat(chp,"=",len);
strlcat(chp,folder,len);
sputenv(chp);free(chp);
}
int setexitcode(trapisset)int trapisset;
{ char*p;int forceret;
if(setxit&&(p=getenv(exitcode)))
{ if((forceret=renvint(-2L,p))>=0)
retval=forceret;
}
else
{ forceret= -1;
if(trapisset)
{ p=buf2+STRLEN(exitcode);
strcpy(buf2,exitcode);*p='=';
ultstr(0,(unsigned long)retval,p+1);sputenv(buf2);
}
}
return forceret;
}
char*gobenv(chp,end)char*chp,*end;
{ int found,i;
found=0;end--;
if(alphanum(i=getb())==1)
for(found=1;*chp++=i,chp<end&&alphanum(i=getb()););
*chp='\0';ungetb(i);
if(chp==end)
{ nlog(exceededlb);setoverflow();
return end+1;
}
switch(i)
{ case ' ':case '\t':case '\n':case '=':
if(found)
return chp;
}
return 0;
}
int asenvcpy(src)char*src;
{ const char*chp;
if(chp=strchr(src,'='))
{ size_t len=chp++-src+1;
erestrict=1;setids();
if(len>linebuf-XTRAlinebuf-1)
{ setoverflow();
nlog("Assignment to variable with excessively long name skipped\n");
}
else
{ memcpy(buf,src,len);
src=buf+len;
if(chp=eputenv(chp,src))
{ src[-1]='\0';
asenv(chp);
}
}
return 1;
}
return 0;
}
void allocbuffers(lineb,setenv)size_t lineb;int setenv;
{ if(buf)
{ char*p=buf;
buf=0;
free(buf2);
free(p);
}
buf=malloc(lineb+XTRAlinebuf);buf2=malloc(lineb+XTRAlinebuf);
if(setenv)
{ char*chp;
*(chp=strcpy(buf,slinebuf)+STRLEN(slinebuf))='=';
ultstr(0,lineb,chp+1);
sputenv(buf);
}
}
static void asenvtext(chp)const char*const chp;
{ int i=MAXvarstrs;
do
if(!strcmp(buf,strenstr[i].sname))
strenstr[i].sval=chp;
while(i--);
}
void asenv(chp)const char*const chp;
{ static const char logfile[]="LOGFILE",Log[]="LOG",sdelivered[]="DELIVERED",
includerc[]="INCLUDERC",eumask[]="UMASK",dropprivs[]="DROPPRIVS",
shift[]="SHIFT",switchrc[]="SWITCHRC";
if(!strcmp(buf,slinebuf))
{ long lineb;
if((lineb=renvint(0L,chp))<MINlinebuf)
lineb=MINlinebuf;
allocbuffers(linebuf=lineb,0);
}
else if(!strcmp(buf,maildir))
{ if(chdir(chp))
{ chderr(chp);
setmaildir(curdir);
}
else
didchd=1;
}
else if(!strcmp(buf,logfile))
opnlog(chp);
else if(!strcmp(buf,Log))
elog(chp);
else if(!strcmp(buf,exitcode))
setxit=1;
else if(!strcmp(buf,lgname))
setlgcs(chp);
else if(!strcmp(buf,lastfolder))
setlfcs(chp);
else if(!strcmp(buf,scomsat))
{ if(!setcomsat(chp))
setdef(scomsat,offvalue);
}
else if(!strcmp(buf,shift))
{ int i;
if((i=renvint(0L,chp))>0)
{ if(i>crestarg)
i=crestarg;
crestarg-=i;restargv+=i;
}
}
else if(!strcmp(buf,dropprivs))
{ if(renvint(0L,chp))
{ if(verbose)
nlog("Assuming identity of the recipient, VERBOSE=off\n");
setids();
}
}
else if(!strcmp(buf,sdelivered))
{ if(renvint(0L,chp))
{ onguard();
if((thepid=sfork())>0)
_exit(retvl2);
if(!forkerr(thepid,procmailn))
fakedelivery=1;
newid();offguard();
}
}
else if(!strcmp(buf,lockfile))
{ if(!lockit(tstrdup((char*)chp),&globlock))
sputenv(lockfile);
}
else if(!strcmp(buf,eumask))
doumask((mode_t)strtol(chp,(char**)0,8));
else if(!strcmp(buf,includerc))
{ if(rc>=0)
pushrc(chp);
}
else if(!strcmp(buf,switchrc))
{ if(rc>=0)
changerc(chp);
}
else if(!strcmp(buf,host))
{ const char*name;
if(strcmp(chp,name=hostname()))
{ yell("HOST mismatched",name);
if(rc<0)
retval=EXIT_SUCCESS,Terminate();
closerc();
}
}
else
{ int i=MAXvarvals;
do
if(!strcmp(buf,strenvvar[i].name))
strenvvar[i].val=renvint(strenvvar[i].val,chp);
while(i--);
asenvtext(chp);
}
}
long renvint(i,env)const long i;const char*const env;
{ const char*p;long t;
t=strtol(env,(char**)&p,10);
if(p==env)
for(;;p++)
{ switch(*p)
{ case ' ':case '\t':case '\n':case '\v':case '\f':case '\r':
continue;
case 'o':case 'O':
if(!strncasecmp(p+1,"n",1))
case 'y':case 'Y':case 't':case 'T':case 'e':case 'E':
t=1;
else if(!strncasecmp(p+1,"ff",2))
case 'n':case 'N':case 'f':case 'F':case 'd':case 'D':
t=0;
else
default:
t=i;
break;
case 'a':case 'A':t=2;
break;
}
break;
}
return t;
}