home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / misc / volume25 / procmail / part01 next >
Encoding:
Text File  |  1991-11-03  |  56.3 KB  |  1,690 lines

  1. Newsgroups: comp.sources.misc
  2. From: berg@messua.informatik.rwth-aachen.de (Stephen R. van den Berg)
  3. Subject:  v25i001:  procmail - mail processing program v2.31, Part01/04
  4. Message-ID: <csm-v25i001=procmail.165750@sparky.IMD.Sterling.COM>
  5. X-Md4-Signature: 6007a34adcd2bffef5564e24a79617a3
  6. Date: Sun, 3 Nov 1991 22:59:31 GMT
  7. Approved: kent@sparky.imd.sterling.com
  8.  
  9. Submitted-by: berg@messua.informatik.rwth-aachen.de (Stephen R. van den Berg)
  10. Posting-number: Volume 25, Issue 1
  11. Archive-name: procmail/part01
  12. Environment: UNIX, sendmail, smail, MMDF
  13. Supersedes: procmail2.10: Volume 20, Issue 89-91
  14.  
  15. The procmail mail processing program. (v2.31 1991/10/22)
  16.  
  17. Can be used to create mail-servers, mailing lists, sort your incoming mail
  18. into separate folders/files (real convenient when subscribing to one or more
  19. mailing lists), preprocess your mail, or selectively forward certain incoming
  20. mail automatically to someone.
  21.  
  22. The accompanying formail program enables you to generate autoreplies, split up
  23. digests/mailboxes into the original messages, do some very simple
  24. header-munging, or force mail into mail-format (with leading From line).
  25.  -- 
  26. Sincerely,                                berg@messua.informatik.rwth-aachen.de
  27.            Stephen R. van den Berg (AKA BuGless).    berg@physik.tu-muenchen.de
  28.  ----------------------
  29. A recent version can be picked up at various comp.sources.misc archives.
  30. The latest version can be obtained directly from the ftp-archive at:
  31.  
  32.     amaru.informatik.rwth-aachen.de (137.226.112.31)
  33.  
  34.     as compressed tar file:        pub/unix/procmail.tar.Z
  35.     or in compressed shar format:    pub/unix/procmail.0?.Z
  36.  ----------------------
  37. Feature summary for procmail:
  38.     + It's small
  39.     + Very easy to install (rated PG6 :-)
  40.     + Simple to maintain and configure because
  41.       all you need is actually only ONE executable (procmail)
  42.       and ONE configuration file (.procmailrc)
  43.     + Is event driven (i.e. gets invoked automagically when mail arrives)
  44.     + Does not use *any* temporary files
  45.     + Uses standard egrep regular expressions
  46.     + Allows for very-easy-to-use yes-no decisions on where the mail
  47.       should go
  48.     + Filters, delivers and forwards mail *reliably*
  49.     + Provides a reliable hook (you might even say anchor :-) for any
  50.       programs or shell scripts you may wish to start upon mail arrival
  51.     + Performs heroically under even the worst conditions
  52.       (file system full, out of swap space, process table full,
  53.       file table full, missing support files, unavailable executables,
  54.       denied permissions) and tries to deliver the mail somehow anyway
  55.     + Absolutely undeliverable mail (after trying every trick in the book)
  56.       will bounce back to the sender (or not, your choice)
  57.     + Is one of the few mailers to perform reliable mailbox locking across
  58.       NFS as well (DON'T use NFS mounted mailboxes WITHOUT installing
  59.       procmail, you may use valuable mail one day)
  60.     + Supports four mailfolder standards: single file folders (standard
  61.       and nonstandard VNIX format), directory folders that contain one file
  62.       per message, or the similar MH directory folders (numbered files)
  63.     + Variable assignment and substitution is an extremely complete subset
  64.       of the standard /bin/sh syntax
  65.     + Provides a mail log file, which logs all mail arrival, shows
  66.       in summary whence it came from, what it was about, where it went
  67.       (what folder) and how long (in bytes) it was
  68.     + Uses this log file to display a wide range of diagnostic and error
  69.       messages (if something went wrong)
  70.     + Processed mail can contain arbitrary 8-bit characters (including
  71.       '\0'); i.e. binary mailings can be processed if the rest of the
  72.       mailing system knew how to handle them too
  73.     + It has a man page (boy, does *it* have a man page)
  74.     + procmail can be used as a local delivery agent (a completely
  75.       integrated substitute for /bin/mail)
  76.     + It runs on virtually all (old and future) operating systems which
  77.       names start with a 'U' or end in an 'X' :-) (i.e. extremely portable
  78.       code)
  79.     + Works with (among others?) sendmail, smail and MMDF
  80.  
  81. Feature summary for formail:
  82.     + Can generate auto-reply headers
  83.     + Can force mail into mailbox format (so that you can process it with
  84.       standard mail programs)
  85.     + Can split up mailboxes into the individual messages
  86.     + Can split up digests into the individual messages
  87.     + Can split up saved articles into the individual articles
  88.     + Can do simple header munging
  89.  
  90. Feature summary for lockfile:
  91.     + Provides NFS-secure lockfiles to shell script programmers
  92.  
  93. #! /bin/sh
  94. # This is a shell archive.  Remove anything before this line, then feed it
  95. # into a shell via "sh file" or similar.  To overwrite existing files,
  96. # type "sh file -c".
  97. # The tool that generated this appeared in the comp.sources.unix newsgroup;
  98. # send mail to comp-sources-unix@uunet.uu.net if you want that tool.
  99. # Contents:  procmail procmail/examples procmail/examples/1procmailrc
  100. #   procmail/goodies.c procmail/include procmail/include/sys
  101. #   procmail/man procmail/man/procmail.man procmail/procmail.c
  102. # Wrapped by kent@sparky on Sun Nov  3 16:50:05 1991
  103. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  104. echo If this archive is complete, you will see the following message:
  105. echo '          "shar: End of archive 1 (of 4)."'
  106. if test ! -d 'procmail' ; then
  107.     echo shar: Creating directory \"'procmail'\"
  108.     mkdir 'procmail'
  109. fi
  110. if test ! -d 'procmail/examples' ; then
  111.     echo shar: Creating directory \"'procmail/examples'\"
  112.     mkdir 'procmail/examples'
  113. fi
  114. if test -f 'procmail/examples/1procmailrc' -a "${1}" != "-c" ; then 
  115.   echo shar: Will not clobber existing file \"'procmail/examples/1procmailrc'\"
  116. else
  117.   echo shar: Extracting \"'procmail/examples/1procmailrc'\" \(830 characters\)
  118.   sed "s/^X//" >'procmail/examples/1procmailrc' <<'END_OF_FILE'
  119. XLOCKFILE=               # in case we were called in explicit delivery mode
  120. X
  121. X# Please check if all the paths in PATH are reachable, remove the ones that
  122. X# are not.
  123. X
  124. XPATH=$HOME/bin:/usr/bin:/usr/ucb:/bin:/usr/local/bin:
  125. XMAILDIR=$HOME/Mail      # You'd better make sure it exists
  126. XDEFAULT=$MAILDIR/mbox
  127. XLOGFILE=$MAILDIR/from
  128. XLOCKFILE=$HOME/.lockmail
  129. X
  130. X:                               # Anything from thf
  131. X^From.*thf\@somewhere.someplace
  132. Xtodd                            # will go to $MAILDIR/todd
  133. X
  134. X:                               # Anything from people at uunet
  135. X^From.*\@uunet
  136. Xuunetbox                        # will go to $MAILDIR/uunetbox
  137. X
  138. X:                               # Anything from Henry
  139. X^From.*henry
  140. Xhenries                         # will go to $MAILDIR/henries
  141. X
  142. X# Anything that has not been delivered by now will go to $DEFAULT
  143. END_OF_FILE
  144.   if test 830 -ne `wc -c <'procmail/examples/1procmailrc'`; then
  145.     echo shar: \"'procmail/examples/1procmailrc'\" unpacked with wrong size!
  146.   fi
  147.   # end of 'procmail/examples/1procmailrc'
  148. fi
  149. if test -f 'procmail/goodies.c' -a "${1}" != "-c" ; then 
  150.   echo shar: Will not clobber existing file \"'procmail/goodies.c'\"
  151. else
  152.   echo shar: Extracting \"'procmail/goodies.c'\" \(9016 characters\)
  153.   sed "s/^X//" >'procmail/goodies.c' <<'END_OF_FILE'
  154. X/************************************************************************
  155. X *    Collection of library-worthy routines                *
  156. X *                                    *
  157. X *    Copyright (c) 1990-1991, S.R.van den Berg, The Netherlands    *
  158. X *    The sources can be freely copied for non-commercial use.    *
  159. X *    #include "README"                        *
  160. X *                                    *
  161. X ************************************************************************/
  162. X#ifdef RCS
  163. Xstatic char rcsid[]="$Id: goodies.c,v 2.8 1991/10/22 15:31:26 berg Rel $";
  164. X#endif
  165. X#include "config.h"
  166. X#include "procmail.h"
  167. X#include "shell.h"
  168. X
  169. X#define NOTHING_YET    (-1)    /* readparse understands a very complete    */
  170. X#define SKIPPING_SPACE    0    /* subset of the standard /bin/sh syntax    */
  171. X#define NORMAL_TEXT    1    /* that includes single-, double- and back- */
  172. X#define DOUBLE_QUOTED    2    /* quotes, backslashes and $subtitutions    */
  173. X#define SINGLE_QUOTED    3
  174. X
  175. X/* sarg==0 : normal parsing, split up arguments like in /bin/sh
  176. X * sarg==1 : environment assignment parsing, parse up till first whitespace
  177. X * sarg==2 : normal parsing, split up arguments by single spaces
  178. X */
  179. Xreadparse(p,fgetc,sarg)register char*p;int(*const fgetc)();const int sarg;
  180. X{ static i;int got;char*startb;
  181. X  for(got=NOTHING_YET;;)            /* buf2 is used as scratch space */
  182. X   {
  183. Xloop:
  184. X     i=fgetc();
  185. X     if(buf+linebuf-3<p)        /* doesn't catch everything, just a hint */
  186. X      { log("Exceeded LINEBUF\n");p=buf+linebuf-3;goto ready;
  187. X      }
  188. Xnewchar:
  189. X     switch(i)
  190. X      { case EOF:
  191. X       if(got>NORMAL_TEXT)
  192. Xearly_eof:    log(unexpeof);
  193. Xready:       if(got!=SKIPPING_SPACE||sarg)  /* not terminated yet or sarg==2 ? */
  194. X          *p++='\0';
  195. X       *p=TMNATE;return;
  196. X    case '\\':
  197. X       if(got==SINGLE_QUOTED)
  198. X          break;
  199. X       switch(i=fgetc())
  200. X        { case EOF:goto early_eof;              /* can't quote EOF */
  201. X          case '\n':continue;            /* concatenate lines */
  202. X          case '#':
  203. X         if(got>SKIPPING_SPACE) /* escaped comment at start of word? */
  204. X            goto noesc;            /* apparently not, literally */
  205. X          case ' ':case '\t':case '\'':
  206. X         if(got==DOUBLE_QUOTED)
  207. X            goto noesc;
  208. X          case '"':case '\\':case '$':case '`':goto nodelim;
  209. X        }
  210. X       if(got>NORMAL_TEXT)
  211. Xnoesc:          *p++='\\';        /* nothing to escape, just echo both */
  212. X       break;
  213. X    case '`':
  214. X       if(got==SINGLE_QUOTED)
  215. X          goto nodelim;
  216. X       for(startb=p;;)                   /* mark your position */
  217. X        { switch(i=fgetc())             /* copy till next backquote */
  218. X           { case '\\':
  219. X            switch(i=fgetc())
  220. X             { case EOF:log(unexpeof);goto forcebquote;
  221. X               case '\n':continue;
  222. X               case '"':
  223. X              if(got!=DOUBLE_QUOTED)
  224. X                 break;
  225. X               case '\\':case '$':case '`':goto escaped;
  226. X             }
  227. X            *p++='\\';break;
  228. X         case '"':
  229. X            if(got!=DOUBLE_QUOTED)    /* missing closing backquote? */
  230. X               break;
  231. Xforcebquote:     case EOF:case '`':*p='\0';
  232. X            if(!(sh=!!strpbrk(startb,tgetenv(shellmetas))))
  233. X             { const char*save=sgetcp;
  234. X               sgetcp=p=tstrdup(startb);readparse(startb,sgetc,0);
  235. X               free(p);sgetcp=save;               /* chopped up */
  236. X             }                       /* drop source buffer */
  237. X            startb=fromprog(p=startb,startb);    /* read from program */
  238. X            if(!sarg&&got!=DOUBLE_QUOTED)
  239. X             { i=0;startb=p;goto simplsplit;          /* split it up */
  240. X             }
  241. X            if(i=='"'||got<=SKIPPING_SPACE)   /* missing closing ` ? */
  242. X               got=NORMAL_TEXT;                 /* or sarg!=0 ? */
  243. X            p=startb;goto loop;
  244. X         case '\n':i=';';           /* newlines separate commands */
  245. X           }
  246. Xescaped:      *p++=i;
  247. X        }
  248. X    case '"':
  249. X       switch(got)
  250. X        { case DOUBLE_QUOTED:got=NORMAL_TEXT;continue;    /* closing " */
  251. X          case SINGLE_QUOTED:goto nodelim;
  252. X        }
  253. X       got=DOUBLE_QUOTED;continue;                /* opening " */
  254. X    case '\'':
  255. X       switch(got)
  256. X        { case DOUBLE_QUOTED:goto nodelim;
  257. X          case SINGLE_QUOTED:got=NORMAL_TEXT;continue;}    /* closing ' */
  258. X       got=SINGLE_QUOTED;continue;                /* opening ' */
  259. X    case '#':
  260. X       if(got>SKIPPING_SPACE)        /* comment at start of word? */
  261. X          break;
  262. X       while((i=fgetc())!=EOF&&i!='\n');            /* skip till EOL */
  263. X       goto ready;
  264. X    case '$':
  265. X       if(got==SINGLE_QUOTED)
  266. X          break;
  267. X       if(EOF==(i=fgetc()))
  268. X        { *p++='$';goto ready;
  269. X        }
  270. X       startb=buf2;
  271. X       if(i=='{')                          /* ${name} */
  272. X        { while(EOF!=(i=fgetc())&&alphanum(i))
  273. X         *startb++=i;
  274. X          *startb='\0';
  275. X          if(i!='}')
  276. X           { log("Bad substitution of");logqnl(buf2);continue;
  277. X           }
  278. X          i='\0';
  279. X        }
  280. X       else if(alphanum(i))                        /* $name */
  281. X        { do *startb++=i;
  282. X          while(EOF!=(i=fgetc())&&alphanum(i));
  283. X          if(i==EOF)
  284. X         i='\0';
  285. X          *startb='\0';}
  286. X       else if(i=='$')                      /* $$ =pid */
  287. X        { ultstr(0,(unsigned long)thepid,p);goto ieofstr;
  288. X        }
  289. X       else if(i=='-')                   /* $- =lastfolder */
  290. X        { strcpy(p,lastfolder);
  291. Xieofstr:      i='\0';goto eofstr;}
  292. X       else
  293. X        { *p++='$';goto newchar;               /* not a substitution */
  294. X        }
  295. X       startb=(char*)tgetenv(buf2);
  296. X       if(!sarg&&got!=DOUBLE_QUOTED)
  297. Xsimplsplit:   for(;;startb++)          /* simply split it up in arguments */
  298. X           { switch(*startb)
  299. X          { case ' ':case '\t':case '\n':
  300. X               if(got<=SKIPPING_SPACE)
  301. X              continue;
  302. X               *p++='\0';got=SKIPPING_SPACE;continue;
  303. X            case '\0':goto eeofstr;}
  304. X         *p++= *startb;got=NORMAL_TEXT;}
  305. X       else
  306. X        { if(got<=SKIPPING_SPACE)        /* can only occur if sarg!=0 */
  307. X         got=NORMAL_TEXT;
  308. X          strcpy(p,startb);                   /* simply copy it */
  309. Xeofstr:          p=strchr(p,'\0');}
  310. Xeeofstr:   if(i)                 /* already read next character? */
  311. X          goto newchar;
  312. X       continue;
  313. X    case ' ':case '\t':
  314. X       switch(got)
  315. X        { case NORMAL_TEXT:
  316. X         if(sarg==1)
  317. X            goto ready;        /* already fetched a single argument */
  318. X         got=SKIPPING_SPACE;*p++=sarg?' ':'\0';     /* space or \0 sep. */
  319. X          case NOTHING_YET:case SKIPPING_SPACE:continue;    /* skip space */
  320. X        }
  321. X    case '\n':
  322. X       if(got<=NORMAL_TEXT)
  323. X          goto ready;                /* EOL means we're ready */
  324. X      }
  325. Xnodelim:
  326. X     *p++=i;                       /* ah, a normal character */
  327. X     if(got<=SKIPPING_SPACE)         /* should we bother to change mode? */
  328. X    got=NORMAL_TEXT;
  329. X   }
  330. X}
  331. X
  332. Xultstr(minwidth,val,dest)unsigned long val;char*dest;
  333. X{ int i;unsigned long j;
  334. X  j=val;i=0;                       /* a beauty, isn't it :-) */
  335. X  do i++;                       /* determine needed width */
  336. X  while(j/=10);
  337. X  while(--minwidth>=i)                 /* fill up any excess width */
  338. X     *dest++=' ';
  339. X  *(dest+=i)='\0';
  340. X  do *--dest='0'+val%10;              /* display value backwards */
  341. X  while(val/=10);
  342. X}
  343. X
  344. Xsputenv(a)char*a;          /* smart putenv, the way it was supposed to be */
  345. X{ static struct lienv{struct lienv*next;char name[255];}*myenv;
  346. X  static alloced;int i,remove;char*split,**preenv;struct lienv*curr,**last;
  347. X  yell("Assigning",a);remove=0;a=tstrdup(a);        /* make working copy */
  348. X  if(!(split=strchr(a,'=')))               /* assignment or removal? */
  349. X   { remove=1;i=strlen(a);*(split=i+(a=realloc(a,i+2)))='=';
  350. X     split[1]='\0';
  351. X   }
  352. X  i= ++split-a;
  353. X  for(curr= *(last= &myenv);curr;curr= *(last= &curr->next))
  354. X     if(!strncmp(a,curr->name,i))         /* is it one I created earlier? */
  355. X      { split=curr->name;*last=curr->next;free(curr);
  356. X    for(preenv=environ;*preenv!=split;preenv++);
  357. X    goto wipenv;
  358. X      }
  359. X  for(preenv=environ;*preenv;preenv++)
  360. X     if(!strncmp(a,*preenv,i))           /* is it in the standard environment? */
  361. X      {
  362. Xwipenv: while(*preenv=preenv[1])   /* wipe this entry out of the environment */
  363. X       preenv++;
  364. X    break;
  365. X      }
  366. X  i=(preenv-environ+2)*sizeof*environ;
  367. X  if(alloced)           /* have we ever alloced the environ array before? */
  368. X     environ=realloc(environ,i);
  369. X  else
  370. X   { alloced=1;environ=tmemmove(malloc(i),environ,i-sizeof*environ);
  371. X   }
  372. X  if(!remove)          /* if not remove, then add it to both environments */
  373. X   { for(preenv=environ;*preenv;preenv++);
  374. X     curr=malloc(offsetof(struct lienv,name)+strlen(a)+1);
  375. X     strcpy(*preenv=curr->name,a);free(a);preenv[1]=0;curr->next=myenv;
  376. X     myenv=curr;
  377. X   }
  378. X}
  379. X                /* strtol replacement which lacks range checking */
  380. X#ifdef NOstrtol
  381. Xlong strtol(start,ptr,base)const char*start,**const ptr;
  382. X{ long result;const char*str=start;unsigned i;int sign,found;
  383. X  if(base>=36||base<(sign=found=result=0))
  384. X     goto fault;
  385. X  for(;;str++)                      /* skip leading whitespace */
  386. X   { switch(*str)
  387. X      { case '\t':case '\n':case '\v':case '\f':case '\r':case ' ':continue;
  388. X      }
  389. X     break;
  390. X   }
  391. X  switch(*str)                               /* any signs? */
  392. X   { case '-':sign=1;
  393. X     case '+':str++;
  394. X   }
  395. X  if(*str=='0')                         /* leading zero(s)? */
  396. X   { start++;
  397. X     if((i= *++str)=='x'||i=='X')            /* leading 0x or 0X? */
  398. X    if(!base||base==16)
  399. X     { base=16;str++;                /* hexadecimal all right */
  400. X     }
  401. X    else
  402. X       goto fault;
  403. X     else if(!base)
  404. X    base=8;                         /* then it is octal */
  405. X   }
  406. X  else if(!base)
  407. X     base=10;                          /* or else decimal */
  408. X  goto jumpin;
  409. X  do
  410. X   { found=1;result=result*base+i;++str;         /* start converting */
  411. Xjumpin:
  412. X     if((i= *str-'0')<10);
  413. X     else if(i-'A'+'0'<26)
  414. X    i-='A'-10-'0';
  415. X     else if(i-'a'+'0'<26)
  416. X    i-='a'-10-'0';
  417. X     else
  418. X    break;                        /* not of this world */
  419. X   }
  420. X  while(i<base);                      /* still of this world */
  421. Xfault:
  422. X  if(ptr)
  423. X    *ptr=found?str:start;                   /* how far did we get */
  424. X  return sign?-result:result;
  425. X}
  426. X#endif
  427. END_OF_FILE
  428.   if test 9016 -ne `wc -c <'procmail/goodies.c'`; then
  429.     echo shar: \"'procmail/goodies.c'\" unpacked with wrong size!
  430.   fi
  431.   # end of 'procmail/goodies.c'
  432. fi
  433. if test ! -d 'procmail/include' ; then
  434.     echo shar: Creating directory \"'procmail/include'\"
  435.     mkdir 'procmail/include'
  436. fi
  437. if test ! -d 'procmail/include/sys' ; then
  438.     echo shar: Creating directory \"'procmail/include/sys'\"
  439.     mkdir 'procmail/include/sys'
  440. fi
  441. if test ! -d 'procmail/man' ; then
  442.     echo shar: Creating directory \"'procmail/man'\"
  443.     mkdir 'procmail/man'
  444. fi
  445. if test -f 'procmail/man/procmail.man' -a "${1}" != "-c" ; then 
  446.   echo shar: Will not clobber existing file \"'procmail/man/procmail.man'\"
  447. else
  448.   echo shar: Extracting \"'procmail/man/procmail.man'\" \(22357 characters\)
  449.   sed "s/^X//" >'procmail/man/procmail.man' <<'END_OF_FILE'
  450. X.de Id
  451. X.ds Rv \\$3
  452. X.ds Dt \\$4
  453. X..
  454. X.Id $Id: procmail.man,v 2.11 1991/10/18 15:53:26 berg Rel $
  455. X.de Sh
  456. X.br
  457. X.ne 9
  458. X.SH "\\$1"
  459. X..
  460. X.de Ss
  461. X.br
  462. X.ne 9
  463. X.SS "\\$1"
  464. X..
  465. X.de Tp
  466. X.br
  467. X.ne 9
  468. X.TP "\\$1"
  469. X..
  470. X.TH PROCMAIL 1 \*(Dt BuGless
  471. X.SH NAME
  472. Xprocmail \- autonomous mail processor
  473. X.SH SYNOPSIS
  474. X.B procmail
  475. X[
  476. X.B \-+PRESERVOPT++TEMPFAILOPT+
  477. X]
  478. X.RI [ " parameter\fB=\fPvalue " | " rcfile " ]
  479. X\&.\|.\|.
  480. X.br
  481. X.B procmail
  482. X[
  483. X.B \-+PRESERVOPT++TEMPFAILOPT+
  484. X]
  485. X.B \-+DELIVEROPT+
  486. X.I recipient
  487. X.br
  488. X.B procmail
  489. X.B \-+VERSIONOPT+
  490. X.Sh DESCRIPTION
  491. X.LP
  492. XFor a quick start, see
  493. X.B NOTES
  494. Xat the end.
  495. X.LP
  496. X.B procmail
  497. Xshould be invoked automatically over the
  498. X.B .forward
  499. Xfile mechanism as soon as mail arrives.  Alternatively, when installed by
  500. Xa system administrator, it can be invoked from within the mailer immediately.
  501. XWhen invoked, it first sets some environment variables to default values,
  502. Xreads the mail message from stdin until an EOF, separates the body from the
  503. Xheader, and then, if no command line arguments are present, it starts to look
  504. Xfor a file named
  505. X.B .procmailrc
  506. Xin your home directory.  According to the processing recipes in this file,
  507. Xthe mail message that just arrived gets distributed into the right folder
  508. X(and more).
  509. X.LP
  510. XIf running suid root or with root priviliges, procmail will be able to
  511. Xperform as a functionally enhanced, backwards compatible mail delivery agent.
  512. X.Ss Defaults
  513. X.Tp 2.2i
  514. X.B "USER, HOME and SHELL"
  515. XYour (the recipient's) defaults
  516. X.Tp
  517. X.B SHELLMETAS
  518. X\&+DEFshellmetas+
  519. X.Tp
  520. X.B SHELLFLAGS
  521. X\&+DEFshellflags+
  522. X.Tp
  523. X.BR ORGMAIL
  524. X\&+SYSTEM_MBOX+
  525. X.Tp
  526. X.B MAILDIR
  527. X\&+DEFmaildir+
  528. X.Tp
  529. X.B DEFAULT
  530. X\&+DEFdefault+
  531. X.Tp
  532. X.B MSGPREFIX
  533. X\&+DEFmsgprefix+
  534. X.Tp
  535. X.B SENDMAIL
  536. X\&+DEFsendmail+
  537. X.Tp
  538. X.B LOCKEXT
  539. X\&+DEFlockext+
  540. X.Tp
  541. X.B LOCKFILE
  542. X\&+DEFdefaultlock+
  543. X.br
  544. X(only if in explicit delivery mode)
  545. X.Ss Environment
  546. X.LP
  547. XBefore you get lost in the multitude of environment variables, keep in mind
  548. Xthat all of them have reasonable defaults.
  549. X.Tp 1.2i
  550. X.B MAILDIR
  551. XCurrent directory while procmail is executing (that means that all paths
  552. Xare relative to $MAILDIR).
  553. X.Tp
  554. X.B DEFAULT
  555. XDefault
  556. X.B mailbox
  557. Xfile (if not told otherwise, procmail will dump mail in this mailbox).
  558. X.Tp
  559. X.B MSGPREFIX
  560. XFilename prefix that is used when delivering to a directory (not used when
  561. Xdelivering to a MH directory).
  562. X.Tp
  563. X.B LOGFILE
  564. XAll incoming messages will be logged here with their `+FROM+' and `Subject:'
  565. Xlines in the header, and an additional line specifying what folder it
  566. Xfinally went to and how long (in bytes) the message was.  This file will
  567. Xalso contain any error or diagnostic messages from procmail
  568. X(normally none :-) or any other programs started by procmail.  If this file
  569. Xis not specified it defaults to
  570. X.BR +console+ .
  571. XYou can turn on
  572. X.I extended diagnostics
  573. Xby prepending a `:' to the filename.
  574. X.Tp
  575. X.B LOG
  576. XAnything assigned to this variable will be echoed in $LOGFILE.
  577. X.Tp
  578. X.B ORGMAIL
  579. XUsually the system mailbox (\fBOR\fPi\fBG\fPinal \fBMAIL\fPbox).  If, for
  580. Xsome obscure reason (like `\fBfilesystem full\fP') the mail could not be
  581. Xdelivered, then this mailbox will be the last resort.  If procmail
  582. Xfails to save the mail in here (deep, deep trouble :-), then the mail
  583. Xwill bounce back to the sender.
  584. X.Tp
  585. X.B LOCKFILE
  586. XGlobal semaphore file.  If this file already exists, procmail
  587. Xwill wait until it has gone before proceeding, and will create it itself
  588. X(cleaning it up when ready, of course).  If more than one
  589. X.I lockfile
  590. Xare specified, then the previous one will be removed before trying to create
  591. Xthe new one.
  592. X.Tp
  593. X.B LOCKEXT
  594. XDefault extension that is appended to a destination file to determine
  595. Xwhat local
  596. X.I lockfile
  597. Xto use (only if turned on, on a per-recipe basis).
  598. X.Tp
  599. X.B LOCKSLEEP
  600. XNumber of seconds procmail will sleep before retrying on a
  601. X.I lockfile
  602. X(if it already existed); if not specified, it defaults to +DEFlocksleep+
  603. Xseconds.
  604. X.Tp
  605. X.B LOCKTIMEOUT
  606. XNumber of seconds that have to have passed since a
  607. X.I lockfile
  608. Xwas last modified/created before procmail decides that this must be an
  609. Xerroneously leftover lockfile that can be removed by force now.  If zero,
  610. Xthen no timeout will be used and procmail will wait forever until the
  611. Xlockfile is removed; if not specified, it defaults to +DEFlocktimeout+ seconds.
  612. XThis variable is usefull to prevent indefinite hangups of
  613. X.BR sendmail /procmail.
  614. X.Tp
  615. X.B TIMEOUT
  616. XNumber of seconds that have to have passed before procmail decides that
  617. Xsome child it started must be hanging.  The offending program will receive
  618. Xa SIGTERM from procmail, and processing of the rcfile will continue. If zero,
  619. Xthen no timeout will be used and procmail will wait forever until the child
  620. Xhas terminated; if not specified, it defaults to +DEFtimeout+ seconds.
  621. X.Tp
  622. X.B HOST
  623. XIf this is not the
  624. X.I hostname
  625. Xof the machine, processing of the current
  626. X.I rcfile
  627. Xwill immediately cease. If other rcfiles were specified on the
  628. Xcommand line, processing will continue with the next one.  If all rcfiles
  629. Xare exhausted, the program will terminate, but will not generate an error
  630. X(i.e. to the mailer it will seem that the mail has been delivered).
  631. X.Tp
  632. X.B UMASK
  633. XThe name says it all (if it doesn't, then forget about this one :-).  It
  634. Xis taken as an
  635. X.B octal
  636. Xnumber.  If not specified, it defaults to +INIT_UMASK+.
  637. X.Tp
  638. X.B SHELLMETAS
  639. XIf any of the characters in SHELLMETAS appears in the line specifying
  640. Xa filter or program, the line will be fed to $SHELL
  641. Xinstead of being executed directly.
  642. X.Tp
  643. X.B SHELLFLAGS
  644. XAny invocation of $SHELL will be like:
  645. X.br
  646. X"$SHELL" "$SHELLFLAGS" "$*";
  647. X.Tp
  648. X.B SENDMAIL
  649. XIf you're not using the
  650. X.I forwarding
  651. Xfacility don't worry about this one.  It specifies the program being
  652. Xcalled to forward any mail.
  653. X.br
  654. XIt gets invoked as: "$SENDMAIL" "$@";
  655. X.Tp
  656. X.B NORESRETRY
  657. XNumber of retries that are to be made if any `\fBprocess table full\fP',
  658. X`\fBfile table full\fP', `\fBout of memory\fP' or
  659. X`\fBout of swap space\fP' error should occur.  If this number is negative,
  660. Xthen procmail will retry indefinitely; if not specified, it defaults to two
  661. Xtimes.  The retries occur with a $SUSPEND second interval.  The idea behind
  662. Xthis is, that if the
  663. X.I swap
  664. X.I space
  665. Xhas been exhausted or the
  666. X.I process
  667. X.I table
  668. Xis full, usually several other programs will either detect this
  669. Xand abort or crash 8-), and thereby freeing valuable
  670. X.I resources
  671. Xfor procmail.
  672. X.Tp
  673. X.B SUSPEND
  674. XNumber of seconds that procmail will pause if it has to wait for something
  675. Xthat is currently unavailable (memory, fork, etc.); if not specified, it will
  676. Xdefault to +DEFsuspend+ seconds.  See also:
  677. X.BR LOCKSLEEP .
  678. X.Tp
  679. X.B LINEBUF
  680. XLength of the internal line buffers, cannot be set smaller than +MINlinebuf+.
  681. XAll lines read from the rcfile
  682. X.RI ( not
  683. Xthe mail itself, which can have arbitrary line lengths, or could be a binary
  684. Xfile for that matter) should not exceed $LINEBUF characters before and after
  685. Xexpansion.  If not specified, it defaults to +DEFlinebuf+.
  686. X.Tp
  687. X.B DELIVERED
  688. XIf set (to a dummy value) procmail will pretend (to the mail agent) the mail
  689. Xhas been delivered.  If mail can not be delivered after meeting this
  690. Xassignment, the mail will be lost (i.e. it will not bounce).
  691. X.Sh OPTIONS
  692. X.Tp 0.5i
  693. X.B \-+VERSIONOPT+
  694. XProcmail will print its version number and exit.
  695. X.Tp
  696. X.B \-+PRESERVOPT+
  697. XPreserve any old environment.  Normally procmail clears the environment
  698. Xupon startup. However, in any case: any default values will override any
  699. Xpreexisting environment variables, i.e. procmail will not pay any attention
  700. Xto any predefined environment variables, it will happily overwrite them
  701. Xwith his own defaults.
  702. X.Tp
  703. X.B \-+TEMPFAILOPT+
  704. XMake procmail fail softly, i.e. if procmail can not deliver the mail to
  705. Xany of the destinations you gave, the mail will not bounce, but will return
  706. Xto the mailqueue.  Another delivery-attempt will be made at some time in
  707. Xthe future.
  708. X.Tp
  709. X.I "\fB\-+DELIVEROPT+\fP recipient"
  710. XThis turns on explicit delivery mode, delivery will be to the local user
  711. X.IR recipient .
  712. XThis, of course, only is possible if procmail has root priviliges.
  713. XFor security reasons procmail will refuse to accept more arguments when using
  714. Xthis mode, procmail will setuid to the intended recipient and will
  715. X.I only
  716. Xread the recipient's .procmailrc file (if present, if not, delivery is like
  717. Xordinary mail).
  718. X.Sh ARGUMENTS
  719. X.LP
  720. XAny arguments containing an '=' are considered to be environment variable
  721. Xassignments, they will
  722. X.I all
  723. Xbe evaluated after the default values have been
  724. Xassigned and before the first rcfile is opened.
  725. X.LP
  726. XAny other arguments are presumed to be rcfile paths (absolute or relative to
  727. X$HOME); procmail will start with the first one it finds on the command line.
  728. XThe following ones will only be parsed if the preceding ones have a not
  729. Xmatching HOST-directive entry, or in case they should not exist.
  730. X.LP
  731. XIf no rcfiles are specified, it looks for
  732. X.BR $HOME/+PROCMAILRC+ .
  733. XIf not even that can be found processing will continue according to
  734. Xthe default settings of the environment variables and the ones specified
  735. Xon the command line.
  736. X.Sh "RCFILE FORMAT"
  737. X.LP
  738. XEnvironment variable
  739. X.B assignments
  740. Xand
  741. X.B recipes
  742. Xcan be freely intermixed in the rcfile. If any environment variable has
  743. Xa special meaning to procmail, it will be used appropiately the moment
  744. Xit is parsed. (i.e. you can change the current directory whenever you
  745. Xwant by specifying a new
  746. X.BR MAILDIR ,
  747. Xswitch lockfiles by specifying a new
  748. X.B LOCKFILE
  749. X(usually one won't need this particular application though), change
  750. Xthe umask at any time, etc., the possibilities are endless :-).
  751. X.LP
  752. XThe assignments and substitutions of these environment variables are handled
  753. Xexactly like in
  754. X.BR sh (1)
  755. X(that includes all possible quotes and escapes),
  756. Xwith the added bonus that blanks around the '=' sign are ignored and that,
  757. Xif an environment variable appears without a trailing '=', it will be
  758. Xremoved from the environment.
  759. X.LP
  760. X.Ss Comments
  761. XA word beginning with # and all the following characters up to a NEWLINE
  762. Xare ignored.
  763. X.Ss Recipes
  764. X.LP
  765. XA line starting with ':' marks the beginning of a recipe.  It has the
  766. Xfollowing format:
  767. X.LP
  768. X:
  769. X.RI [ " number " ]
  770. X.RI [ " flags " ]
  771. X.RI "[ : [" " locallockfile " "] ]"
  772. X.LP
  773. XThe
  774. X.I number
  775. Xis optional (defaults to 1) and specifies the number of conditionals
  776. Xfollowing this line.  Conditionals are complete lines that are passed on to
  777. Xthe internal egrep
  778. X.BR literally ,
  779. Xexcept for leading blanks.
  780. XIf a conditional starts with an '!', the condition is inverted.  If you really
  781. Xwant the conditional to start with an '!', precede the '!' by a '\\'.
  782. XThese conditionals are
  783. X.B completely
  784. Xcompatible to the normal egrep regular expressions.  Conditionals are anded; if
  785. X.I number
  786. Xis zero, then the condition is always true and no conditionals are expected
  787. Xnext.
  788. X.LP
  789. X.I Flags
  790. Xcan be any of the following:
  791. X.Tp 0.5i
  792. X.B +HEAD_GREP+
  793. XEgrep the header (default).
  794. X.Tp
  795. X.B +BODY_GREP+
  796. XEgrep the body.
  797. X.Tp
  798. X.B +DISTINGUISH_CASE+
  799. XTell the internal egrep to distinguish between upper and lower case (defaults
  800. Xto ignoring case).
  801. X.Tp
  802. X.B +ALSO_NEXT_RECIPE+
  803. XThis recipe will depend on the last preceding recipe without the
  804. X`+ALSO_NEXT_RECIPE+' flag.  This allows you to chain actions that depend on a
  805. Xcommon condition.  The number of conditionals that are expected to follow
  806. Xdefault to none.
  807. X.Tp
  808. X.B +PASS_HEAD+
  809. XFeed the header to the pipe (default).
  810. X.Tp
  811. X.B +PASS_BODY+
  812. XFeed the body to the pipe (default).
  813. X.Tp
  814. X.B +FILTER+
  815. XConsider the pipe as a filter (ignored if a file).
  816. X.Tp
  817. X.B +CONTINUE+
  818. XContinue processing rcfile even if this recipe matches (not needed if 'f'
  819. Xspecified).
  820. X.Tp
  821. X.B +WAIT_EXIT+
  822. XWait for the filter or program to finish and check its exitcode (normally
  823. Xignored); if the filter is unsuccessfull, then the text will
  824. Xnot have been filtered.  This flag is also recommended if you specified any
  825. X.I locallockfile
  826. Xon this recipe.
  827. X.Tp
  828. X.B +IGNORE_WRITERR+
  829. XIgnore any write errors on this recipe (i.e. usually due to an early closed
  830. Xpipe).
  831. X.Ss "Local lockfile"
  832. X.LP
  833. XIf you put a second ':' on the first recipe line, then procmail will use a
  834. X.I locallockfile
  835. X(for this recipe only).  You optionally can specify the locallockfile
  836. Xto use; if you don't however, procmail
  837. Xwill use the filename specified as the destination (or the filename
  838. Xfollowing the first '>>') and will append $LOCKEXT to it.
  839. X.Ss "Recipe destination"
  840. X.LP
  841. XThe next line can start with the following characters:
  842. X.Tp
  843. X.B !
  844. XForwards to all the specified mail addresses.
  845. X.Tp
  846. X.B |
  847. XStarts the specified program, possibly in $SHELL if any
  848. Xof the characters $SHELLMETAS are found.
  849. X.LP
  850. XAnything else will be taken as a mailbox name (either a filename or a
  851. Xdirectory, absolute or relative to the current directory (see $MAILDIR)).
  852. XIf it is a filename (or nonexistent), the mail will be appended to it.  If
  853. Xit is a directory, the mail will be delivered to a newly created, guaranteed
  854. Xto be unique, file named $MSGPREFIX* in the specified directory.  If the
  855. Xdirectory name ends in "/.", then this directory is presumed to be a MH
  856. Xfolder; i.e. procmail will use the lowest number it finds available.
  857. X.Sh EXAMPLES
  858. X.LP
  859. XSome example recipes are listed below:
  860. X.br
  861. XSort out all mail to mailling list scuba-dive.
  862. X.RS
  863. X.LP
  864. X:
  865. X.br
  866. X^TOscuba
  867. X.br
  868. Xscubafile
  869. X.LP
  870. X.RE
  871. XForward all mail from peter about compilers to william (and keep a copy
  872. Xof it here in petcompil).
  873. X.RS
  874. X.LP
  875. X:2 +PASS_BODY++CONTINUE+
  876. X.br
  877. X^From.*peter
  878. X.br
  879. X^Subject:.*compilers
  880. X.br
  881. X! william@somewhere.edu
  882. X.br
  883. X:+ALSO_NEXT_RECIPE+
  884. X.br
  885. Xpetcompil
  886. X.br
  887. X.RE
  888. X.LP
  889. XAdd the headers of all messages that didn't come from the postmaster
  890. Xto your private header collection (for
  891. Xstatistics or mail debugging); and use the lockfile `headc.lock'.  In order
  892. Xto make sure the lockfile is not removed until the pipe has finished,
  893. Xyou have to specify option 'w'; otherwise the lockfile would be removed as
  894. Xsoon as the pipe has accepted the mail.
  895. X.RS
  896. X.LP
  897. X:+PASS_HEAD++WAIT_EXIT++CONTINUE+:
  898. X.br
  899. X!From +(postmaster|Mailer)
  900. X.br
  901. X| uncompress headc.Z; cat >>headc; compress headc
  902. X.RE
  903. X.Sh CAVEATS
  904. X.LP
  905. XIf you don't explicitly tell procmail to wait (recipe option 'w') for a
  906. Xprogram to finish, it won't wait and will terminate early (not knowing if
  907. Xthe program returns success).  That also means that any locallockfile on this
  908. Xrecipe might get removed
  909. X.I before
  910. Xthe program has terminated.
  911. X.LP
  912. XContinued lines in a recipe that are to be executed are concatenated
  913. X.I before
  914. Xbeing parsed, hence
  915. X.I any
  916. Xbackslash-newline combinations in them are removed regardless.
  917. X.LP
  918. XDon't put comments on the condition lines (the regular expressions) in a recipe,
  919. Xthese lines are fed to the internal egrep
  920. X.IR literally .
  921. X(Except for any
  922. X.I leading
  923. Xwhitespace, `!' or `\\', it will be stripped.
  924. XPrecede it by a `\\' if you want it to be taken literally too.)
  925. X.LP
  926. XWatch out for deadlocks when doing unhealthy things like forwarding mail
  927. Xto your own account.  Deadlocks can be broken by proper use of
  928. X.BR LOCKTIMEOUT .
  929. X.LP
  930. XAny default values that procmail has for some environment variables will
  931. X.B always
  932. Xoverride the ones that were already defined.  If you really want to
  933. Xoverride the defaults, you either have to put them in the
  934. X.B rcfile
  935. Xor in the command line as arguments.
  936. X.Sh FILES
  937. X.PD 0
  938. X.Tp 2.2i
  939. X.B /etc/passwd
  940. Xto get the recipients USER, HOME and SHELL variable defaults
  941. X.Tp
  942. X.B +SYSTEM_MBOX+
  943. Xdefault mailbox
  944. X.Tp
  945. X.B $HOME/+PROCMAILRC+
  946. Xdefault rc file
  947. X.Tp
  948. X.B +SYSTEM_MBOX+.lock
  949. Xlockfile for standard system mail directory (not used by
  950. X.B procmail
  951. Xunless you explicitly tell it to)
  952. X.Tp
  953. X.B +DEFsendmail+
  954. Xdefault mail forwarder
  955. X.PD
  956. X.Sh "SEE ALSO"
  957. X.LP
  958. X.BR sh (1),
  959. X.BR csh (1),
  960. X.BR mail (1),
  961. X.BR binmail (1),
  962. X.BR uucp (1C),
  963. X.BR aliases (5),
  964. X.BR sendmail (8),
  965. X.BR egrep (1V),
  966. X.BR lockfile (1),
  967. X.BR formail (1)
  968. X.Sh DIAGNOSTICS
  969. X.Tp 2.3i
  970. XBad substitution of "x"
  971. XNot a valid environment variable name specified.
  972. X.Tp
  973. XCouldn't unlock "x"
  974. XLockfile was already gone, or write permission to the directory were the
  975. Xlockfile is has been denied.
  976. X.Tp
  977. XError while writing to "x"
  978. XNonexistent subdirectory, no write permission, pipe died or disk full.
  979. X.Tp
  980. XExceeded LINEBUF
  981. XBuffer overflow detected, LINEBUF was too small, memory might be corrupted.
  982. X.Tp
  983. XFailed forking "x"
  984. XProcess table is full (and NORESRETRY has been exhausted).
  985. X.Tp
  986. XFailed to execute "x"
  987. XProgram not in path, or not executable.
  988. X.Tp
  989. XForced unlock denied on "x"
  990. XNo write permission in the directory where
  991. X.B lockfile
  992. Xresides, or more than one procmail trying to force a lock at exactly the same
  993. Xtime.
  994. X.Tp
  995. XForcing lock on "x"
  996. XSpecified
  997. X.B lockfile
  998. Xis going to be removed by force because of a timeout (see also:
  999. X.BR LOCKTIMEOUT ).
  1000. X.Tp
  1001. XLockfailure on "x"
  1002. XCan only occur if you specify some real weird (and illegal) lockfilenames
  1003. Xor if the
  1004. X.B lockfile
  1005. Xcould not be created because of insufficient permissions or noexistent
  1006. Xsubdirectories.
  1007. X.Tp
  1008. XMail bounced
  1009. XProcmail hasn't been able to deliver the mail correctly.
  1010. X.Tp
  1011. XMail lost
  1012. XProcmail could not bounce or requeue the mail anymore.
  1013. X.Tp
  1014. XMail requeued
  1015. XProcmail could not deliver the mail, another delivery attempt will be done
  1016. Xsome time in the future.
  1017. X.Tp
  1018. XOut of memory
  1019. XThe system is out of swap space (and NORESRETY has been exhausted).
  1020. X.Tp
  1021. XProcessing continued
  1022. XThe unrecognised options on the command line are ignored, proceeding as
  1023. Xusual.
  1024. X.Tp
  1025. XProgram failure of "x"
  1026. XProgram that was started by procmail didn't return EX_OK (=0).
  1027. X.Tp
  1028. XSkipped: "x"
  1029. XCouldn't do anything with "x" in the rcfile (syntax error), ignoring it.
  1030. X.Tp
  1031. XTerminating prematurely whilst waiting for .\|.\|.
  1032. XProcmail received a signal while it was waiting for .\|.\|.
  1033. X.Tp
  1034. XTimeout, terminating "x"
  1035. XTimeout has occurred on program/filter "x".
  1036. X.Tp
  1037. XRescue of unfiltered data succeeded/failed
  1038. XA filter returned unsuccessfully, procmail tried to get back the original text.
  1039. X.Tp
  1040. XUnexpected EOL
  1041. XMissing closing quote, or trying to escape EOF.
  1042. X.Sh "EXTENDED DIAGNOSTICS"
  1043. X.Tp 2.3i
  1044. XAssigning "x"
  1045. XEnvironment variable assignment
  1046. X.Tp
  1047. XExecuting "x"
  1048. XStarting program "x"
  1049. X.Tp
  1050. XHOST mismatched "x"
  1051. XThis host was called "x", HOST contained something else
  1052. X.Tp
  1053. XLocking "x"
  1054. XCreating lockfile "x"
  1055. X.Tp
  1056. XMatch on "x"
  1057. XConditional matched
  1058. X.Tp
  1059. XNo match on "x"
  1060. XConditional didn't match, recipe skipped
  1061. X.Tp
  1062. XOpening "x"
  1063. XOpening file "x" for appending
  1064. X.Tp
  1065. XRcfile: "x"
  1066. XRcfile changed to "x"
  1067. X.Tp
  1068. XUnlocking "x"
  1069. XRemoving lockfile "x" again
  1070. X.PD
  1071. X.Sh WARNINGS
  1072. X.LP
  1073. XYou should create a shell script that uses
  1074. X.BR lockfile (1)
  1075. Xbefore invoking your mail shell on any mailbox file other than the system
  1076. Xmailbox (unless of course, your mail shell uses the same lockfiles (local
  1077. Xor global) you specified in your rcfile).
  1078. X.LP
  1079. XIn the unlikely event that you absolutely need to kill
  1080. Xprocmail before it has finished, first try and use
  1081. Xthe regular kill command
  1082. X.RB ( SIGTERM ),
  1083. Xotherwise some
  1084. X.I lockfiles
  1085. Xmight not get removed.
  1086. X.LP
  1087. XBeware when using the
  1088. X.B \-+TEMPFAILOPT+
  1089. Xoption, if procmail repeatedly is unable to deliver the mail (e.g. due to
  1090. Xan incorrect rcfile), the system mailqueue could fill up.  This could
  1091. Xaggravate both the local postmaster and other users.
  1092. X.Sh BUGS
  1093. X.LP
  1094. XThe only substitutions of environment variables that can be handled by
  1095. Xprocmail itself are of the type $name, ${name}, $$ and $\-; whereas $\- will
  1096. Xbe substituted by the name of the last folder delivered to.
  1097. X.LP
  1098. XAfter a lockfile is removed by force, a suspension of $SUSPEND seconds
  1099. Xis taken into account, in order to prevent the inadvertent immediate removal
  1100. Xof any newly created lockfile by another program.
  1101. X.LP
  1102. XA line buffer of length $LINEBUF is used when processing the
  1103. X.IR rcfile ,
  1104. Xany expansions
  1105. X.B have
  1106. Xto fit within this limit; if they don't, behaviour is undefined.
  1107. X.LP
  1108. XProcmail uses the regular kill command
  1109. X.RB ( SIGTERM ),
  1110. Xto terminate any runaway filter, but it does not check if the filter responds
  1111. Xto that signal and it only sends it to the filter itself, not to any of its
  1112. Xchildren.
  1113. X.LP
  1114. XIf the global lockfile has a
  1115. X.I relative
  1116. Xpath, and the current directory
  1117. Xis not the same as when the global lockfile was created, then the global
  1118. Xlockfile will not be removed if procmail exits at that point (remedy:
  1119. Xuse
  1120. X.I absolute
  1121. Xpaths to specify global lockfiles).
  1122. X.LP
  1123. XSome braindamaged mailers want
  1124. X.I all
  1125. Xlines that start with `+FROM+' to be escaped,
  1126. Xprocmail only escapes those that could really be dangerous; to support those
  1127. Xother mailers you should consider using
  1128. X.BR formail (1)
  1129. Xas a filter for all your mail.
  1130. X.Sh MISCELLANEOUS
  1131. X.LP
  1132. XWhitespace is ignored in the rcfile, except on the
  1133. Xlines that are fed to the internal egrep where only leading whitespace is
  1134. Xignored; i.e. you can indent everything.
  1135. X.LP
  1136. XIf the regular expression starts with `\fB+TOkey+\fP' it will be substituted by
  1137. X`\fB+TOsubstitute+\fP', which should catch all destination
  1138. Xspecifications.
  1139. X.LP
  1140. XAny lines in the body of the message that look like postmarks are prepended
  1141. Xwith `+ESCAP+' (disarms bogus mailheaders).  The regular expression that is
  1142. Xused to search for these postmarks is:
  1143. X.RS
  1144. X"+FROM_EXPR+"
  1145. X.RE
  1146. X.LP
  1147. XShould the uid procmail is running under, have no corresponding /etc/passwd
  1148. Xentry, then HOME will default to +Tmp+, USER will default to #uid.
  1149. X.LP
  1150. XWhen delivering to directories (or to MH folders) you
  1151. X.B don't
  1152. Xneed to use lockfiles to prevent several concurrently running procmail
  1153. Xprograms from messing up.
  1154. X.LP
  1155. XDelivering to MH folders is slightly more time consuming than delivering
  1156. Xto normal directories or mailboxes, because procmail has to search for
  1157. Xthe first available number (instead of having the filename immediately
  1158. Xavailable).
  1159. X.LP
  1160. XOn general failure procmail will return EX_CANTCREAT, unless option
  1161. X.B \-+TEMPFAILOPT+
  1162. Xis specified, in which case it will return EX_TEMPFAIL.
  1163. X.LP
  1164. XProcmail performs the locking in an NFS-secure way.
  1165. X.Sh NOTES
  1166. X.LP
  1167. XFor
  1168. X.I really
  1169. Xcomplicated processing you can even consider calling
  1170. X.B procmail
  1171. Xrecursively.
  1172. X.br
  1173. X.ne 20
  1174. X.LP
  1175. XIf procmail is
  1176. X.I not
  1177. Xinstalled globally as the default mail delivery agent (ask your system
  1178. Xadministrator), you have to make sure it is invoked when you mail arrives.
  1179. XIn this case your $HOME/.forward (beware, it
  1180. X.B has
  1181. Xto be world readable) file should contain (include the single and double
  1182. Xquotes,
  1183. X.I must
  1184. Xbe an
  1185. X.I absolute
  1186. Xpath):
  1187. X.LP
  1188. X"|IFS=' ';exec /usr/local/bin/procmail"
  1189. X.br
  1190. X.Ss "A sample small .procmailrc:"
  1191. X.br
  1192. XPATH=/bin:/usr/bin:/usr/local/bin
  1193. X.br
  1194. XMAILDIR=$HOME/Mail      #you'd better make sure it exists
  1195. X.br
  1196. XDEFAULT=$MAILDIR/mbox
  1197. X.br
  1198. XLOGFILE=$MAILDIR/from
  1199. X.br
  1200. XLOCKFILE=$HOME/.lockmail
  1201. X.br
  1202. X:
  1203. X.br
  1204. X^From.*berg
  1205. X.br
  1206. Xfrom_me
  1207. X.br
  1208. X:
  1209. X.br
  1210. X^Subject:.*Flame
  1211. X.br
  1212. X/dev/null
  1213. X.Sh AUTHOR
  1214. X.LP
  1215. XStephen R. van den Berg at RWTH-Aachen, Germany
  1216. X.RS
  1217. Xberg@messua.informatik.rwth-aachen.de
  1218. X.br
  1219. Xberg@physik.tu-muenchen.de
  1220. X.RE
  1221. END_OF_FILE
  1222.   if test 22357 -ne `wc -c <'procmail/man/procmail.man'`; then
  1223.     echo shar: \"'procmail/man/procmail.man'\" unpacked with wrong size!
  1224.   fi
  1225.   # end of 'procmail/man/procmail.man'
  1226. fi
  1227. if test -f 'procmail/procmail.c' -a "${1}" != "-c" ; then 
  1228.   echo shar: Will not clobber existing file \"'procmail/procmail.c'\"
  1229. else
  1230.   echo shar: Extracting \"'procmail/procmail.c'\" \(15641 characters\)
  1231.   sed "s/^X//" >'procmail/procmail.c' <<'END_OF_FILE'
  1232. X/************************************************************************
  1233. X *    procmail.c    an autonomous mail processor            *
  1234. X *                                    *
  1235. X *    Seems to be perfect.                        *
  1236. X *                                    *
  1237. X *    Copyright (c) 1990-1991, S.R.van den Berg, The Netherlands    *
  1238. X *    The sources can be freely copied for non-commercial use.    *
  1239. X *    #include "README"                        *
  1240. X *                                    *
  1241. X ************************************************************************/
  1242. X#ifdef RCS
  1243. Xstatic char rcsid[]="$Id: procmail.c,v 2.17 1991/10/22 15:31:26 berg Rel $";
  1244. X#endif
  1245. X#include "config.h"
  1246. X#define MAIN
  1247. X#include "procmail.h"
  1248. X#include "shell.h"
  1249. X#include "patchlevel.h"
  1250. X
  1251. Xchar*buf,*buf2,*globlock,*loclock,*tolock,*lastfolder;
  1252. Xconst char shellflags[]="SHELLFLAGS",shell[]="SHELL",
  1253. X shellmetas[]="SHELLMETAS",lockext[]="LOCKEXT",newline[]="\n",binsh[]=BinSh,
  1254. X unexpeof[]="Unexpected EOL\n",*const*gargv,*sgetcp,*rcfile=PROCMAILRC,
  1255. X dirsep[]=DIRSEP,msgprefix[]="MSGPREFIX",devnull[]=DevNull,Mail[]="Mail ",
  1256. X executing[]="Executing",oquote[]=" \"",cquote[]="\"\n",procmailn[]="procmail",
  1257. X whilstwfor[]=" whilst waiting for ",delivered[]="DELIVERED";
  1258. Xstatic const char linebufs[]="LINEBUF",tokey[]=TOkey,eumask[]="UMASK",
  1259. X tosubstitute[]=TOsubstitute,lockfile[]="LOCKFILE",defaultf[]="DEFAULT",
  1260. X maildir[]="MAILDIR",couldnread[]="Couldn't read",logfile[]="LOGFILE",
  1261. X orgmail[]="ORGMAIL",user[]="USER",tmp[]=Tmp,home[]="HOME",sfolder[]=FOLDER,
  1262. X sendmail[]="SENDMAIL",host[]="HOST",Log[]="LOG",From[]=FROM,
  1263. X exflags[]=RECFLAGS;
  1264. Xstruct varval strenvvar[]={{"LOCKSLEEP",DEFlocksleep},
  1265. X {"LOCKTIMEOUT",DEFlocktimeout},{"SUSPEND",DEFsuspend},
  1266. X {"NORESRETRY",DEFnoresretry},{"TIMEOUT",DEFtimeout}};
  1267. Xlong lastdump;
  1268. Xint retval=EX_CANTCREAT,sh,pwait,lcking,locknext,verbose,linebuf=DEFlinebuf,
  1269. X rc= -2,tofolder,ignwerr,fakedelivery;
  1270. Xvolatile int nextexit;
  1271. Xvolatile time_t alrmtime;
  1272. Xpid_t thepid;
  1273. X
  1274. Xmain(argc,argv)const char*const argv[];
  1275. X{ static char flags[maxindex(exflags)-1];
  1276. X  char*themail,*thebody,*chp,*startchar,*chp2;long tobesent,filled;
  1277. X  int i,lastcond;uid_t uid;gid_t gid;
  1278. X  for(lastcond=i=argc=0;(chp=(char*)argv[++argc])&&*chp=='-';)
  1279. X     for(;;)                           /* processing options */
  1280. X      { switch(*++chp)
  1281. X     { case VERSIONOPT:log(VERSION);return EX_OK;
  1282. X       case PRESERVOPT:i=1;continue;
  1283. X       case TEMPFAILOPT:retval=EX_TEMPFAIL;continue;
  1284. X       case DELIVEROPT:
  1285. X /*
  1286. X  *    if delivery is not to the current uid, this option can be specified;
  1287. X  *    for security reasons there may be NO command line arguments following
  1288. X  *    it
  1289. X  *    more command line arguments are only allowed if the uid is to be
  1290. X  *    the recipient (i.e. the recipient started it itself, e.g. from its
  1291. X  *    .forward file)
  1292. X  */
  1293. X          if(!chp[1]&&argv[++argc]&&!argv[argc+1])
  1294. X           { lastcond=1;chp2=(char*)argv[argc];break;     /* save the */
  1295. X           }                     /* recipient's name */
  1296. X       default:log("Unrecognised options:");logqnl(chp);log(PROCMAIL_USAGE);
  1297. X          log("Processing continued\n");
  1298. X       case '\0':;
  1299. X     }
  1300. X    break;
  1301. X      }
  1302. X  if(!i)
  1303. X     *environ=0;                     /* drop the environment */
  1304. X  gargv=argv+argc;umask(INIT_UMASK);thepid=getpid();fclose(stdout);
  1305. X  fclose(stderr);rclose(STDOUT);rclose(STDERR);             /* sure is sure */
  1306. X  if(0>opena(devnull)||0>opena(console)&&0>opena(devnull))
  1307. X     return EX_OSFILE;              /* couldn't open stdout and stderr */
  1308. X  setbuf(stdin,(char*)0);buf=malloc(linebuf);buf2=malloc(linebuf);chdir(tmp);
  1309. X  ultstr(0,(unsigned long)(i=getuid()),buf);setpwent();
  1310. X {struct passwd*pass;
  1311. X  if(lastcond&&(pass=getpwnam(chp2))||(pass=getpwuid(i)))
  1312. X    /*
  1313. X     *    set preferred uid to the intended recipient
  1314. X     */
  1315. X   { gid=pass->pw_gid;uid=pass->pw_uid;
  1316. X     setdef(home,pass->pw_dir);chdir(pass->pw_dir);
  1317. X     setdef(user,pass->pw_name?pass->pw_name:buf);setdef(shell,pass->pw_shell);
  1318. X   }
  1319. X  else             /* user could not be found, set reasonable defaults */
  1320. X    /*
  1321. X     *    set preferred uid to nobody, just in case we are running as root
  1322. X     */
  1323. X   { setdef(home,tmp);setdef(user,buf);setdef(shell,binsh);
  1324. X     gid=NOBODY_gid;uid=NOBODY_uid;
  1325. X   }
  1326. X /*
  1327. X  *    create the original/default mailbox file, chown it to the recipient
  1328. X  */
  1329. X  setdef(orgmail,SYSTEM_MBOX);close(opena(chp=getenv(orgmail)));
  1330. X  chown(chp,uid,gid);
  1331. X }
  1332. X /*
  1333. X  *    inject the one and only allowed command line argument if we are
  1334. X  *    doing delivery to an explicit recipient
  1335. X  */
  1336. X  if(!lastcond)                       /* not explicit delivery mode */
  1337. X    /*
  1338. X     *    really change the uid now, since we are not in explicit delivery mode
  1339. X     */
  1340. X   { setgid(gid);setuid(uid);
  1341. X   }
  1342. X  endpwent();setdef(shellmetas,DEFshellmetas);setdef(shellflags,DEFshellflags);
  1343. X  setdef(maildir,DEFmaildir);setdef(defaultf,DEFdefault);
  1344. X  setdef(sendmail,DEFsendmail);setdef(lockext,DEFlockext);
  1345. X  setdef(msgprefix,DEFmsgprefix);chdir(getenv(maildir));nextrcfile();
  1346. X  thebody=themail=malloc(1);filled=0;
  1347. X#ifdef SIGXCPU
  1348. X  signal(SIGXCPU,SIG_IGN);signal(SIGXFSZ,SIG_IGN);
  1349. X#endif
  1350. X  signal(SIGPIPE,SIG_IGN);signal(SIGTERM,sterminate);signal(SIGINT,sterminate);
  1351. X  signal(SIGHUP,sterminate);signal(SIGQUIT,sterminate);
  1352. X  signal(SIGALRM,ftimeout);
  1353. Xchangedmail:
  1354. X  themail=readdyn(themail,&filled);             /* read in the mail */
  1355. Xonlyhead:
  1356. X  startchar=filled+(thebody=themail);
  1357. X  while(thebody<startchar&&*thebody++=='\n');         /* skip leading garbage */
  1358. X  while(thebody=egrepin("[^\n]\n[\n\t ]",thebody,(long)(startchar-thebody),1))
  1359. X     if(*--thebody!='\n')
  1360. X    thebody[-1]=' ';            /* concatenate continuated lines */
  1361. X     else
  1362. X    goto eofheader;               /* empty line marks end of header */
  1363. X  thebody=startchar;
  1364. Xeofheader:
  1365. X  for(chp=mx(themail,thebody-1);
  1366. X   chp=egrepin(FROM_EXPR,chp,(long)(startchar-chp),1);)
  1367. X   { while(*--chp!='\n');               /* where did this line start? */
  1368. X     ++chp;tmemmove(chp+1,chp,startchar++-chp);*chp=ESCAP;  /* bogus header! */
  1369. X     themail=realloc(chp2=themail,++filled+1);
  1370. X#define ADJUST(x)    ((x)=themail+((x)-chp2))
  1371. X     ADJUST(thebody);ADJUST(startchar);ADJUST(chp);
  1372. X   }
  1373. X  do                         /* main rcfile interpreter loop */
  1374. X   { while(chp=(char*)argv[argc])      /* interpret command line specs first */
  1375. X      { argc++;
  1376. Xlikearg:
  1377. X    strcpy(buf,chp);
  1378. X    if(chp=strchr(buf,'='))
  1379. X     { strcpy(sgetcp=buf2,++chp);readparse(chp,sgetc,2);goto argenv;
  1380. X     }
  1381. X      }
  1382. X     if(rc<0)                         /* open new rc file */
  1383. X      {  i=rc;
  1384. X     while(*buf='\0',0>bopen(strcat(
  1385. X      strchr(dirsep,*rcfile)?buf:cat(tgetenv(home),MCDIRSEP),rcfile)))
  1386. X     { log(couldnread);logqnl(buf);
  1387. X       if(!nextrcfile())              /* not available? try the next */
  1388. X        { if(i==-2&&!lastcond)     /* no rcfile & explicit delivery mode */
  1389. X           { chp=DEFdefaultlock;goto likearg;         /* acquire lock */
  1390. X           }
  1391. X          goto nomore_rc;
  1392. X        }
  1393. X     }
  1394. X       /*
  1395. X    *    set uid back to recipient in any case, since we might just
  1396. X    *    have opened his/her .procmailrc
  1397. X    */
  1398. X    lastcond=0;setgid(gid);setuid(uid);
  1399. X      }
  1400. X     unlock(&loclock);alarm((unsigned)(alrmtime=0));          /* reset alarm */
  1401. X     do skipspace();                      /* skip whitespace */
  1402. X     while(testb('\n'));
  1403. X     if(testb(':'))                       /* check for a recipe */
  1404. X      { readparse(buf,getb,0);sh=strtol(buf,&chp,10);
  1405. X    if(chp==buf)                     /* no number parsed */
  1406. X       sh= -1;
  1407. X    if(tolock)         /* clear temporary buffer for lockfile name */
  1408. X       free(tolock);
  1409. X    for(i=maxindex(flags);flags[i]=0,i--;);          /* clear the flags */
  1410. X    for(tolock=0,locknext=0;;)
  1411. X     { switch(i= *chp++)
  1412. X        { default:
  1413. X         if(!(chp2=strchr(exflags,i)))       /* check for a valid flag */
  1414. X          { --chp;break;
  1415. X          }
  1416. X         flags[chp2-exflags]=1;                 /* set the flag */
  1417. X          case ' ':case '\t':continue;
  1418. X          case '\0':
  1419. X         if(*chp!=TMNATE)        /* if not the real end, skip */
  1420. X            continue;
  1421. X         break;
  1422. X          case ':':locknext=1;        /* yep, local lockfile specified */
  1423. X         if(*chp||*++chp!=TMNATE)
  1424. X          { tolock=tstrdup(chp);chp=strchr(chp,'\0')+1;
  1425. X          }
  1426. X        }
  1427. X       if(concatenate(chp))
  1428. X          skipped(chp);                /* display any leftovers */
  1429. X       break;
  1430. X     }
  1431. X    if(sh<0)                   /* assume the appropriate */
  1432. X       sh=!flags[ALSO_NEXT_RECIPE];         /* default nr of conditions */
  1433. X    startchar=themail;tobesent=thebody-themail;
  1434. X    if(flags[BODY_GREP])               /* what needs to be egrepped? */
  1435. X       if(flags[HEAD_GREP])
  1436. X          tobesent=filled;
  1437. X       else
  1438. X        { startchar=thebody;tobesent=filled-tobesent;
  1439. X        }
  1440. X    i=flags[ALSO_NEXT_RECIPE]?lastcond:1;          /* init test value */
  1441. X    while(sh--)                    /* any conditions (left) */
  1442. X     { skipspace();getbl(buf2);
  1443. X       if(!strncmp(buf2,tokey,STRLEN(tokey)))         /* magic TOkey? */
  1444. X          cat(tosubstitute,buf2+STRLEN(tokey));
  1445. X       else if(*buf=='!'&&!strncmp(buf2+1,tokey,STRLEN(tokey)))  /* yes! */
  1446. X          strcat(cat("!",tosubstitute),buf2+1+STRLEN(tokey));
  1447. X       else
  1448. X          strcpy(buf,buf2);
  1449. X       if(i)                 /* check out all conditions */
  1450. X        { i=!!egrepin((*buf=='!'||*buf=='\\')+buf,startchar,tobesent,
  1451. X           flags[DISTINGUISH_CASE])^*buf=='!';
  1452. X          if(verbose)
  1453. X           { log(i?"M":"No m");log("atch on");logqnl(buf);
  1454. X           }
  1455. X        }
  1456. X     }
  1457. X    if(!flags[ALSO_NEXT_RECIPE])       /* save the outcome for posterity */
  1458. X       lastcond=i;
  1459. X    startchar=themail;tobesent=filled;        /* body, header or both? */
  1460. X    if(flags[PASS_HEAD])
  1461. X     { if(!flags[PASS_BODY])
  1462. X          tobesent=thebody-themail;
  1463. X     }
  1464. X    else if(flags[PASS_BODY])
  1465. X       tobesent-=(startchar=thebody)-themail;
  1466. X    chp=strchr(strcpy(buf,tgetenv(sendmail)),'\0');sh=0;
  1467. X    pwait=flags[WAIT_EXIT];ignwerr=flags[IGNORE_WRITERR];skipspace();
  1468. X    if(testb('!'))                     /* forward the mail */
  1469. X     { readparse(chp+1,getb,0);
  1470. X       if(i)
  1471. X          goto forward;}
  1472. X    else if(testb('|'))                    /* pipe the mail */
  1473. X     { getbl(buf2);
  1474. X       for(chp=buf2;*(chp=strchr(chp,'\0')-1)=='\\'&&getbl(chp););
  1475. X       if(i)
  1476. X        { if(sh=!!strpbrk(buf2,tgetenv(shellmetas)))
  1477. X         strcpy(buf,buf2);     /* copy literally, shell will parse */
  1478. X          else
  1479. X           { sgetcp=buf2;readparse(buf,sgetc,0);    /* parse it yourself */
  1480. X           }
  1481. Xforward:      chp=buf;*buf2='\0';
  1482. X          while(i= *chp)   /* find the implicit lockfile name ('>>name') */
  1483. X         if(chp++,i=='>'&&*chp=='>')
  1484. X          { chp=pstrspn(chp+1," \t");
  1485. X            tmemmove(buf2,chp,i=strcspn(chp,EOFName));chp[i]='\0';
  1486. X            if(sh)         /* expand any environment variables */
  1487. X             { chp=tstrdup(buf);sgetcp=buf2;readparse(buf,sgetc,0);
  1488. X               strcpy(buf2,buf);strcpy(buf,chp);free(chp);
  1489. X             }
  1490. X            break;
  1491. X          }
  1492. X          lcllock();inittmout(buf);
  1493. X          if(flags[FILTER])
  1494. X           { if(startchar==themail&&tobesent!=filled)     /* if only 'h' */
  1495. X          { long dfilled=0;
  1496. X            if(pipthrough(buf,startchar,tobesent))
  1497. X               continue;
  1498. X            chp=readdyn(malloc(1),&dfilled);filled-=tobesent;
  1499. X            if(tobesent<dfilled)   /* adjust buffer size (grow only) */
  1500. X               themail=realloc(themail,dfilled+filled);
  1501. X            tmemmove(themail+dfilled,thebody,filled);
  1502. X            tmemmove(themail,chp,dfilled);free(chp);
  1503. X            themail=realloc(themail,1+(filled+=dfilled));goto onlyhead;
  1504. X          }
  1505. X         if(pipthrough(buf,startchar,tobesent))
  1506. X            continue;
  1507. X         filled=startchar-themail;goto changedmail;
  1508. X           }
  1509. X          if(!pipin(buf,startchar,tobesent)&&!flags[CONTINUE])
  1510. X         goto mailed;
  1511. X        }
  1512. X     }
  1513. X    else           /* dump the mail into a mailbox file or directory */
  1514. X     { readparse(buf,getb,0);
  1515. X       if(concatenate(chp=strchr(buf,'\0')+1))
  1516. X          skipped(chp);                 /* report any leftovers */
  1517. X       if(i)
  1518. X        { strcpy(buf2,buf);lcllock();strcpy(buf2,buf);
  1519. X          if(dump(deliver(buf2),startchar,tobesent))
  1520. X         writeerr(buf);
  1521. X          else if(!flags[CONTINUE])
  1522. X         goto mailed;
  1523. X          tofolder=0;
  1524. X        }
  1525. X     }
  1526. X      }
  1527. X     else if(testb('#'))                   /* no comment :-) */
  1528. X    getbl(buf);
  1529. X     else                    /* then it must be an assignment */
  1530. X      { for(*(chp=buf)='\0';;)                /* get the variable name */
  1531. X     { switch(i=getb())
  1532. X        { case ' ':case '\t':skipspace();i=testb('=')?'=':0;
  1533. X          case '\n':case '=':case EOF:*chp='\0';goto eofvarname;
  1534. X        }
  1535. X       if(!alphanum(*chp++=i))
  1536. X          for(;;*chp++=i)             /* it was garbage after all */
  1537. X         switch(i=getb())
  1538. X          { case ' ':case '\t':case '\n':case EOF:*chp='\0';
  1539. X               skipped(buf);goto mainloop;
  1540. X          }
  1541. X     }
  1542. Xeofvarname:
  1543. X    if(i!='=')                   /* removal or assignment? */
  1544. X     { sputenv(buf);continue;
  1545. X     }
  1546. X    *chp='=';readparse(++chp,getb,1);
  1547. Xargenv: sputenv(buf);chp[-1]='\0';
  1548. X    if(!strcmp(buf,linebufs))
  1549. X     { if((linebuf=renvint(0L,chp)+XTRAlinebuf)<MINlinebuf+XTRAlinebuf)
  1550. X          linebuf=MINlinebuf+XTRAlinebuf;           /* check minimum size */
  1551. X       free(buf);free(buf2);buf=malloc(linebuf);buf2=malloc(linebuf);
  1552. X     }
  1553. X    else if(!strcmp(buf,maildir))
  1554. X     { if(chdir(chp))
  1555. X        { log("Couldn't chdir to");logqnl(chp);
  1556. X        }
  1557. X     }
  1558. X    else if(!strcmp(buf,logfile))
  1559. X     { close(STDERR);
  1560. X       if(verbose=':'==*chp)             /* turn on diagnostics? */
  1561. X          chp++;;
  1562. X       if(0>opena(chp))
  1563. X          if(0>opena(console))
  1564. X         retval=EX_OSFILE;      /* bad news, but can't tell anyone */
  1565. X          else
  1566. X         writeerr(chp);}
  1567. X    else if(!strcmp(buf,Log))
  1568. X       log(chp);
  1569. X    else if(!strcmp(buf,delivered))                /* fake delivery */
  1570. X     { lcking=1;
  1571. X       if((thepid=sfork())>0)
  1572. X        { nextexit=2;lcking=0;return EX_OK; /* signals may cause trouble */
  1573. X        }
  1574. X       else
  1575. X        { if(!forkerr(thepid,procmailn))
  1576. X         fakedelivery=1;
  1577. X          thepid=getpid();lcking=0;
  1578. X          if(nextexit)             /* signals occurred so far? */
  1579. X           { log(newline);terminate();
  1580. X           }
  1581. X        }
  1582. X     }
  1583. X    else if(!strcmp(buf,lockfile))
  1584. X     { lockit(chp,&globlock);chown(chp,uid,gid);
  1585. X     }
  1586. X    else if(!strcmp(buf,eumask))
  1587. X       umask((int)strtol(chp,(char**)0,8));
  1588. X    else if(!strcmp(buf,host))
  1589. X     { if(strcmp(chp,chp2=(char*)hostname()))
  1590. X        { yell("HOST mismatched",chp2);
  1591. X          if(rc<0||!nextrcfile())          /* if no rcfile opened yet */
  1592. X           { retval=EX_OK;terminate();      /* exit gracefully as well */
  1593. X           }
  1594. X          rclose(rc);rc= -1;
  1595. X        }
  1596. X     }
  1597. X    else
  1598. X     { i=MAXvarvals;
  1599. X       do                      /* several numeric assignments */
  1600. X          if(!strcmp(buf,strenvvar[i].name))
  1601. X           { strenvvar[i].val=renvint(strenvvar[i].val,chp);break;
  1602. X           }
  1603. X       while(i--);
  1604. X     }
  1605. X      }
  1606. Xmainloop:;
  1607. X   }
  1608. X  while(rc<0||!testb(EOF));                /* main interpreter loop */
  1609. Xnomore_rc:
  1610. X  if(dump(deliver(tgetenv(defaultf)),themail,filled))          /* default */
  1611. X   { writeerr(buf);        /* if it fails, don't panic, try the last resort */
  1612. X     if(dump(deliver(tgetenv(orgmail)),themail,filled))
  1613. X    writeerr(buf);goto mailerr;            /* now you can panic */
  1614. X   }
  1615. Xmailed:
  1616. X  retval=EX_OK;                  /* we're home free, mail delivered */
  1617. Xmailerr:
  1618. X  unlock(&loclock);*thebody='\0';      /* Terminate the header, just in case */
  1619. X  if(!strncmp(From,chp=themail,STRLEN(From)))  /* Check for a "From " header */
  1620. X   { if(chp=strchr(themail,'\n'))
  1621. X    *chp++='\0';
  1622. X     else
  1623. X    chp=thebody;
  1624. X     log(themail);log(newline);         /* preserve mailbox format (any length) */
  1625. X   }
  1626. X  if(chp=egrepin(NSUBJECT,chp,(long)(thebody-chp),0))
  1627. X   { for(chp2= --chp;*--chp2!='\n';);
  1628. X     if(chp-++chp2>MAXSUBJECTSHOW)            /* keep it within bounds */
  1629. X    chp2[MAXSUBJECTSHOW]='\0';
  1630. X     *chp='\0';detab(chp2);log(" ");log(chp2);log(newline);
  1631. X   }
  1632. X  log(sfolder);i=strlen(strncpy(buf,lastfolder,MAXfoldlen))+STRLEN(sfolder);
  1633. X  buf[MAXfoldlen]='\0';detab(buf);log(buf);i-=i%TABWIDTH;    /* last dump */
  1634. X  do log(TABCHAR);
  1635. X  while((i+=TABWIDTH)<LENoffset);
  1636. X  ultstr(7,lastdump,buf);log(buf);log(newline);terminate();
  1637. X}
  1638. X
  1639. Xdirmail()                /* buf should contain directory name */
  1640. X{ char*chp;struct stat stbuf;
  1641. X  if((chp=strchr(buf,'\0')-1)-1>=buf&&chp[-1]==*MCDIRSEP&&*chp=='.')
  1642. X   { *chp='\0';strcpy(buf2,buf);               /* it ended in /. */
  1643. X   }
  1644. X  else
  1645. X   { chp=0;strcpy(buf2,strcat(buf,MCDIRSEP));
  1646. X   }
  1647. X  if(unique(buf2,strchr(buf2,'\0'),0666))
  1648. X   { if(chp)
  1649. X      { unsigned long i=0;
  1650. X    do ultstr(0,++i,chp);               /* find first empty MH folder */
  1651. X    while(link(buf2,buf));
  1652. X    unlink(buf2);goto opn;
  1653. X      }
  1654. X     stat(buf2,&stbuf);
  1655. X     ultoan((unsigned long)stbuf.st_ino,      /* filename with i-node number */
  1656. X      strchr(strcat(buf,tgetenv(msgprefix)),'\0'));
  1657. X     if(!myrename(buf2,buf))           /* rename it, we need the same i-node */
  1658. Xopn:    return opena(buf);
  1659. X   }
  1660. X  return -1;
  1661. X}
  1662. END_OF_FILE
  1663.   if test 15641 -ne `wc -c <'procmail/procmail.c'`; then
  1664.     echo shar: \"'procmail/procmail.c'\" unpacked with wrong size!
  1665.   fi
  1666.   # end of 'procmail/procmail.c'
  1667. fi
  1668. echo shar: End of archive 1 \(of 4\).
  1669. cp /dev/null ark1isdone
  1670. MISSING=""
  1671. for I in 1 2 3 4 ; do
  1672.     if test ! -f ark${I}isdone ; then
  1673.     MISSING="${MISSING} ${I}"
  1674.     fi
  1675. done
  1676. if test "${MISSING}" = "" ; then
  1677.     echo You have unpacked all 4 archives.
  1678.     rm -f ark[1-9]isdone
  1679. else
  1680.     echo You still must unpack the following archives:
  1681.     echo "        " ${MISSING}
  1682. fi
  1683. exit 0
  1684. exit 0 # Just in case...
  1685. -- 
  1686. Kent Landfield                   INTERNET: kent@sparky.IMD.Sterling.COM
  1687. Sterling Software, IMD           UUCP:     uunet!sparky!kent
  1688. Phone:    (402) 291-8300         FAX:      (402) 291-4362
  1689. Please send comp.sources.misc-related mail to kent@uunet.uu.net.
  1690.