[comp.sources.misc] v20i050: procmail - mail processing program v2.02, Part02/03

berg@messua.informatik.rwth-aachen.de (Stephen R. van den Berg) (06/17/91)

Submitted-by: Stephen R. van den Berg <berg@messua.informatik.rwth-aachen.de>
Posting-number: Volume 20, Issue 50
Archive-name: procmail/part02
Environment: UNIX, sendmail
Supersedes: procmail: Volume 17, Issue 31-32

---- Cut Here and feed the following to sh ----
#!/bin/sh
# This is part 02 of procmail
# ============= procmail/README ==============
if test ! -d 'procmail'; then
    echo 'x - creating directory procmail'
    mkdir 'procmail'
fi
if test -f 'procmail/README' -a X"$1" != X"-c"; then
	echo 'x - skipping procmail/README (File already exists)'
else
echo 'x - extracting procmail/README (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'procmail/README' &&
XSome legal stuff:
X
XUse this software package at your own risk.  The programmer can not
Xbe held liable for any incurred damages due to the 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 in tact.	 If you have some
Ximportant changes that might be usefull to the rest of the world, contact
Xme instead.
X
X-------------------------- SYSTEM REQUIREMENTS -------------------------------
X
XA ".forward" file (or equivalent) mechanism for forwarding mail, *grep or
Xequivalent.
X
XThe most important system calls that need to be supported (among others):
Xfork(),read(),write(),dup(),wait(),pipe(),getpwent()
X
XFor a more complete list of all library references see "includes.h"
X
X------------------------------ DESCRIPTION -----------------------------------
X
XThe procmail mail processing program. (v2.02 1991/06/12)
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
XFor installation instructions see the INSTALL file.
X
X----------------------
X
XAlthough I can't guarantee that the procmail program will perform as
Xrequired, I must say that I made the utmost effort to make procmail as
Xrobust as any program can be (every conceivable system error is caught *and*
Xhandled).
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.
X
XFor a more extensive list of features see the FEATURES file.
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 *NIX 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.informaik.rwth-aachen.de
X				berg@physik.tu-muenchen.de
X
XOr:	P.O.Box 21074
X	6369 ZG Simpelveld
X	The Netherlands
X
X----------------------
X
XP.S. I don't mind if you feed the program files through your favourite C
X     beautifier first, so any patches need not necessarily be from the
X     original sources; I apply these patches by hand anyway.
SHAR_EOF
chmod 0644 procmail/README ||
echo 'restore of procmail/README failed'
Wc_c="`wc -c < 'procmail/README'`"
test 3358 -eq "$Wc_c" ||
	echo 'procmail/README: original size 3358, current size' "$Wc_c"
fi
# ============= procmail/STYLE ==============
if test -f 'procmail/STYLE' -a X"$1" != X"-c"; then
	echo 'x - skipping procmail/STYLE (File already exists)'
else
echo 'x - extracting procmail/STYLE (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'procmail/STYLE' &&
XDon't complain about the formatting of my C code.  I know it's unconventional,
Xbut it's my standard format.  If you don't like it, feed it through your
Xfavourite C beautifier.
X
XYes, I do have my reasons for formatting it this way:
X1. consistent, functional indenting
X2. I got used to it
X3. the C compiler doesn't mind at all
X4. I get more program text on my screen when editing, hence I don't have to
X   scroll as often to see other parts of the program while working, (you won't
X   believe this, I know) and therefore it helps to get a better overview of
X   the program
X5. I hate it when I have to scroll back the screen those 5 lines just to see
X   the top of the loop (and then back down to look at the end again, etc.)
X
XAnd, now don't start flaming me about "bad practice", I don't consider this
Xformatting method bad practice (it's properly indented).
X
XI consider "bad practice" to be unportable or non-ANSI code, which my code is
Xcertainly not.
SHAR_EOF
chmod 0644 procmail/STYLE ||
echo 'restore of procmail/STYLE failed'
Wc_c="`wc -c < 'procmail/STYLE'`"
test 951 -eq "$Wc_c" ||
	echo 'procmail/STYLE: original size 951, current size' "$Wc_c"
fi
# ============= procmail/common.c ==============
if test -f 'procmail/common.c' -a X"$1" != X"-c"; then
	echo 'x - skipping procmail/common.c (File already exists)'
else
echo 'x - extracting procmail/common.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'procmail/common.c' &&
X/************************************************************************
X *	A some common routines for procmail and formail			*
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 *	#include "STYLE"						*
X *									*
X ************************************************************************/
X#ifdef	RCS
Xstatic char rcsid[]="$Id: common.c,v 2.0 1991/06/10 14:35:35 berg Rel $";
X#endif
X#include "includes.h"
X
Xvoid*tmalloc();
Xextern const char binsh[];
X
X#ifdef NOmemmove
Xvoid*memmove(To,From,count)void*To,*From;register size_t count;{
X#ifdef NObcopy
X register char*to=To,*from=From;/*void*old;*/	  /* silly compromise, throw */
X /*old=to;*/count++;--to;--from;   /* away space to be syntactically correct */
X if(to<=from){
X   goto jiasc;
X   do{
X      *++to= *++from;					  /* copy from above */
Xjiasc:;}
X   while(--count);}
X else{
X   to+=count;from+=count;
X   goto jidesc;
X   do{
X      *--to= *--from;					  /* copy from below */
Xjidesc:;}
X   while(--count);}
X return To/*old*/;}
X#else
X bcopy(From,To,count);return To;}
X#endif
X#endif
X
X#include "shell.h"
X
Xshexec(argv)const char *const*argv;{int i;const char**newargv,**p;
X execvp(*argv,argv);	 /* if this one fails, we retry it as a shell script */
X for(p=(const char**)argv,i=1;i++,*p++;);	      /* count the arguments */
X newargv=malloc(i*sizeof*p);
X for(*(p=newargv)=binsh;*++p= *++argv;);
X execve(*newargv,newargv,environ);	      /* no shell script? -> trouble */
X log("Failed to execute");logqnl(*argv);exit(EX_UNAVAILABLE);}
SHAR_EOF
chmod 0644 procmail/common.c ||
echo 'restore of procmail/common.c failed'
Wc_c="`wc -c < 'procmail/common.c'`"
test 1611 -eq "$Wc_c" ||
	echo 'procmail/common.c: original size 1611, current size' "$Wc_c"
fi
# ============= procmail/exopen.c ==============
if test -f 'procmail/exopen.c' -a X"$1" != X"-c"; then
	echo 'x - skipping procmail/exopen.c (File already exists)'
else
echo 'x - extracting procmail/exopen.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'procmail/exopen.c' &&
X/************************************************************************
X *	Collection of NFS secure exclusive open routines		*
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 *	#include "STYLE"						*
X *									*
X ************************************************************************/
X#ifdef	RCS
Xstatic char rcsid[]="$Id: exopen.c,v 2.0 1991/06/10 14:35:35 berg Rel $";
X#endif
X#include "config.h"
X#include "includes.h"
X#include "exopen.h"
X
Xconst char*hostname();
Xextern pid_t thepid;
X
Xconst char*hostname(){static char name[HOSTNAMElen+1];
X#ifdef	NOuname
X gethostname(name,HOSTNAMElen+1);
X#else
X struct utsname names;
X uname(&names);strncpy(name,names.nodename,HOSTNAMElen);
X#endif
X name[HOSTNAMElen]='\0';return name;}
X
Xultoan(val,dest)unsigned long val;char*dest;{register i;       /* convert to */
X do{				    /* a number within the set [0-9A-Za-z-_] */
X    i=val&0x3f;
X    *dest++=i+(i<10?'0':i<10+26?'A'-10:i<10+26+26?'a'-10-26:
X       i==10+26+26?'-'-10-26-26:'_'-10-26-27);}
X while(val>>=6);
X *dest='\0';}
X
Xunique(full,p,mode)const char*const full;char*const p;const mode_t mode;{
X unsigned long retry=3;int i;			  /* create unique file name */
X do{
X   ultoan(SERIALmask&(retry<<16)+(unsigned long)thepid,p+1);
X   *p='_';strcat(p,hostname());}
X while(0>(i=ropen(full,O_WRONLY|O_CREAT|O_EXCL|O_SYNC,mode))&&errno==EEXIST
X   &&retry--);	    /* casually check if it already exists (highly unlikely) */
X if(i<0){
X   writeerr(full);return 0;}
X rclose(i);return 1;}
X				     /* rename MUST fail if already existent */
Xmyrename(old,new)const char*const old,*const new;{int i,serrno;
X i=link(old,new);serrno=errno;unlink(old);errno=serrno;return i;}
SHAR_EOF
chmod 0644 procmail/exopen.c ||
echo 'restore of procmail/exopen.c failed'
Wc_c="`wc -c < 'procmail/exopen.c'`"
test 1788 -eq "$Wc_c" ||
	echo 'procmail/exopen.c: original size 1788, current size' "$Wc_c"
fi
# ============= procmail/Manifest ==============
if test -f 'procmail/Manifest' -a X"$1" != X"-c"; then
	echo 'x - skipping procmail/Manifest (File already exists)'
else
echo 'x - extracting procmail/Manifest (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'procmail/Manifest' &&
XMakefile	We all know what that is.
XREADME		Important, read it.
XINSTALL		A description of what has to be done to install procmail.
XHISTORY		Recent and ancient changes (or bugs) documented.
XFEATURES	A summary of all the things procmail is particularly good at.
XSTYLE		A short explanation of why the source looks so "awkward"
Xlockfile.c	main program for lockfile
Xformail.c	main program for formail
XManifest	You guessed it.
Xprocmail.c	main program for procmail.
Xnonint.c	Collection of routines that don't return ints.
Xretint.c	Collection of routines that return ints.
Xgoodies.c	Some real nice routines, deserve to be put in a library.
Xcommon.c	Some routines that are used by procmail and formail.
Xexopen.c	Collection of routines about an NFS secure excl. open.
Xexopen.h	The very same.
Xprocmail.h	Include file with all declarations.
X
Xincludes.h	System include files are all referenced here.
Xconfig.h	The file to edit if you want to change, yes, the configuration.
Xautoconf	The shell script that seizes your compiler and machine,
X		and then creates a file called autoconf.h describing the
X		kludges that are going to be applied for your installation.
X
Xshell.h		Defines a few 'shell' macros for malloc and the like.
Xman/*		Yes, the man pages (made in a labour camp).
Xinclude/*	A few files that are supposed to fool your compiler into
X		thinking that it has ANSI and POSIX conforming include files.
Xexamples/?procmailrc
X		Sample .procmailrc files.
Xexamples/?rmail
X		Sample shell scripts that demonstrate how to use
X		lockfiles while reading the mail (to ensure mail integrity
X		as soon as you exit the mail program).
Xexamples/forward
X		A sample .forward file.
Xexamples/advanced
X		Some extra info for network mounted mailboxes, examples of
X		advanced .procmailrc expressions and using procmail as
X		a local delivery agent.
SHAR_EOF
chmod 0644 procmail/Manifest ||
echo 'restore of procmail/Manifest failed'
Wc_c="`wc -c < 'procmail/Manifest'`"
test 1814 -eq "$Wc_c" ||
	echo 'procmail/Manifest: original size 1814, current size' "$Wc_c"
fi
# ============= procmail/lockfile.c ==============
if test -f 'procmail/lockfile.c' -a X"$1" != X"-c"; then
	echo 'x - skipping procmail/lockfile.c (File already exists)'
else
echo 'x - extracting procmail/lockfile.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'procmail/lockfile.c' &&
X/************************************************************************
X *	lockfile.c	a conditional semaphore-file creator		*
X *									*
X *	Is relatively bug free.						*
X *									*
X *	Created by S.R.van den Berg, The Netherlands			*
X *	This file can be freely copied for any use.			*
X ************************************************************************/
X#ifdef	RCS
Xstatic char rcsid[]="$Id: lockfile.c,v 2.1 1991/06/11 14:00:41 berg Rel $";
X#endif
Xstatic char rcsdate[]="$Date: 1991/06/11 14:00:41 $";
X#include "config.h"		       /* overkill, I know, only need DIRSEP */
X#include "includes.h"
X
Xvolatile int exitflag;
Xpid_t thepid;
Xconst char dirsep[]=DIRSEP;
X
Xvoid failure(){
X exitflag=1;}
X
Xmain(argc,argv)const int argc;const char*argv[];{const char**p,*cp;
X int sleepsec,retries,i,invert,force,suspend,retval=0;
X static char usage[]=
X   "Usage: lockfile -nnn | -rnnn | -! | -lnnn | -snnn | file ...\n";
X sleepsec=8;force=retries=invert=0;suspend=16;thepid=getpid();
X if(argc<2){
X   putse(usage);return EX_USAGE;}
Xagain:
X p=argv+1;signal(SIGHUP,failure);signal(SIGINT,failure);
X signal(SIGQUIT,failure);signal(SIGTERM,failure);
X while(*p)
X    if(*(cp= *p++)=='-')
X       switch(cp[1]){
X       case '!':invert=1;break;
X       case 'r':retries=strtol(cp+2,(char**)0,10);break;
X       case 'l':force=strtol(cp+2,(char**)0,10);break;
X       case 's':suspend=strtol(cp+2,(char**)0,10);break;
X       default:
X	  if(cp[1]-'0'>(unsigned)9){
X	     putse(usage);retval=EX_USAGE;goto failure;}
X	  if(sleepsec>=0)
X	     sleepsec=strtol(cp+1,(char**)0,10);}
X    else
X      if(sleepsec<0)
X	 unlink(cp);
X      else{
X	 while(0>NFSxopen(cp)){struct stat buf;time_t t;
X	    if(exitflag||retries==1){
Xfailure:       sleepsec= -1;p[-1]=0;goto again;}
X	    if(force&&(t=time((time_t*)0),!stat(cp,&buf))&&
X	       force<t-buf.st_mtime){
X	       unlink(cp);putse("Forcing lock on \"");putse(cp);putse("\"\n");
X	       sleep(suspend);}
X	    else
X	       sleep(sleepsec);
X	    if(retries)
X	       retries--;}}
Xreturn retval?retval:invert^(sleepsec<0)?EX_CANTCREAT:EX_OK;}
X
Xputse(a)char*a;{char*b;
X b=a-1;
X while(*++b);
X write(STDERR,a,b-a);}
X
X#include "exopen.h"
X
XNFSxopen(name)char*name;{char*p,*q;int j= -1,i;
X for(q=name;p=strpbrk(q,dirsep);q=p+1);
X i=q-name;
X if(!(p=malloc(i+UNIQnamelen)))
X    return exitflag=1;
X strncpy(p,name,i);
X if(unique(p,p+i,0))
X   j=myrename(p,name);
X free(p);return j;}
X
Xvoid*tmalloc(len)const size_t len;{				     /* stub */
X return malloc(len);}
X
Xropen(name,mode,mask)const char*const name;const mode_t mask;{	     /* stub */
X return open(name,mode,mask);}
X
Xrclose(fd)const int fd;{					     /* stub */
X return close(fd);}
X
Xwriteerr(a)const char*const a;{}				     /* stub */
SHAR_EOF
chmod 0644 procmail/lockfile.c ||
echo 'restore of procmail/lockfile.c failed'
Wc_c="`wc -c < 'procmail/lockfile.c'`"
test 2698 -eq "$Wc_c" ||
	echo 'procmail/lockfile.c: original size 2698, current size' "$Wc_c"
fi
# ============= procmail/goodies.c ==============
if test -f 'procmail/goodies.c' -a X"$1" != X"-c"; then
	echo 'x - skipping procmail/goodies.c (File already exists)'
else
echo 'x - extracting procmail/goodies.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'procmail/goodies.c' &&
X/************************************************************************
X *	Collection of library-worthy routines				*
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 *	#include "STYLE"						*
X *									*
X ************************************************************************/
X#ifdef	RCS
Xstatic char rcsid[]="$Id: goodies.c,v 2.1 1991/06/11 12:59:16 berg Rel $";
X#endif
X#include "config.h"
X#include "procmail.h"
X#include "shell.h"
X
X#define NOTHING_YET	(-1)	/* readparse understands a very complete    */
X#define SKIPPING_SPACE	0	/* subset of the standard /bin/sh syntax    */
X#define NORMAL_TEXT	1	/* that includes single-, double- and back- */
X#define DOUBLE_QUOTED	2	/* quotes, backslashes and $subtitutions    */
X#define SINGLE_QUOTED	3
X
Xreadparse(p,fgetc,sarg)register char*p;int(*const fgetc)();
X const int sarg;{static i;int got;char*startb;
X for(got=NOTHING_YET;;){		    /* buf2 is used as scratch space */
Xloop:
X   i=fgetc();
X   if(buf+linebuf-3<p){		    /* doesn't catch everything, just a hint */
X      log("Exceeded LINEBUF\n");p=buf+linebuf-3;goto ready;}
Xnewchar:
X   switch(i){
X      case EOF:
X	 if(got>NORMAL_TEXT)
Xearly_eof:  log(unexpeof);
Xready:	 if(got!=SKIPPING_SPACE||sarg)	  /* not terminated yet or sarg==2 ? */
Xready0:	    *p++='\0';
X	 *p=TMNATE;return;
X      case '\\':
X	 if(got==SINGLE_QUOTED)
X	    break;
X	 switch(i=fgetc()){
X	    case EOF:goto early_eof;			  /* can't quote EOF */
X	    case '\n':continue;				/* concatenate lines */
X	    case '#':
X	       if(got>SKIPPING_SPACE)	/* escaped comment at start of word? */
X		  goto noesc;			/* apparently not, literally */
X	    case ' ':case '\t':case '\'':
X	       if(got==DOUBLE_QUOTED)
X		  goto noesc;
X	    case '"':case '\\':case '$':case '`':goto nodelim;}
X	 if(got>NORMAL_TEXT)
Xnoesc:	    *p++='\\';			/* nothing to escape, just echo both */
X	 break;
X      case '`':
X	 if(got==SINGLE_QUOTED)
X	    goto nodelim;
X	 for(startb=p;;){			       /* mark your position */
X	    switch(i=fgetc()){			 /* copy till next backquote */
X	       case '\\':
X		  switch(i=fgetc()){
X		     case EOF:log(unexpeof);goto forcebquote;
X		     case '\n':continue;
X		     case '"':
X			if(got!=DOUBLE_QUOTED)
X			   break;
X		     case '\\':case '$':case '`':goto escaped;}
X		  *p++='\\';break;
X	       case '"':
X		  if(got!=DOUBLE_QUOTED)       /* missing closing backquote? */
X		     break;
Xforcebquote:   case EOF:case '`':*p='\0';
X		  if(!(sh=!!strpbrk(startb,tgetenv(shellmetas)))){
X		     const char*save=sgetcp;
X		     sgetcp=p=tstrdup(startb);readparse(startb,sgetc,0);
X		     free(p);sgetcp=save;} /* chopped up, drop source buffer */
X		  startb=fromprog(p=startb,startb);	/* read from program */
X		  if(got!=DOUBLE_QUOTED){
X		     i=0;startb=p;goto simplsplit;}	      /* split it up */
X		  if(i=='"')		  /* was there a missing closing ` ? */
X		     got=NORMAL_TEXT;			 /* yes, terminate " */
X		  p=startb;goto loop;
X	       case '\n':i=';';}	       /* newlines separate commands */
Xescaped:    *p++=i;}
X      case '"':
X	 switch(got){
X	    case DOUBLE_QUOTED:got=NORMAL_TEXT;continue;	/* closing " */
X	    case SINGLE_QUOTED:goto nodelim;}
X	 got=DOUBLE_QUOTED;continue;				/* opening " */
X      case '\'':
X	 switch(got){
X	    case DOUBLE_QUOTED:goto nodelim;
X	    case SINGLE_QUOTED:got=NORMAL_TEXT;continue;}	/* closing ' */
X	 got=SINGLE_QUOTED;continue;				/* opening ' */
X      case '#':
X	 if(got>SKIPPING_SPACE)			/* comment at start of word? */
X	    break;
X	 while((i=fgetc())!=EOF&&i!='\n');		    /* skip till EOL */
X	 goto ready;
X      case '$':
X	 if(got==SINGLE_QUOTED)
X	    break;
X	 if(EOF==(i=fgetc())){
X	    *p++='$';goto ready;}
X	 startb=buf2;
X	 if(i=='{'){						  /* ${name} */
X	    while(EOF!=(i=fgetc())&&alphanum(i))
X	       *startb++=i;
X	    *startb='\0';
X	    if(i!='}'){
Xbadsubst:      log("Bad substitution of");logqnl(buf2);continue;}
X	    i='\0';}
X	 else if(alphanum(i)){					    /* $name */
X	    do *startb++=i;
X	    while(EOF!=(i=fgetc())&&alphanum(i));
X	    if(i==EOF)
X	       i='\0';
X	    *startb='\0';}
X	 else if(i=='$'){					   /* $$=pid */
X	    ultostr(0,(unsigned long)thepid,p);i='\0';goto eofstr;}
X	 else{
X	    *p++='$';goto newchar;}		       /* not a substitution */
X	 startb=(char*)tgetenv(buf2);
X	 if(got!=DOUBLE_QUOTED)
Xsimplsplit: for(;;startb++){		  /* simply split it up in arguments */
X	       switch(*startb){
X		  case ' ':case '\t':case '\n':
X		     if(got<=SKIPPING_SPACE)
X			continue;
X		     *p++='\0';got=SKIPPING_SPACE;continue;
X		  case '\0':goto eeofstr;}
X	       *p++= *startb;got=NORMAL_TEXT;}
X	 else{
X	    strcpy(p,startb);				   /* simply copy it */
Xeofstr:	    p=strchr(p,'\0');}
Xeeofstr: if(i)				     /* already read next character? */
X	    goto newchar;
X	 continue;
X      case ' ':case '\t':
X	 switch(got){
X	    case NORMAL_TEXT:
X	       if(sarg==1)
X		  goto ready;		/* already fetched a single argument */
X	       got=SKIPPING_SPACE;*p++=sarg?' ':'\0';	 /* space or \0 sep. */
X	    case NOTHING_YET:case SKIPPING_SPACE:continue;}    /* skip space */
X      case '\n':
X	 if(got<=NORMAL_TEXT)
X	    goto ready;}			    /* EOL means we're ready */
Xnodelim:
X   *p++=i;					   /* ah, a normal character */
X   if(got<=SKIPPING_SPACE)		 /* should we bother to change mode? */
X      got=NORMAL_TEXT;}}
X
Xultostr(minwidth,val,dest)unsigned long val;char*dest;{int i;unsigned long j;
X j=val;i=0;					   /* a beauty, isn't it :-) */
X do i++;					   /* determine needed width */
X while(j/=10);
X while(--minwidth>=i)				 /* fill up any excess width */
X   *dest++=' ';
X *(dest+=i)='\0';
X do *--dest='0'+val%10;				  /* display value backwards */
X while(val/=10);}
X
Xsputenv(a)char*a;{	      /* smart putenv, the way it was supposed to be */
X static struct lienv{struct lienv*next;char name[255];}*myenv;
X static alloced;int i,remove;char*split,**preenv;struct lienv*curr,**last;
X yell("Assigning",a);remove=0;a=tstrdup(a);		/* make working copy */
X if(!(split=strchr(a,'='))){			   /* assignment or removal? */
X    remove=1;i=strlen(a);*(split=i+(a=realloc(a,i+2)))='=';
X    split[1]='\0';}
X i= ++split-a;
X for(curr= *(last= &myenv);curr;curr= *(last= &curr->next))
X   if(!strncmp(a,curr->name,i)){	     /* is it one I created earlier? */
X      split=curr->name;*last=curr->next;free(curr);
X      for(preenv=environ;*preenv!=split;preenv++);
X      goto wipenv;}
X for(preenv=environ;*preenv;preenv++)
X   if(!strncmp(a,*preenv,i)){	       /* is it in the standard environment? */
Xwipenv:
X      while(*preenv=preenv[1])	   /* wipe this entry out of the environment */
X	 preenv++;
X      break;}
X i=(preenv-environ+2)*sizeof*environ;
X if(alloced)		   /* have we ever alloced the environ array before? */
X   environ=realloc(environ,i);
X else{
X   alloced=1;environ=tmemmove(malloc(i),environ,i-sizeof*environ);}
X if(!remove){		  /* if not remove, then add it to both environments */
X   for(preenv=environ;*preenv;preenv++);
X   curr=malloc(curr->name-(char*)curr+strlen(a)+1);
X   strcpy(*preenv=curr->name,a);free(a);preenv[1]=0;curr->next=myenv;
X   myenv=curr;}}
SHAR_EOF
chmod 0644 procmail/goodies.c ||
echo 'restore of procmail/goodies.c failed'
Wc_c="`wc -c < 'procmail/goodies.c'`"
test 7091 -eq "$Wc_c" ||
	echo 'procmail/goodies.c: original size 7091, current size' "$Wc_c"
fi
# ============= procmail/procmail.c ==============
if test -f 'procmail/procmail.c' -a X"$1" != X"-c"; then
	echo 'x - skipping procmail/procmail.c (File already exists)'
else
echo 'x - extracting procmail/procmail.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'procmail/procmail.c' &&
X/************************************************************************
X *	procmail.c	an autonomous mail processor			*
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 *	#include "STYLE"						*
X *									*
X ************************************************************************/
X#ifdef	RCS
Xstatic char rcsid[]="$Id: procmail.c,v 2.3 1991/06/12 10:23:06 berg Rel $";
X#endif
X#include "config.h"
X#define MAIN
X#include "procmail.h"
X#include "shell.h"
X
X#define VERSION "procmail v2.02 1991/06/12 written by Stephen R.van den Berg\n\
X\t\t\t\tberg@messua.informatik.rwth-aachen.de\n\
X\t\t\t\tberg@physik.tu-muenchen.de\n"
X
Xchar*buf,*buf2,*globlock,*loclock,*tolock,*lastfolder;
Xconst char grep[]="GREP",shellflags[]="SHELLFLAGS",shell[]="SHELL",
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,
X executing[]="Executing",oquote[]=" \"",cquote[]="\"\n",
X whilstwfor[]=" whilst waiting for ";
Xstatic const char linebufs[]="LINEBUF",tokey[]=TOkey,eumask[]="UMASK",
X tosubstitute[]=TOsubstitute,lockfile[]="LOCKFILE",defaultf[]="DEFAULT",
X maildir[]="MAILDIR",couldnread[]="Couldn't read",logfile[]="LOGFILE",
X orgmail[]="ORGMAIL",user[]="USER",tmp[]=Tmp,home[]="HOME",sfolder[]=FOLDER,
X sendmail[]="SENDMAIL",host[]="HOST";
Xstruct varval strenvvar[]={{"LOCKSLEEP",DEFlocksleep},
X {"LOCKTIMEOUT",DEFlocktimeout},{"SUSPEND",DEFsuspend},
X {"NORESRETRY",DEFnoresretry}};
Xlong lastdump;
Xint retval=EX_CANTCREAT,sh,pwait,lcking,locknext,verbose,linebuf=DEFlinebuf,
X rc= -1;
Xvolatile int flaggerd=2,nextexit;
Xpid_t thepid;
X
Xmain(argc,argv)const char*const argv[];{static char flags[NRRECFLAGS];int i;
X char*themail,*thebody,*chp,*startchar,*chp2;long tobesent,filled;
X if((chp=(char*)argv[argc=1])&&*chp=='-'&&*++chp&&!chp[1])
X   switch(*chp){		     /* these options are mutually exclusive */
X      case VERSIONOPT:log(VERSION);return EX_OK;
X      case DEBUGOPT:verbose=1;
X      default:*environ=0;
X      case PRESERVOPT:argc++;}
X else
X   *environ=0;					     /* drop the environment */
X gargv=argv+argc;umask(077);thepid=getpid();fclose(stdout);fclose(stderr);
X rclose(STDOUT);rclose(STDERR);		    /* don't trust the stdio library */
X if(0>opena(devnull)||0>opena(console))
X   return EX_OSFILE;
X setbuf(stdin,(char*)0);buf=malloc(linebuf);buf2=malloc(linebuf);chdir(tmp);
X ultostr(0,(unsigned long)(i=getuid()),buf);
X setpwent();
X {struct passwd*pass;
X if(pass=getpwuid(i)){			/* find user defaults in /etc/passwd */
X   setdef(home,pass->pw_dir);chdir(pass->pw_dir);
X   setdef(user,pass->pw_name?pass->pw_name:buf);setdef(shell,pass->pw_shell);}
X else{			 /* user could not be found, set reasonable defaults */
X   setdef(home,tmp);setdef(user,buf);setdef(shell,binsh);}}
X endpwent();setdef(shellmetas,DEFshellmetas);setdef(shellflags,DEFshellflags);
X setdef(maildir,DEFmaildir);setdef(defaultf,DEFdefault);
X setdef(orgmail,DEForgmail);setdef(grep,DEFgrep);setdef(sendmail,DEFsendmail);
X setdef(lockext,DEFlockext);setdef(msgprefix,DEFmsgprefix);
X chdir(getenv(maildir));nextrcfile();thebody=themail=malloc(1);filled=0;
X signal(SIGTERM,sterminate);signal(SIGINT,sterminate);
X signal(SIGHUP,sterminate);signal(SIGQUIT,flagger);
Xchangedmail:
X themail=readdyn(themail,&filled);			 /* read in the mail */
Xonlyhead:
X startchar=filled+(thebody=themail);
X while(thebody<startchar&&*thebody++=='\n');	     /* skip leading garbage */
X while(thebody<startchar&&startchar>(thebody=findnl(thebody,startchar)))
X   switch(*thebody++){
X      case '\n':goto eofheader;		   /* empty line marks end of header */
X      case '\t':case ' ':thebody[-2]=' ';}  /* concatenate continuated lines */
Xeofheader:
X if((chp=thebody)<startchar){
X   goto firstel;				 /* search for bogus headers */
X   do{
X      if(*chp++!='\n'||chp==startchar)		/* is the line really empty? */
X	 continue;
Xfirstel:
X      *startchar='\0';		   /* put a terminator at the end for sscanf */
X      if(0>=sscanf(chp,FromSCAN,buf)){
X	 chp--;continue;}		  /* no match, back up, and on we go */
X      tmemmove(chp+1,chp,startchar++-chp);*chp='>';	/* insert '>' before */
X      themail=realloc(chp2=themail,++filled+1);		     /* bogus header */
X#define ADJUST(x)	((x)=themail+((x)-chp2))
X      ADJUST(thebody);ADJUST(startchar);ADJUST(chp);}/* find next empty line */
X while(startchar>(chp=findnl(chp,startchar)));}
Xdo{					     /* main rcfile interpreter loop */
X   while(chp=(char*)argv[argc]){       /* interpret command line specs first */
X      argc++;strcpy(buf,chp);
X      if(chp=strchr(buf,'=')){
X	 strcpy(sgetcp=buf2,++chp);readparse(chp,sgetc,0);goto argenv;}}
X   if(rc<0)						 /* open new rc file */
X      while(*buf='\0',0>bopen(strcat(
X	 strchr(dirsep,*rcfile)?buf:cat(tgetenv(home),MCDIRSEP),rcfile))){
X	 log(couldnread);logqnl(buf);
X	 if(!nextrcfile())		      /* not available? try the next */
X	    goto nomore_rc;}
X   unlock(&loclock);	/* unlock any local lockfile after every parsed line */
X   do skipspace();					  /* skip whitespace */
X   while(testb('\n'));
X   if(testb(':')){				       /* check for a recipe */
X      readparse(buf,getb,2);i=sh=1;*buf2='\0';
X      if(0>=sscanf(buf,"%d%[^\n]",&sh,buf2))		 /* nr of conditions */
X	 strcpy(buf2,buf);
X      *buf= *flags='\0';
X      if(0>=sscanf(buf2,RECFLAGS,flags,buf))		   /* read the flags */
X	 strcpy(buf,buf2);
X      if(tolock)		 /* clear temporary buffer for lockfile name */
X	 free(tolock);
X      tolock=0;*buf2='\0';
X      if((locknext=':'==*buf)&&0<sscanf(buf,": %[^ \t\n] %[^\n]",buf,buf2))
X	 tolock=tstrdup(buf);		    /* yep, local lockfile specified */
X      if(*buf2)
X	 skipped(buf2);				    /* display any leftovers */
X      startchar=themail;tobesent=thebody-themail;
X      if(strchr(flags,'B'))		/* what needs to be piped into grep? */
X	 if(strchr(flags,'H'))
X	    tobesent=filled;
X	 else{
X	    startchar=thebody;tobesent=filled-tobesent;}
X      while(sh--){				    /* any conditions (left) */
X	 getbl(buf2);
X	 if(!strncmp(buf2,tokey,STRLEN(tokey)))		     /* magic TOkey? */
X	    cat(tosubstitute,buf2+STRLEN(tokey));
X	 else if(*buf=='!'&&!strncmp(buf2+1,tokey,STRLEN(tokey))) /* !TOkey? */
X	    strcat(cat("!",tosubstitute),buf2+1+STRLEN(tokey));
X	 else
X	    strcpy(buf,buf2);
X	 if(i){					 /* check out all conditions */
X	    i=!grepin((*buf=='!'||*buf=='\\')+buf,startchar,tobesent,
X	       !!strchr(flags,'D'))^*buf=='!';
X	    if(verbose){
X	       log(i?"M":"No m");log("atch on");logqnl(buf);}}}
X      startchar=themail;tobesent=filled;	    /* body, header or both? */
X      if(strchr(flags,'h')){
X	 if(!strchr(flags,'b'))
X	    tobesent=thebody-themail;}
X      else if(strchr(flags,'b'))
X	 tobesent-=(startchar=thebody)-themail;
X      chp=strchr(strcpy(buf,tgetenv(sendmail)),'\0');sh=0;
X      pwait=!!strchr(flags,'w');
X      if(testb('!')){					 /* forward the mail */
X	 readparse(chp+1,getb,0);
X	 if(i)
X	    goto forward;}
X      else if(testb('|')){				    /* pipe the mail */
X	 getbl(buf2);
X	 for(chp=buf2;*(chp=strchr(chp,'\0')-1)=='\\'&&getbl(chp););
X	 if(i){
X	    if(sh=!!strpbrk(buf2,tgetenv(shellmetas)))
X	       strcpy(buf,buf2);	 /* copy literally, shell will parse */
X	    else{
X	       sgetcp=buf2;readparse(buf,sgetc,0);}	/* parse it yourself */
X	    chp=buf;*buf2='\0';
X	    while(i= *chp)     /* find the implicit lockfile name ('>>name') */
X	      if(chp++,i=='>'&&*chp=='>'){
X		 while((i= *++chp)==' '||i=='\t');
X		 sscanf(chp,EOFName,buf2);break;}
X	    lcllock();
X	    if(strchr(flags,'f')){
X	       if(startchar==themail&&tobesent!=filled){      /* if only 'h' */
X		  long dfilled=0;
X		  if(pipthrough(buf,startchar,tobesent))
X		     continue;
X		  chp=readdyn(malloc(1),&dfilled);filled-=tobesent;
X		  if(tobesent<dfilled)	   /* adjust buffer size (grow only) */
X		     themail=realloc(themail,dfilled+filled);
X		  tmemmove(themail+dfilled,thebody,filled);
X		  tmemmove(themail,chp,dfilled);free(chp);
X		  themail=realloc(themail,1+(filled+=dfilled));goto onlyhead;}
X	       if(pipthrough(buf,startchar,tobesent))
X		  continue;
X	       filled=startchar-themail;goto changedmail;}
Xforward:    if(!pipin(buf,startchar,tobesent)&&!strchr(flags,'c'))
X	       goto mailed;}}
X      else{		   /* dump the mail into a mailbox file or directory */
X	 readparse(buf,getb,0);chp2=chp=strchr(buf,'\0')+1;
X	 while(*chp!=TMNATE){		  /* concatenate all other arguments */
X	    while(*chp++);
X	    chp[-1]=' ';}
X	 *chp=chp[-1]='\0';
X	 if(*chp2)
X	    skipped(chp2);			     /* report any leftovers */
X	 if(i){
X	    strcpy(buf2,buf);lcllock();strcpy(buf2,buf);
X	    if(!dump(deliver(buf2),startchar,tobesent)&&!strchr(flags,'c'))
X	       goto mailed;
X	    writeerr(buf);}}}
X   else if(testb('#'))					   /* no comment :-) */
X      getbl(buf);
X   else{				    /* then it must be an assignment */
X      for(*(chp=buf)='\0';;){			    /* get the variable name */
X	 switch(i=getb()){
X	    case ' ':case '\t':skipspace();i=testb('=')?'=':0;
X	    case '\n':case '=':case EOF:
X	       *chp='\0';goto eofvarname;}
X	 if(!alphanum(*chp++=i))
X	    for(;;*chp++=i)			 /* it was garbage after all */
X	       switch(i=getb()){
X		  case ' ':case '\t':case '\n':case EOF:*chp='\0';
X		     skipped(buf);goto mainloop;}}
Xeofvarname:
X      if(i!='='){				   /* removal or assignment? */
X	 sputenv(buf);continue;}
X      *chp='=';readparse(++chp,getb,1);
Xargenv:
X      sputenv(buf);chp[-1]='\0';
X      if(!strcmp(buf,linebufs)){
X	 if((linebuf=renvint(0L,chp)+XTRAlinebuf)<MINlinebuf+XTRAlinebuf)
X	    linebuf=MINlinebuf+XTRAlinebuf;	       /* check minimum size */
X	 free(buf);free(buf2);buf=malloc(linebuf);buf2=malloc(linebuf);}
X      else if(!strcmp(buf,maildir)){
X	 if(chdir(chp)){
X	    log("Couldn't chdir to");logqnl(chp);}}
X      else if(!strcmp(buf,logfile)){
X	 close(STDERR);
X	 if(0>opena(chp))
X	    if(0>opena(console))
X	       retval=EX_OSFILE;	  /* bad news, but can't tell anyone */
X	    else
X	       writeerr(chp);}
X      else if(!strcmp(buf,lockfile))
X	 lockit(chp,&globlock);
X      else if(!strcmp(buf,eumask)){
X	 sscanf(chp,"%o",&i);umask(i);}
X      else if(!strcmp(buf,host)){
X	 if(strcmp(chp,chp2=(char*)hostname())){
X	    yell("HOST mismatched",chp2);
X	    if(rc<0||!nextrcfile()){		  /* if no rcfile opened yet */
X	       retval=EX_OK;terminate();}	  /* exit gracefully as well */
X	    rclose(rc);rc= -1;}}
X      else{
X	 i=MAXvarvals;
X	 do				      /* several numeric assignments */
X	    if(!strcmp(buf,strenvvar[i].name)){
X	       strenvvar[i].val=renvint(strenvvar[i].val,chp);break;}
X	 while(i--);}}
Xmainloop:
X    ;}
X while(rc<0||!testb(EOF));			    /* main interpreter loop */
Xnomore_rc:
X if(dump(deliver(tgetenv(defaultf)),themail,filled)){		  /* default */
X   writeerr(buf);	    /* if it fails, don't panic, try the last resort */
X   if(dump(deliver(tgetenv(orgmail)),themail,filled))
X      writeerr(buf);goto mailerr;}			/* now you can panic */
Xmailed:
X retval=EX_OK;				  /* we're home free, mail delivered */
Xmailerr:
X unlock(&loclock);			/* any local lock file still around? */
X for(;themail<thebody;){
X   chp=buf-1;
X   while(themail<thebody&&chp<buf+linebuf-1&&(*++chp= *themail++)!='\n');
X   if(chp<buf)
X      chp++;
X   *chp='\0';
X   if(0<sscanf(buf,SFROM_S,buf2)){	      /* find case sensitive "From " */
X      log(SFROM);goto foundsorf;}
X   else if(0<sscanf(buf,SSUBJECT_S,buf2)){  /* case insensitive "Subject:" ? */
X      log(SSUBJECT);
Xfoundsorf:
X      log(buf2);log(newline);}}				  /* log its arrival */
X log(sfolder);i=strlen(strncpy(buf,lastfolder,MAXfoldlen))+STRLEN(sfolder);
X buf[MAXfoldlen]='\0';
X while(chp=strchr(buf,'\t'))
X   *chp=' ';						/* take out all tabs */
X log(buf);i-=i%TABWIDTH;		     /* tell where we last dumped it */
X do log(TABCHAR);
X while((i+=TABWIDTH)<LENoffset);
X ultostr(7,lastdump,buf);log(buf);log(newline);terminate();}
X
Xdirmail(){struct stat stbuf;		/* directory name is expected in buf */
X strcpy(buf2,strcat(buf,MCDIRSEP));
X if(unique(buf2,strchr(buf2,'\0'),0666)){
X   stat(buf2,&stbuf);
X   ultoan((unsigned long)stbuf.st_ino,	      /* filename with i-node number */
X      strchr(strcat(buf,tgetenv(msgprefix)),'\0'));
X   if(!myrename(buf2,buf))	       /* rename it, we need the same i-node */
X       return opena(buf);}
X return -1;}
SHAR_EOF
chmod 0644 procmail/procmail.c ||
echo 'restore of procmail/procmail.c failed'
Wc_c="`wc -c < 'procmail/procmail.c'`"
test 12352 -eq "$Wc_c" ||
	echo 'procmail/procmail.c: original size 12352, current size' "$Wc_c"
fi
# ============= procmail/nonint.c ==============
if test -f 'procmail/nonint.c' -a X"$1" != X"-c"; then
	echo 'x - skipping procmail/nonint.c (File already exists)'
else
echo 'x - extracting procmail/nonint.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'procmail/nonint.c' &&
X/************************************************************************
X *	Collection of routines that don't return int			*
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 *	#include "STYLE"						*
X *									*
X ************************************************************************/
X#ifdef	RCS
Xstatic char rcsid[]="$Id: nonint.c,v 2.0 1991/06/10 14:35:35 berg Rel $";
X#endif
X#include "config.h"
X#include "procmail.h"
X
X#define nomemretry	noresretry
X#define noforkretry	noresretry
X
Xvoid*tmalloc(len)const size_t len;{void*p;int i;  /* this malloc can survive */
X if(p=malloc(len))		/* a temporary "out of swap space" condition */
X   return p;
X if(p=malloc(1))
X   free(p);			   /* works on some systems with latent free */
X for(lcking=2,i=nomemretry;i<0||i--;){
X   suspend();		     /* problems?  don't panic, wait a few secs till */
X   if(p=malloc(len)){	     /* some other process has paniced (and died 8-) */
X      lcking=0;return p;}}
X nomemerr();}
X
Xvoid*trealloc(old,len)void*const old;const size_t len;{void*p;int i;
X if(p=realloc(old,len))
X    return p;				    /* for comment see tmalloc above */
X if(p=malloc(1))
X   free(p);
X for(lcking=2,i=nomemretry;i<0||i--;){
X   suspend();
X   if(p=realloc(old,len)){
X      lcking=0;return p;}}
X nomemerr();}
X		       /* line buffered to keep concurrent entries untangled */
Xlog(new)const char*const new;{int lnew,i;static lold;static char*old;char*p;
X if(lnew=strlen(new)){						/* anything? */
X   if(nextexit)
X      goto direct;			      /* carefull, in terminate code */
X   i=lold+lnew;
X   if(p=lold?realloc(old,i):malloc(i)){
X      memmove((old=p)+lold,new,(size_t)lnew);			   /* append */
X      if(p[(lold=i)-1]=='\n'){					     /* EOL? */
X	 rwrite(STDERR,p,i);lold=0;free(p);}}		/* flush the line(s) */
X   else{					   /* no memory, force flush */
X      if(lold){
X	 rwrite(STDERR,old,i);lold=0;free(old);}
Xdirect:
X      rwrite(STDERR,new,lnew);}}}
X
X#include "shell.h"
X
Xpid_t sfork(){pid_t i;int r;		/* this fork can survive a temporary */
X r=noforkretry;				   /* "process table full" condition */
X while((i=fork())==-1){
X   lcking=3;
X   if(!(r<0||r--))
X      break;
X   suspend();}
X lcking=0;return i;}
X
Xextern char*backblock;				/* see retint.c for comment */
Xextern long backlen;
Xpid_t pidfilt,pidchild;
Xextern pbackfd[2];
X
Xvoid sterminate(){static const char*const msg[]={newline,0,
X "memory\n","fork\n","file descriptor\n"};
X signal(SIGTERM,SIG_IGN);signal(SIGHUP,SIG_IGN);signal(SIGINT,SIG_IGN);
X if(pidchild)		    /* don't kill what is not ours, we might be root */
X   kill(pidchild,SIGTERM);
X if(!nextexit){
X   nextexit=1;log("Terminating prematurely");
X   if(1!=lcking){
X      if(1<lcking)
X	 log(whilstwfor);
X      log(msg[lcking]);terminate();}}}
X
Xvoid stermchild(){
X signal(SIGHUP,SIG_IGN);signal(SIGINT,SIG_IGN);signal(SIGQUIT,SIG_IGN);
X signal(SIGTERM,SIG_IGN);kill(pidfilt,SIGTERM);kill(thepid,SIGQUIT);
X log("Rescue of unfiltered data ");
X if(dump(PWRB,backblock,backlen)) /* pump back the data through the backpipe */
X    log("failed\n");
X else
X    log("succeeded\n");
X exit(EX_UNAVAILABLE);}
X
Xvoid flagger(){				       /* hey, we received a SIGQUIT */
X signal(SIGQUIT,flagger);flaggerd=1;}
X
Xlong dump(s,source,len)const int s;const char*source;long len;{int i;
X if(s>=0){
X    lastdump=len;
X    while(i=rwrite(s,source,BLKSIZ<len?BLKSIZ:(int)len)){
X       if(i<0){
X	  i=0;goto writefin;}
X       len-=i;source+=i;}
X    if(!len&&(lastdump<2||!(source[-1]=='\n'&&source[-2]=='\n')))
X       lastdump++,rwrite(s,newline,1); /* message always ends with a newline */
Xwritefin:
X    rclose(s);return len-i;}
X return len?len:-1;}	   /* return an error even if nothing was to be sent */
X
Xlong pipin(line,source,len)char*const line;const char*source;long len;{
X pid_t pid;int poutfd[2];
X rpipe(poutfd);
X if(!(pid=sfork())){					    /* spawn program */
X   rclose(PWRO);rclose(rc);getstdin(PRDO);callnewprog(line);}
X rclose(PRDO);forkerr(pid,line);
X if(len=dump(PWRO,source,len))			    /* dump mail in the pipe */
X   writeerr(line);		       /* pipe was shut in our face, get mad */
X if(pwait&&waitfor(pid)!=EX_OK){	    /* optionally check the exitcode */
X   progerr(line);len=1;}
X if(!sh){char*p;
X   for(p=line;;)	    /* change back the \0's into blanks for printing */
X      if(!*p++)
X	 if(*p!=TMNATE)
X	    p[-1]=' ';
X	 else
X	    break;}
X lastfolder=cstr(lastfolder,line);return len;}
X
Xchar*readdyn(bf,filled)char*bf;long*const filled;{int i;long oldsize;
X oldsize= *filled;goto jumpin;
X do{
X   *filled+=i;					/* change listed buffer size */
Xjumpin:
X   bf=realloc(bf,*filled+BLKSIZ);      /* dynamically adjust the buffer size */
Xjumpback:;}
X while(0<(i=rread(STDIN,bf+*filled,BLKSIZ)));			/* read mail */
X switch(flaggerd){
X   case 0:waitflagger();		    /* wait for the filter to finish */
X   case 1:getstdin(PRDB);		       /* filter ready, get backpipe */
X      if(1==rread(STDIN,buf,1)){		      /* backup pipe closed? */
X	 bf=realloc(bf,(*filled=oldsize+1)+BLKSIZ);bf[oldsize]= *buf;flaggerd=2;
X	 goto jumpback;}}		       /* filter goofed, rescue data */
X pidchild=0;					/* child must be gone by now */
X if(!*filled)
X   return realloc(bf,1);		     /* +1 for housekeeping purposes */
X return realloc(bf,*filled+1);}			/* minimize the buffer space */
X
Xchar*fromprog(name,dest)char*const name;char*dest;{int pinfd[2];long nls;
X rpipe(pinfd);
X if(!(pidchild=fork())){				    /* spawn program */
X   rclose(STDIN);opena(devnull);rclose(PRDI);rclose(rc);rclose(STDOUT);
X   rdup(PWRI);rclose(PWRI);callnewprog(name);}
X rclose(PWRI);nls=0;
X if(!forkerr(pidchild,name))
X    while(0<rread(PRDI,dest,1))				    /* read its lips */
X       if(*dest=='\n')				   /* carefull with newlines */
X	  nls++;			/* trailing ones should be discarded */
X       else{
X	  if(nls)
X	     for(dest[nls]= *dest;*dest++='\n',--nls;);	     /* fill them in */
X	  dest++;}
X pidchild=0;rclose(PRDI);*dest='\0';return dest;}
X
Xchar*cat(a,b)const char*const a,*const b;{
X return strcat(strcpy(buf,a),b);}
X
Xchar*findnl(start,end)register const char*start,*end;{
X while(start<end)				   /* find the first newline */
X   if(*start++=='\n')
X      return(char*)start;
X return(char*)end;}
X
Xchar*tstrdup(a)const char*const a;{int i;
X i=strlen(a)+1;return tmemmove(malloc(i),a,i);}
X
Xconst char*tgetenv(a)const char*a;{const char*b;
X return(b=getenv(a))?b:"";}
X
Xchar*cstr(a,b)const char*const a,*const b;{	/* dynamic buffer management */
X if(a)
X   free(a);
X return tstrdup(b);}
X
Xlong renvint(i,env)long i;const char*const env;{
X sscanf(tgetenv(env),"%d",&i);return i;}       /* parse it like a decimal nr */
SHAR_EOF
chmod 0644 procmail/nonint.c ||
echo 'restore of procmail/nonint.c failed'
Wc_c="`wc -c < 'procmail/nonint.c'`"
test 6650 -eq "$Wc_c" ||
	echo 'procmail/nonint.c: original size 6650, current size' "$Wc_c"
fi
true || echo 'restore of procmail/retint.c failed'
echo End of part 2, continue with part 3
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.