home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / misc / volume20 / procmail2.10 / part02 < prev    next >
Encoding:
Text File  |  1991-07-11  |  49.1 KB  |  1,283 lines

  1. Newsgroups: comp.sources.misc
  2. From: Stephen R. van den Berg <berg@messua.informatik.rwth-aachen.de>
  3. Subject:  v20i090:  procmail - mail processing program v2.10, Part02/03
  4. Message-ID: <1991Jul10.013436.16803@sparky.IMD.Sterling.COM>
  5. X-Md4-Signature: 5b91d126ae94aca781114760b72e78f9
  6. Date: Wed, 10 Jul 1991 01:34:36 GMT
  7. Approved: kent@sparky.imd.sterling.com
  8.  
  9. Submitted-by: Stephen R. van den Berg <berg@messua.informatik.rwth-aachen.de>
  10. Posting-number: Volume 20, Issue 90
  11. Archive-name: procmail2.10/part02
  12. Supersedes: procmail: Volume 20, Issue 49-51,68
  13. Environment: UNIX, sendmail, smail, MMDF
  14.  
  15. ---- Cut Here and feed the following to sh ----
  16. #!/bin/sh
  17. # This is part 02 of procmail
  18. # ============= procmail/includes.h ==============
  19. if test ! -d 'procmail'; then
  20.     echo 'x - creating directory procmail'
  21.     mkdir 'procmail'
  22. fi
  23. if test -f 'procmail/includes.h' -a X"$1" != X"-c"; then
  24.     echo 'x - skipping procmail/includes.h (File already exists)'
  25. else
  26. echo 'x - extracting procmail/includes.h (Text)'
  27. sed 's/^X//' << 'SHAR_EOF' > 'procmail/includes.h' &&
  28. X/*$Id: includes.h,v 2.4 1991/07/03 18:49:25 berg Rel $*/
  29. X
  30. X#include "autoconf.h"
  31. X    /* not all the "library identifiers" specified here need to be
  32. X       available for all programs in this package; some have substitutes
  33. X       as well (see autoconf); this is just an informal list */
  34. X
  35. X#include <unistd.h>        /* open() read() write() close() dup() pipe()
  36. X                   fork() getuid() getpid() execve()
  37. X                   execvp() sleep() */
  38. X#include <stdio.h>        /* sscanf() setbuf() fclose() stdin stdout
  39. X                   stderr fopen() fread() fwrite() fgetc()
  40. X                   getc() putc() fputs() FILE EOF */
  41. X#include <stddef.h>        /* ptrdiff_t size_t sigatomic_t */
  42. X#include <stdlib.h>        /* getenv() malloc() realloc() free()
  43. X                   strtol() */
  44. X#include <time.h>        /* time() ctime() time_t */
  45. X#include <fcntl.h>        /* O_RDONLY O_WRONLY O_APPEND O_CREAT O_EXCL */
  46. X#include <pwd.h>        /* getpwuid() struct passwd */
  47. X#include <sys/wait.h>        /* wait() */
  48. X#include <sys/utsname.h>    /* uname() utsname */
  49. X#include <sys/types.h>        /* pid_t mode_t */
  50. X#include <sys/stat.h>        /* stat() S_ISDIR() struct stat */
  51. X#include <signal.h>        /* signal() kill() alarm() SIG_IGN SIGHUP
  52. X                   SIGINT SIGQUIT SIGALRM SIGTERM */
  53. X#include <string.h>        /* strcpy() strncpy() strcat() strlen()
  54. X                   strspn() strcspn() strchr() strcmp()
  55. X                   strncmp() strpbrk() strstr() memmove() */
  56. X#include <errno.h>        /* EINTR EEXIST EMFILE ENFILE */
  57. X#include <sysexits.h>        /* EX_OK EX_UNAVAILABLE EX_OSERR EX_OSFILE
  58. X                   EX_CANTCREAT EX_IOERR */
  59. X#ifndef O_SYNC
  60. X#define O_SYNC        0
  61. X#endif
  62. X
  63. X#ifndef EOF
  64. X#define EOF    (-1)
  65. X#endif
  66. X
  67. X#ifndef S_ISDIR
  68. X#define S_ISDIR(mode)    (((mode)&S_IFMT)==S_IFDIR)
  69. X#ifndef S_IFMT
  70. X#define S_IFMT    0170000
  71. X#endif
  72. X#ifndef S_IFDIR
  73. X#define S_IFDIR 0040000
  74. X#endif
  75. X#endif
  76. X
  77. Xextern /*const*/char**environ;
  78. Xextern errno;
  79. X
  80. X#ifndef STDIN_FILENO
  81. X#define STDIN    0
  82. X#define STDOUT    1
  83. X#define STDERR    2
  84. X#else
  85. X#define STDIN    STDIN_FILENO
  86. X#define STDOUT    STDOUT_FILENO
  87. X#define STDERR    STDERR_FILENO
  88. X#endif
  89. X
  90. X#define maxindex(x)    (sizeof(x)/sizeof((x)[0])-1)
  91. X#define STRLEN(x)    (sizeof(x)-1)
  92. X
  93. X#define mx(a,b)        ((a)>(b)?(a):(b))
  94. SHAR_EOF
  95. chmod 0644 procmail/includes.h ||
  96. echo 'restore of procmail/includes.h failed'
  97. Wc_c="`wc -c < 'procmail/includes.h'`"
  98. test 2029 -eq "$Wc_c" ||
  99.     echo 'procmail/includes.h: original size 2029, current size' "$Wc_c"
  100. fi
  101. # ============= procmail/README ==============
  102. if test -f 'procmail/README' -a X"$1" != X"-c"; then
  103.     echo 'x - skipping procmail/README (File already exists)'
  104. else
  105. echo 'x - extracting procmail/README (Text)'
  106. sed 's/^X//' << 'SHAR_EOF' > 'procmail/README' &&
  107. XSome legal stuff:
  108. X
  109. XUse this software package at your own risk.  The programmer can not
  110. Xbe held liable for any incurred damages due to the use of this software.
  111. X
  112. XYou are encouraged to distribute this package freely.  This package is
  113. Xhowever not to be sold (minor transfer costs excepted) or included in
  114. Xany commercially sold software package (if you want to do this anyway,
  115. Xcontact me (address below), and we'll work something out).
  116. X
  117. XIf you distribute it, please leave the package in tact.     If you have some
  118. Ximportant changes that might be usefull to the rest of the world, contact
  119. Xme instead.
  120. X
  121. X-------------------------- SYSTEM REQUIREMENTS -------------------------------
  122. X
  123. XA ".forward" file (or equivalent) mechanism for forwarding mail (should work
  124. Xwith (among others?) sendmail, smail and MMDF), *grep or equivalent.
  125. X
  126. XThe most important system calls that need to be supported (among others):
  127. Xfork(),read(),write(),dup(),wait(),pipe(),getpwent()
  128. X
  129. XFor a more complete list of all library references see "includes.h"
  130. X
  131. X------------------------------ DESCRIPTION -----------------------------------
  132. X
  133. XThe procmail mail processing program. (v2.10 1991/07/08)
  134. X
  135. XCan be used to create mail-servers, mailing lists, sort your incoming mail
  136. Xinto separate folders/files (real convenient when subscribing to one or more
  137. Xmailing lists), preprocess your mail, or selectively forward certain incoming
  138. Xmail automatically to someone.
  139. X
  140. XFor installation instructions see the INSTALL file.
  141. X
  142. X----------------------
  143. X
  144. XAlthough I can't guarantee that the procmail program will perform as
  145. Xrequired, I must say that I made the utmost effort to make procmail as
  146. Xrobust as any program can be (every conceivable system error is caught *and*
  147. Xhandled).
  148. X
  149. Xprocmail was designed to deliver the mail under the worst conditions
  150. X(file system full, out of swap space, process table full, file table full,
  151. Xmissing support files, unavailable executables; it all doesn't matter).
  152. XShould (in the unlikely event) procmail be unable to deliver your mail
  153. Xsomewhere, the mail will bounce back to the sender.
  154. X
  155. XFor a more extensive list of features see the FEATURES file.
  156. X
  157. XHowever, as with any program, bugs can not be completely ruled out.
  158. XI tested the program extensively, and believe it should be relatively
  159. Xbug free (no known bug at the time).  Should, however, anyone find any
  160. Xbugs (highly unlikely :-), I would be pleased (well, sort of :-) to hear
  161. Xabout it.  Please send me the patches or bug report.
  162. XI'll look at them and will try to fix it in a future release.
  163. X(BTW, if you should find any spelling or grammar errors in these files,
  164. Xit's not priority one, but if you were sending me mail anyway, don't hesitate
  165. Xto point them out to me; I like correct English just as much as you do).
  166. X
  167. XPlease note that this program essentially is supposed to be static, that
  168. Xmeans no extra features (honouring the VNIX spirit) are supposed to be
  169. Xadded (though any usefull suggestions will be appreciated and evaluated if
  170. Xtime permits).
  171. X
  172. XCheers,
  173. X       Stephen R. van den Berg    at RWTH-Aachen, Germany.
  174. X
  175. XInternet E-mail:        berg@messua.informaik.rwth-aachen.de
  176. X                berg@physik.tu-muenchen.de
  177. X
  178. XOr:    P.O.Box 21074
  179. X    6369 ZG Simpelveld
  180. X    The Netherlands
  181. X
  182. X----------------------
  183. XA recent version can be picked up at various comp.sources.misc archives.
  184. XThe latest version can be obtained directly from the ftp-archive at:
  185. X
  186. X    amaru.informatik.rwth-aachen.de (137.226.112.31)
  187. X
  188. X    as compressed tar file:        pub/unix/procmail.tar.Z
  189. X    or in compressed shar format:    pub/unix/procmail.0?.Z
  190. X----------------------
  191. X
  192. XP.S. I don't mind if you feed the program files through your favourite C
  193. X     beautifier first, so any patches need not necessarily be from the
  194. X     original sources; I apply these patches by hand anyway.
  195. SHAR_EOF
  196. chmod 0644 procmail/README ||
  197. echo 'restore of procmail/README failed'
  198. Wc_c="`wc -c < 'procmail/README'`"
  199. test 3739 -eq "$Wc_c" ||
  200.     echo 'procmail/README: original size 3739, current size' "$Wc_c"
  201. fi
  202. # ============= procmail/STYLE ==============
  203. if test -f 'procmail/STYLE' -a X"$1" != X"-c"; then
  204.     echo 'x - skipping procmail/STYLE (File already exists)'
  205. else
  206. echo 'x - extracting procmail/STYLE (Text)'
  207. sed 's/^X//' << 'SHAR_EOF' > 'procmail/STYLE' &&
  208. XDon't complain about the formatting of my C code.  I know it's unconventional,
  209. Xbut it's my standard format.  If you don't like it, feed it through your
  210. Xfavourite C beautifier.
  211. X
  212. XYes, I do have my reasons for formatting it this way:
  213. X1. consistent, functional indenting
  214. X2. I got used to it
  215. X3. the C compiler doesn't mind at all
  216. X4. I get more program text on my screen when editing, hence I don't have to
  217. X   scroll as often to see other parts of the program while working, (you won't
  218. X   believe this, I know) and therefore it helps to get a better overview of
  219. X   the program
  220. X5. I hate it when I have to scroll back the screen those 5 lines just to see
  221. X   the top of the loop (and then back down to look at the end again, etc.)
  222. X6. This is not a multi-programmer project (if it were, I agree, every one
  223. X   should use a more conventional style), and therefore a good place to show
  224. X   the world some alternatives
  225. X
  226. XAnd, now don't start flaming me about "bad practice", I don't consider this
  227. Xformatting method bad practice.  The only way it distinguishes itself from
  228. Xnormal formatting methods is by the distribution of whitespace (and that is
  229. Xnot even so "bad" since it is properly indented).  This uncommon distribution
  230. Xof whitespace does not make the source harder to read; it just seems that way,
  231. Xbecause you advance less lines in the same time while reading and trying to
  232. Xunderstand the code.  If the code were more conventionally formatted you
  233. Xwould probably advance through the code just as fast, except it would seem
  234. Xto be faster because you scroll more often.
  235. X
  236. XI consider "bad practice" to be unportable or non-ANSI code, which my code is
  237. Xcertainly not.
  238. SHAR_EOF
  239. chmod 0644 procmail/STYLE ||
  240. echo 'restore of procmail/STYLE failed'
  241. Wc_c="`wc -c < 'procmail/STYLE'`"
  242. test 1652 -eq "$Wc_c" ||
  243.     echo 'procmail/STYLE: original size 1652, current size' "$Wc_c"
  244. fi
  245. # ============= procmail/common.c ==============
  246. if test -f 'procmail/common.c' -a X"$1" != X"-c"; then
  247.     echo 'x - skipping procmail/common.c (File already exists)'
  248. else
  249. echo 'x - extracting procmail/common.c (Text)'
  250. sed 's/^X//' << 'SHAR_EOF' > 'procmail/common.c' &&
  251. X/************************************************************************
  252. X *    A some common routines for procmail and formail            *
  253. X *                                    *
  254. X *    Copyright (c) 1990-1991, S.R.van den Berg, The Netherlands    *
  255. X *    The sources can be freely copied for non-commercial use.    *
  256. X *    #include "README"                        *
  257. X *                                    *
  258. X *    #include "STYLE"                        *
  259. X *                                    *
  260. X ************************************************************************/
  261. X#ifdef    RCS
  262. Xstatic char rcsid[]="$Id: common.c,v 2.1 1991/06/19 17:41:41 berg Rel $";
  263. X#endif
  264. X#include "includes.h"
  265. X
  266. Xvoid*tmalloc();
  267. Xextern const char binsh[];
  268. X
  269. X#ifdef NOmemmove
  270. Xvoid*memmove(To,From,count)void*To,*From;register size_t count;{
  271. X#ifdef NObcopy
  272. X register char*to=To,*from=From;/*void*old;*/      /* silly compromise, throw */
  273. X /*old=to;*/count++;--to;--from;   /* away space to be syntactically correct */
  274. X if(to<=from){
  275. X   goto jiasc;
  276. X   do{
  277. X      *++to= *++from;                      /* copy from above */
  278. Xjiasc:;}
  279. X   while(--count);}
  280. X else{
  281. X   to+=count;from+=count;
  282. X   goto jidesc;
  283. X   do{
  284. X      *--to= *--from;                      /* copy from below */
  285. Xjidesc:;}
  286. X   while(--count);}
  287. X return To/*old*/;}
  288. X#else
  289. X bcopy(From,To,count);return To;}
  290. X#endif
  291. X#endif
  292. X
  293. X#include "shell.h"
  294. X
  295. Xshexec(argv)const char*const*argv;{int i;const char**newargv,**p;
  296. X execvp(*argv,argv);     /* if this one fails, we retry it as a shell script */
  297. X for(p=(const char**)argv,i=1;i++,*p++;);          /* count the arguments */
  298. X newargv=malloc(i*sizeof*p);
  299. X for(*(p=newargv)=binsh;*++p= *++argv;);
  300. X execve(*newargv,newargv,environ);          /* no shell script? -> trouble */
  301. X log("Failed to execute");logqnl(*argv);exit(EX_UNAVAILABLE);}
  302. SHAR_EOF
  303. chmod 0644 procmail/common.c ||
  304. echo 'restore of procmail/common.c failed'
  305. Wc_c="`wc -c < 'procmail/common.c'`"
  306. test 1610 -eq "$Wc_c" ||
  307.     echo 'procmail/common.c: original size 1610, current size' "$Wc_c"
  308. fi
  309. # ============= procmail/exopen.c ==============
  310. if test -f 'procmail/exopen.c' -a X"$1" != X"-c"; then
  311.     echo 'x - skipping procmail/exopen.c (File already exists)'
  312. else
  313. echo 'x - extracting procmail/exopen.c (Text)'
  314. sed 's/^X//' << 'SHAR_EOF' > 'procmail/exopen.c' &&
  315. X/************************************************************************
  316. X *    Collection of NFS secure exclusive open routines        *
  317. X *                                    *
  318. X *    Copyright (c) 1990-1991, S.R.van den Berg, The Netherlands    *
  319. X *    The sources can be freely copied for non-commercial use.    *
  320. X *    #include "README"                        *
  321. X *                                    *
  322. X *    #include "STYLE"                        *
  323. X *                                    *
  324. X ************************************************************************/
  325. X#ifdef    RCS
  326. Xstatic char rcsid[]="$Id: exopen.c,v 2.0 1991/06/10 14:35:35 berg Rel $";
  327. X#endif
  328. X#include "config.h"
  329. X#include "includes.h"
  330. X#include "exopen.h"
  331. X
  332. Xconst char*hostname();
  333. Xextern pid_t thepid;
  334. X
  335. Xconst char*hostname(){static char name[HOSTNAMElen+1];
  336. X#ifdef    NOuname
  337. X gethostname(name,HOSTNAMElen+1);
  338. X#else
  339. X struct utsname names;
  340. X uname(&names);strncpy(name,names.nodename,HOSTNAMElen);
  341. X#endif
  342. X name[HOSTNAMElen]='\0';return name;}
  343. X
  344. Xultoan(val,dest)unsigned long val;char*dest;{register i;       /* convert to */
  345. X do{                    /* a number within the set [0-9A-Za-z-_] */
  346. X    i=val&0x3f;
  347. X    *dest++=i+(i<10?'0':i<10+26?'A'-10:i<10+26+26?'a'-10-26:
  348. X       i==10+26+26?'-'-10-26-26:'_'-10-26-27);}
  349. X while(val>>=6);
  350. X *dest='\0';}
  351. X
  352. Xunique(full,p,mode)const char*const full;char*const p;const mode_t mode;{
  353. X unsigned long retry=3;int i;              /* create unique file name */
  354. X do{
  355. X   ultoan(SERIALmask&(retry<<16)+(unsigned long)thepid,p+1);
  356. X   *p='_';strcat(p,hostname());}
  357. X while(0>(i=ropen(full,O_WRONLY|O_CREAT|O_EXCL|O_SYNC,mode))&&errno==EEXIST
  358. X   &&retry--);        /* casually check if it already exists (highly unlikely) */
  359. X if(i<0){
  360. X   writeerr(full);return 0;}
  361. X rclose(i);return 1;}
  362. X                     /* rename MUST fail if already existent */
  363. Xmyrename(old,new)const char*const old,*const new;{int i,serrno;
  364. X i=link(old,new);serrno=errno;unlink(old);errno=serrno;return i;}
  365. SHAR_EOF
  366. chmod 0644 procmail/exopen.c ||
  367. echo 'restore of procmail/exopen.c failed'
  368. Wc_c="`wc -c < 'procmail/exopen.c'`"
  369. test 1788 -eq "$Wc_c" ||
  370.     echo 'procmail/exopen.c: original size 1788, current size' "$Wc_c"
  371. fi
  372. # ============= procmail/Manifest ==============
  373. if test -f 'procmail/Manifest' -a X"$1" != X"-c"; then
  374.     echo 'x - skipping procmail/Manifest (File already exists)'
  375. else
  376. echo 'x - extracting procmail/Manifest (Text)'
  377. sed 's/^X//' << 'SHAR_EOF' > 'procmail/Manifest' &&
  378. XMakefile    We all know what that is.
  379. XREADME        Important, read it.
  380. XINSTALL        A description of what has to be done to install procmail.
  381. XHISTORY        Recent and ancient changes, features (or bugs) documented.
  382. XFEATURES    A summary of all the things procmail is particularly good at.
  383. XSTYLE        A short explanation of why the source looks so "awkward"
  384. Xlockfile.c    main program for lockfile
  385. Xformail.c    main program for formail
  386. XManifest    You guessed it.
  387. Xprocmail.c    main program for procmail.
  388. Xnonint.c    Collection of routines that don't return ints.
  389. Xretint.c    Collection of routines that return ints.
  390. Xgoodies.c    Some real nice routines, deserve to be put in a library.
  391. Xcommon.c    Some routines that are used by procmail and formail.
  392. Xexopen.c    Collection of routines about an NFS secure excl. open.
  393. Xexopen.h    The very same.
  394. Xprocmail.h    Include file with all declarations.
  395. X
  396. Xincludes.h    System include files are all referenced here.
  397. Xconfig.h    The file to edit if you want to change, yes, the configuration.
  398. Xautoconf    The shell script that seizes your compiler and machine,
  399. X        and then creates a file called autoconf.h describing the
  400. X        kludges that are going to be applied for your installation.
  401. X
  402. Xshell.h        Defines a few 'shell' macros for malloc and the like.
  403. Xman/*        Yes, the man pages (made in a labour camp).
  404. Xinclude/*    A few files that are supposed to fool your compiler into
  405. X        thinking that it has ANSI and POSIX conforming include files.
  406. Xexamples/?procmailrc
  407. X        Sample .procmailrc files.
  408. Xexamples/?rmail
  409. X        Sample shell scripts that demonstrate how to use
  410. X        lockfiles while reading the mail (to ensure mail integrity
  411. X        as soon as you exit the mail program).
  412. Xexamples/forward
  413. X        A sample .forward file.
  414. Xexamples/advanced
  415. X        Some extra info for network mounted mailboxes, examples of
  416. X        advanced .procmailrc expressions and using procmail as
  417. X        a local delivery agent.
  418. SHAR_EOF
  419. chmod 0644 procmail/Manifest ||
  420. echo 'restore of procmail/Manifest failed'
  421. Wc_c="`wc -c < 'procmail/Manifest'`"
  422. test 1824 -eq "$Wc_c" ||
  423.     echo 'procmail/Manifest: original size 1824, current size' "$Wc_c"
  424. fi
  425. # ============= procmail/lockfile.c ==============
  426. if test -f 'procmail/lockfile.c' -a X"$1" != X"-c"; then
  427.     echo 'x - skipping procmail/lockfile.c (File already exists)'
  428. else
  429. echo 'x - extracting procmail/lockfile.c (Text)'
  430. sed 's/^X//' << 'SHAR_EOF' > 'procmail/lockfile.c' &&
  431. X/************************************************************************
  432. X *    lockfile.c    a conditional semaphore-file creator        *
  433. X *                                    *
  434. X *    Seems to be perfect.                        *
  435. X *                                    *
  436. X *    Created by S.R.van den Berg, The Netherlands            *
  437. X *    This file can be freely copied for any use.            *
  438. X ************************************************************************/
  439. X#ifdef    RCS
  440. Xstatic char rcsid[]="$Id: lockfile.c,v 2.4 1991/07/04 17:03:11 berg Rel $";
  441. X#endif
  442. Xstatic char rcsdate[]="$Date: 1991/07/04 17:03:11 $";
  443. X#include "config.h"               /* overkill, I know, only need DIRSEP */
  444. X#include "includes.h"
  445. X
  446. Xvolatile int exitflag;
  447. Xpid_t thepid;
  448. Xconst char dirsep[]=DIRSEP;
  449. X
  450. Xvoid failure(){
  451. X exitflag=1;}
  452. X
  453. Xmain(argc,argv)const int argc;const char*argv[];{const char**p,*cp;
  454. X int sleepsec,retries,invert,force,suspend,retval=0;
  455. X static char usage[]=
  456. X   "Usage: lockfile -nnn | -rnnn | -! | -lnnn | -snnn | file ...\n";
  457. X sleepsec=8;force=retries=invert=0;suspend=16;thepid=getpid();
  458. X if(argc<2){
  459. X   putse(usage);return EX_USAGE;}
  460. Xagain:
  461. X p=argv+1;signal(SIGHUP,failure);signal(SIGINT,failure);
  462. X signal(SIGQUIT,failure);signal(SIGTERM,failure);
  463. X while(*p)
  464. X    if(*(cp= *p++)=='-')
  465. X       switch(cp[1]){
  466. X       case '!':invert=1;break;
  467. X       case 'r':retries=strtol(cp+2,(char**)0,10);break;
  468. X       case 'l':force=strtol(cp+2,(char**)0,10);break;
  469. X       case 's':suspend=strtol(cp+2,(char**)0,10);break;
  470. X       default:
  471. X      if(cp[1]-'0'>(unsigned)9){
  472. X         putse(usage);retval=EX_USAGE;goto failurel;}
  473. X      if(sleepsec>=0)
  474. X         sleepsec=strtol(cp+1,(char**)0,10);}
  475. X    else
  476. X      if(sleepsec<0)
  477. X     unlink(cp);
  478. X      else{
  479. X     while(0>NFSxopen(cp)){struct stat buf;time_t t;
  480. X        if(exitflag||retries==1){
  481. Xfailurel:      sleepsec= -1;p[-1]=0;goto again;}
  482. X        if(force&&(t=time((time_t*)0),!stat(cp,&buf))&&
  483. X           force<t-buf.st_mtime){
  484. X           unlink(cp);putse("Forcing lock on \"");putse(cp);putse("\"\n");
  485. X           sleep(suspend);}
  486. X        else
  487. X           sleep(sleepsec);
  488. X        if(retries)
  489. X           retries--;}}
  490. Xreturn retval?retval:invert^(sleepsec<0)?EX_CANTCREAT:EX_OK;}
  491. X
  492. Xputse(a)char*a;{char*b;
  493. X b=a-1;
  494. X while(*++b);
  495. X write(STDERR,a,(size_t)(b-a));}
  496. X
  497. X#include "exopen.h"
  498. X
  499. XNFSxopen(name)char*name;{char*p,*q;int j= -1,i;
  500. X for(q=name;p=strpbrk(q,dirsep);q=p+1);
  501. X i=q-name;
  502. X if(!(p=malloc(i+UNIQnamelen)))
  503. X    return exitflag=1;
  504. X strncpy(p,name,i);
  505. X if(unique(p,p+i,0))
  506. X   j=myrename(p,name);
  507. X free(p);return j;}
  508. X
  509. Xvoid*tmalloc(len)const size_t len;{                     /* stub */
  510. X return malloc(len);}
  511. X
  512. Xropen(name,mode,mask)const char*const name;const int mode;const mode_t mask;{
  513. X return open(name,mode,mask);}                         /* stub */
  514. X
  515. Xrclose(fd)const int fd;{                         /* stub */
  516. X return close(fd);}
  517. X
  518. Xwriteerr(a)const char*const a;{}                     /* stub */
  519. SHAR_EOF
  520. chmod 0644 procmail/lockfile.c ||
  521. echo 'restore of procmail/lockfile.c failed'
  522. Wc_c="`wc -c < 'procmail/lockfile.c'`"
  523. test 2723 -eq "$Wc_c" ||
  524.     echo 'procmail/lockfile.c: original size 2723, current size' "$Wc_c"
  525. fi
  526. # ============= procmail/goodies.c ==============
  527. if test -f 'procmail/goodies.c' -a X"$1" != X"-c"; then
  528.     echo 'x - skipping procmail/goodies.c (File already exists)'
  529. else
  530. echo 'x - extracting procmail/goodies.c (Text)'
  531. sed 's/^X//' << 'SHAR_EOF' > 'procmail/goodies.c' &&
  532. X/************************************************************************
  533. X *    Collection of library-worthy routines                *
  534. X *                                    *
  535. X *    Copyright (c) 1990-1991, S.R.van den Berg, The Netherlands    *
  536. X *    The sources can be freely copied for non-commercial use.    *
  537. X *    #include "README"                        *
  538. X *                                    *
  539. X *    #include "STYLE"                        *
  540. X *                                    *
  541. X ************************************************************************/
  542. X#ifdef    RCS
  543. Xstatic char rcsid[]="$Id: goodies.c,v 2.4 1991/07/08 14:29:31 berg Rel $";
  544. X#endif
  545. X#include "config.h"
  546. X#include "procmail.h"
  547. X#include "shell.h"
  548. X
  549. X#define NOTHING_YET    (-1)    /* readparse understands a very complete    */
  550. X#define SKIPPING_SPACE    0    /* subset of the standard /bin/sh syntax    */
  551. X#define NORMAL_TEXT    1    /* that includes single-, double- and back- */
  552. X#define DOUBLE_QUOTED    2    /* quotes, backslashes and $subtitutions    */
  553. X#define SINGLE_QUOTED    3
  554. X
  555. X/* sarg==0 : normal parsing, split up arguments like in /bin/sh
  556. X * sarg==1 : environment assignment parsing, parse up till first whitespace
  557. X * sarg==2 : normal parsing, split up arguments by single spaces
  558. X */
  559. Xreadparse(p,fgetc,sarg)register char*p;int(*const fgetc)();
  560. X const int sarg;{static i;int got;char*startb;
  561. X for(got=NOTHING_YET;;){            /* buf2 is used as scratch space */
  562. Xloop:
  563. X   i=fgetc();
  564. X   if(buf+linebuf-3<p){            /* doesn't catch everything, just a hint */
  565. X      log("Exceeded LINEBUF\n");p=buf+linebuf-3;goto ready;}
  566. Xnewchar:
  567. X   switch(i){
  568. X      case EOF:
  569. X     if(got>NORMAL_TEXT)
  570. Xearly_eof:  log(unexpeof);
  571. Xready:     if(got!=SKIPPING_SPACE||sarg)      /* not terminated yet or sarg==2 ? */
  572. X        *p++='\0';
  573. X     *p=TMNATE;return;
  574. X      case '\\':
  575. X     if(got==SINGLE_QUOTED)
  576. X        break;
  577. X     switch(i=fgetc()){
  578. X        case EOF:goto early_eof;              /* can't quote EOF */
  579. X        case '\n':continue;                /* concatenate lines */
  580. X        case '#':
  581. X           if(got>SKIPPING_SPACE)    /* escaped comment at start of word? */
  582. X          goto noesc;            /* apparently not, literally */
  583. X        case ' ':case '\t':case '\'':
  584. X           if(got==DOUBLE_QUOTED)
  585. X          goto noesc;
  586. X        case '"':case '\\':case '$':case '`':goto nodelim;}
  587. X     if(got>NORMAL_TEXT)
  588. Xnoesc:        *p++='\\';            /* nothing to escape, just echo both */
  589. X     break;
  590. X      case '`':
  591. X     if(got==SINGLE_QUOTED)
  592. X        goto nodelim;
  593. X     for(startb=p;;){                   /* mark your position */
  594. X        switch(i=fgetc()){             /* copy till next backquote */
  595. X           case '\\':
  596. X          switch(i=fgetc()){
  597. X             case EOF:log(unexpeof);goto forcebquote;
  598. X             case '\n':continue;
  599. X             case '"':
  600. X            if(got!=DOUBLE_QUOTED)
  601. X               break;
  602. X             case '\\':case '$':case '`':goto escaped;}
  603. X          *p++='\\';break;
  604. X           case '"':
  605. X          if(got!=DOUBLE_QUOTED)       /* missing closing backquote? */
  606. X             break;
  607. Xforcebquote:   case EOF:case '`':*p='\0';
  608. X          if(!(sh=!!strpbrk(startb,tgetenv(shellmetas)))){
  609. X             const char*save=sgetcp;
  610. X             sgetcp=p=tstrdup(startb);readparse(startb,sgetc,0);
  611. X             free(p);sgetcp=save;} /* chopped up, drop source buffer */
  612. X          startb=fromprog(p=startb,startb);    /* read from program */
  613. X          if(!sarg&&got!=DOUBLE_QUOTED){
  614. X             i=0;startb=p;goto simplsplit;}          /* split it up */
  615. X          if(i=='"'||got<=SKIPPING_SPACE)     /* missing closing ` ? */
  616. X             got=NORMAL_TEXT;                 /* or sarg!=0 ? */
  617. X          p=startb;goto loop;
  618. X           case '\n':i=';';}           /* newlines separate commands */
  619. Xescaped:    *p++=i;}
  620. X      case '"':
  621. X     switch(got){
  622. X        case DOUBLE_QUOTED:got=NORMAL_TEXT;continue;    /* closing " */
  623. X        case SINGLE_QUOTED:goto nodelim;}
  624. X     got=DOUBLE_QUOTED;continue;                /* opening " */
  625. X      case '\'':
  626. X     switch(got){
  627. X        case DOUBLE_QUOTED:goto nodelim;
  628. X        case SINGLE_QUOTED:got=NORMAL_TEXT;continue;}    /* closing ' */
  629. X     got=SINGLE_QUOTED;continue;                /* opening ' */
  630. X      case '#':
  631. X     if(got>SKIPPING_SPACE)            /* comment at start of word? */
  632. X        break;
  633. X     while((i=fgetc())!=EOF&&i!='\n');            /* skip till EOL */
  634. X     goto ready;
  635. X      case '$':
  636. X     if(got==SINGLE_QUOTED)
  637. X        break;
  638. X     if(EOF==(i=fgetc())){
  639. X        *p++='$';goto ready;}
  640. X     startb=buf2;
  641. X     if(i=='{'){                          /* ${name} */
  642. X        while(EOF!=(i=fgetc())&&alphanum(i))
  643. X           *startb++=i;
  644. X        *startb='\0';
  645. X        if(i!='}'){
  646. X           log("Bad substitution of");logqnl(buf2);continue;}
  647. X        i='\0';}
  648. X     else if(alphanum(i)){                        /* $name */
  649. X        do *startb++=i;
  650. X        while(EOF!=(i=fgetc())&&alphanum(i));
  651. X        if(i==EOF)
  652. X           i='\0';
  653. X        *startb='\0';}
  654. X     else if(i=='$'){                      /* $$ =pid */
  655. X        ultstr(0,(unsigned long)thepid,p);goto ieofstr;}
  656. X     else if(i=='-'){                   /* $- =lastfolder */
  657. X        strcpy(p,lastfolder);
  658. Xieofstr:    i='\0';goto eofstr;}
  659. X     else{
  660. X        *p++='$';goto newchar;}               /* not a substitution */
  661. X     startb=(char*)tgetenv(buf2);
  662. X     if(!sarg&&got!=DOUBLE_QUOTED)
  663. Xsimplsplit: for(;;startb++){          /* simply split it up in arguments */
  664. X           switch(*startb){
  665. X          case ' ':case '\t':case '\n':
  666. X             if(got<=SKIPPING_SPACE)
  667. X            continue;
  668. X             *p++='\0';got=SKIPPING_SPACE;continue;
  669. X          case '\0':goto eeofstr;}
  670. X           *p++= *startb;got=NORMAL_TEXT;}
  671. X     else{
  672. X        if(got<=SKIPPING_SPACE)        /* can only occur if sarg!=0 */
  673. X           got=NORMAL_TEXT;
  674. X        strcpy(p,startb);                   /* simply copy it */
  675. Xeofstr:        p=strchr(p,'\0');}
  676. Xeeofstr: if(i)                     /* already read next character? */
  677. X        goto newchar;
  678. X     continue;
  679. X      case ' ':case '\t':
  680. X     switch(got){
  681. X        case NORMAL_TEXT:
  682. X           if(sarg==1)
  683. X          goto ready;        /* already fetched a single argument */
  684. X           got=SKIPPING_SPACE;*p++=sarg?' ':'\0';     /* space or \0 sep. */
  685. X        case NOTHING_YET:case SKIPPING_SPACE:continue;}    /* skip space */
  686. X      case '\n':
  687. X     if(got<=NORMAL_TEXT)
  688. X        goto ready;}                /* EOL means we're ready */
  689. Xnodelim:
  690. X   *p++=i;                       /* ah, a normal character */
  691. X   if(got<=SKIPPING_SPACE)         /* should we bother to change mode? */
  692. X      got=NORMAL_TEXT;}}
  693. X
  694. Xultstr(minwidth,val,dest)unsigned long val;char*dest;{int i;unsigned long j;
  695. X j=val;i=0;                       /* a beauty, isn't it :-) */
  696. X do i++;                       /* determine needed width */
  697. X while(j/=10);
  698. X while(--minwidth>=i)                 /* fill up any excess width */
  699. X   *dest++=' ';
  700. X *(dest+=i)='\0';
  701. X do *--dest='0'+val%10;                  /* display value backwards */
  702. X while(val/=10);}
  703. X
  704. Xsputenv(a)char*a;{          /* smart putenv, the way it was supposed to be */
  705. X static struct lienv{struct lienv*next;char name[255];}*myenv;
  706. X static alloced;int i,remove;char*split,**preenv;struct lienv*curr,**last;
  707. X yell("Assigning",a);remove=0;a=tstrdup(a);        /* make working copy */
  708. X if(!(split=strchr(a,'='))){               /* assignment or removal? */
  709. X    remove=1;i=strlen(a);*(split=i+(a=realloc(a,i+2)))='=';
  710. X    split[1]='\0';}
  711. X i= ++split-a;
  712. X for(curr= *(last= &myenv);curr;curr= *(last= &curr->next))
  713. X   if(!strncmp(a,curr->name,i)){         /* is it one I created earlier? */
  714. X      split=curr->name;*last=curr->next;free(curr);
  715. X      for(preenv=environ;*preenv!=split;preenv++);
  716. X      goto wipenv;}
  717. X for(preenv=environ;*preenv;preenv++)
  718. X   if(!strncmp(a,*preenv,i)){           /* is it in the standard environment? */
  719. Xwipenv:
  720. X      while(*preenv=preenv[1])       /* wipe this entry out of the environment */
  721. X     preenv++;
  722. X      break;}
  723. X i=(preenv-environ+2)*sizeof*environ;
  724. X if(alloced)           /* have we ever alloced the environ array before? */
  725. X   environ=realloc(environ,i);
  726. X else{
  727. X   alloced=1;environ=tmemmove(malloc(i),environ,i-sizeof*environ);}
  728. X if(!remove){          /* if not remove, then add it to both environments */
  729. X   for(preenv=environ;*preenv;preenv++);
  730. X   curr=malloc(curr->name-(char*)curr+strlen(a)+1);
  731. X   strcpy(*preenv=curr->name,a);free(a);preenv[1]=0;curr->next=myenv;
  732. X   myenv=curr;}}
  733. SHAR_EOF
  734. chmod 0644 procmail/goodies.c ||
  735. echo 'restore of procmail/goodies.c failed'
  736. Wc_c="`wc -c < 'procmail/goodies.c'`"
  737. test 7495 -eq "$Wc_c" ||
  738.     echo 'procmail/goodies.c: original size 7495, current size' "$Wc_c"
  739. fi
  740. # ============= procmail/procmail.c ==============
  741. if test -f 'procmail/procmail.c' -a X"$1" != X"-c"; then
  742.     echo 'x - skipping procmail/procmail.c (File already exists)'
  743. else
  744. echo 'x - extracting procmail/procmail.c (Text)'
  745. sed 's/^X//' << 'SHAR_EOF' > 'procmail/procmail.c' &&
  746. X/************************************************************************
  747. X *    procmail.c    an autonomous mail processor            *
  748. X *                                    *
  749. X *    Seems to be perfect.                        *
  750. X *                                    *
  751. X *    Copyright (c) 1990-1991, S.R.van den Berg, The Netherlands    *
  752. X *    The sources can be freely copied for non-commercial use.    *
  753. X *    #include "README"                        *
  754. X *                                    *
  755. X *    #include "STYLE"                        *
  756. X *                                    *
  757. X ************************************************************************/
  758. X#ifdef    RCS
  759. Xstatic char rcsid[]="$Id: procmail.c,v 2.9 1991/07/08 13:03:07 berg Rel $";
  760. X#endif
  761. X#include "config.h"
  762. X#define MAIN
  763. X#include "procmail.h"
  764. X#include "shell.h"
  765. X
  766. X#define VERSION "procmail v2.10 1991/07/08 written by Stephen R.van den Berg\n\
  767. X\t\t\t\tberg@messua.informatik.rwth-aachen.de\n\
  768. X\t\t\t\tberg@physik.tu-muenchen.de\n"
  769. X
  770. Xchar*buf,*buf2,*globlock,*loclock,*tolock,*lastfolder;
  771. Xconst char grep[]="GREP",shellflags[]="SHELLFLAGS",shell[]="SHELL",
  772. X shellmetas[]="SHELLMETAS",lockext[]="LOCKEXT",newline[]="\n",binsh[]=BinSh,
  773. X unexpeof[]="Unexpected EOL\n",*const*gargv,*sgetcp,*rcfile=PROCMAILRC,
  774. X dirsep[]=DIRSEP,msgprefix[]="MSGPREFIX",devnull[]=DevNull,
  775. X executing[]="Executing",oquote[]=" \"",cquote[]="\"\n",
  776. X whilstwfor[]=" whilst waiting for ";
  777. Xstatic const char linebufs[]="LINEBUF",tokey[]=TOkey,eumask[]="UMASK",
  778. X tosubstitute[]=TOsubstitute,lockfile[]="LOCKFILE",defaultf[]="DEFAULT",
  779. X maildir[]="MAILDIR",couldnread[]="Couldn't read",logfile[]="LOGFILE",
  780. X orgmail[]="ORGMAIL",user[]="USER",tmp[]=Tmp,home[]="HOME",sfolder[]=FOLDER,
  781. X sendmail[]="SENDMAIL",host[]="HOST",Log[]="LOG",From[]=SFROM;
  782. Xstruct varval strenvvar[]={{"LOCKSLEEP",DEFlocksleep},
  783. X {"LOCKTIMEOUT",DEFlocktimeout},{"SUSPEND",DEFsuspend},
  784. X {"NORESRETRY",DEFnoresretry},{"TIMEOUT",DEFtimeout}};
  785. Xlong lastdump;
  786. Xint retval=EX_CANTCREAT,sh,pwait,lcking,locknext,verbose,linebuf=DEFlinebuf,
  787. X rc= -1;
  788. Xvolatile int flaggerd=2,nextexit;
  789. Xvolatile time_t alrmtime;
  790. Xpid_t thepid;
  791. X
  792. Xmain(argc,argv)const char*const argv[];{static char flags[NRRECFLAGS];
  793. X char*themail,*thebody,*chp,*startchar,*chp2;long tobesent,filled;
  794. X int i,lastcond=0;
  795. X if((chp=(char*)argv[argc=1])&&*chp=='-'&&*++chp&&!chp[1])
  796. X   switch(*chp){             /* these options are mutually exclusive */
  797. X      case VERSIONOPT:log(VERSION);return EX_OK;
  798. X      case DEBUGOPT:verbose=1;
  799. X      default:*environ=0;
  800. X      case PRESERVOPT:argc++;}
  801. X else
  802. X   *environ=0;                         /* drop the environment */
  803. X gargv=argv+argc;umask(077);thepid=getpid();fclose(stdout);fclose(stderr);
  804. X rclose(STDOUT);rclose(STDERR);            /* don't trust the stdio library */
  805. X if(0>opena(devnull)||0>opena(console))
  806. X   return EX_OSFILE;
  807. X setbuf(stdin,(char*)0);buf=malloc(linebuf);buf2=malloc(linebuf);chdir(tmp);
  808. X ultstr(0,(unsigned long)(i=getuid()),buf);
  809. X setpwent();
  810. X {struct passwd*pass;
  811. X if(pass=getpwuid(i)){            /* find user defaults in /etc/passwd */
  812. X   setdef(home,pass->pw_dir);chdir(pass->pw_dir);
  813. X   setdef(user,pass->pw_name?pass->pw_name:buf);setdef(shell,pass->pw_shell);}
  814. X else{             /* user could not be found, set reasonable defaults */
  815. X   setdef(home,tmp);setdef(user,buf);setdef(shell,binsh);}}
  816. X endpwent();setdef(shellmetas,DEFshellmetas);setdef(shellflags,DEFshellflags);
  817. X setdef(maildir,DEFmaildir);setdef(defaultf,DEFdefault);
  818. X setdef(orgmail,DEForgmail);setdef(grep,DEFgrep);setdef(sendmail,DEFsendmail);
  819. X setdef(lockext,DEFlockext);setdef(msgprefix,DEFmsgprefix);
  820. X chdir(getenv(maildir));nextrcfile();thebody=themail=malloc(1);filled=0;
  821. X signal(SIGTERM,sterminate);signal(SIGINT,sterminate);
  822. X signal(SIGHUP,sterminate);signal(SIGQUIT,flagger);signal(SIGALRM,ftimeout);
  823. Xchangedmail:
  824. X themail=readdyn(themail,&filled);             /* read in the mail */
  825. Xonlyhead:
  826. X startchar=filled+(thebody=themail);
  827. X while(thebody<startchar&&*thebody++=='\n');         /* skip leading garbage */
  828. X while(thebody<startchar&&startchar>(thebody=findnl(thebody,startchar)))
  829. X   switch(*thebody++){
  830. X      case '\n':goto eofheader;           /* empty line marks end of header */
  831. X      case '\t':case ' ':thebody[-2]=' ';}  /* concatenate continuated lines */
  832. Xeofheader:
  833. X if((chp=thebody)<startchar){
  834. X   goto firstel;                 /* search for bogus headers */
  835. X   do{
  836. X      if(*chp++!='\n'||chp==startchar)        /* is the line really empty? */
  837. X     continue;
  838. Xfirstel:
  839. X      *startchar='\0';           /* put a terminator at the end for sscanf */
  840. X      if(0>=sscanf(chp,FromSCAN,buf)){
  841. X     chp--;continue;}          /* no match, back up, and on we go */
  842. X      tmemmove(chp+1,chp,startchar++-chp);*chp='>';    /* insert '>' before */
  843. X      themail=realloc(chp2=themail,++filled+1);             /* bogus header */
  844. X#define ADJUST(x)    ((x)=themail+((x)-chp2))
  845. X      ADJUST(thebody);ADJUST(startchar);ADJUST(chp);}/* find next empty line */
  846. X while(startchar>(chp=findnl(chp,startchar)));}
  847. Xdo{                         /* main rcfile interpreter loop */
  848. X   while(chp=(char*)argv[argc]){       /* interpret command line specs first */
  849. X      argc++;strcpy(buf,chp);
  850. X      if(chp=strchr(buf,'=')){
  851. X     strcpy(sgetcp=buf2,++chp);readparse(chp,sgetc,2);goto argenv;}}
  852. X   if(rc<0)                         /* open new rc file */
  853. X      while(*buf='\0',0>bopen(strcat(
  854. X     strchr(dirsep,*rcfile)?buf:cat(tgetenv(home),MCDIRSEP),rcfile))){
  855. X     log(couldnread);logqnl(buf);
  856. X     if(!nextrcfile())              /* not available? try the next */
  857. X        goto nomore_rc;}
  858. X   unlock(&loclock);alarm((unsigned)(alrmtime=0));          /* reset alarm */
  859. X   do skipspace();                      /* skip whitespace */
  860. X   while(testb('\n'));
  861. X   if(testb(':')){                       /* check for a recipe */
  862. X      readparse(buf,getb,2);sh= -1;*buf2='\0';
  863. X      if(0>=sscanf(buf,"%d%[^\n]",&sh,buf2))         /* nr of conditions */
  864. X     strcpy(buf2,buf);
  865. X      *buf= *flags='\0';
  866. X      if(0>=sscanf(buf2,RECFLAGS,flags,buf)){           /* read the flags */
  867. X     strcpy(buf,buf2);}
  868. X      if(sh<0)          /* assume the appropriate default nr of conditions */
  869. X     sh=!strchr(flags,'A');
  870. X      if(tolock)         /* clear temporary buffer for lockfile name */
  871. X     free(tolock);
  872. X      tolock=0;*buf2='\0';
  873. X      if((locknext=':'==*buf)&&0<sscanf(buf,": %[^ \t\n] %[^\n]",buf,buf2))
  874. X     tolock=tstrdup(buf);            /* yep, local lockfile specified */
  875. X      if(*buf2)
  876. X     skipped(buf2);                    /* display any leftovers */
  877. X      startchar=themail;tobesent=thebody-themail;
  878. X      if(strchr(flags,'B'))        /* what needs to be piped into grep? */
  879. X     if(strchr(flags,'H'))
  880. X        tobesent=filled;
  881. X     else{
  882. X        startchar=thebody;tobesent=filled-tobesent;}
  883. X      i=strchr(flags,'A')?lastcond:1;              /* init test value */
  884. X      while(sh--){                    /* any conditions (left) */
  885. X     getbl(buf2);
  886. X     if(!strncmp(buf2,tokey,STRLEN(tokey)))             /* magic TOkey? */
  887. X        cat(tosubstitute,buf2+STRLEN(tokey));
  888. X     else if(*buf=='!'&&!strncmp(buf2+1,tokey,STRLEN(tokey))) /* !TOkey? */
  889. X        strcat(cat("!",tosubstitute),buf2+1+STRLEN(tokey));
  890. X     else
  891. X        strcpy(buf,buf2);
  892. X     if(i){                     /* check out all conditions */
  893. X        i=!grepin((*buf=='!'||*buf=='\\')+buf,startchar,tobesent,
  894. X           !!strchr(flags,'D'))^*buf=='!';
  895. X        if(verbose){
  896. X           log(i?"M":"No m");log("atch on");logqnl(buf);}}}
  897. X      if(!strchr(flags,'A'))           /* save the outcome for posterity */
  898. X     lastcond=i;
  899. X      startchar=themail;tobesent=filled;        /* body, header or both? */
  900. X      if(strchr(flags,'h')){
  901. X     if(!strchr(flags,'b'))
  902. X        tobesent=thebody-themail;}
  903. X      else if(strchr(flags,'b'))
  904. X     tobesent-=(startchar=thebody)-themail;
  905. X      chp=strchr(strcpy(buf,tgetenv(sendmail)),'\0');sh=0;
  906. X      pwait=!!strchr(flags,'w');
  907. X      if(testb('!')){                     /* forward the mail */
  908. X     readparse(chp+1,getb,0);
  909. X     if(i)
  910. X        goto forward;}
  911. X      else if(testb('|')){                    /* pipe the mail */
  912. X     getbl(buf2);
  913. X     for(chp=buf2;*(chp=strchr(chp,'\0')-1)=='\\'&&getbl(chp););
  914. X     if(i){
  915. X        if(sh=!!strpbrk(buf2,tgetenv(shellmetas)))
  916. X           strcpy(buf,buf2);     /* copy literally, shell will parse */
  917. X        else{
  918. X           sgetcp=buf2;readparse(buf,sgetc,0);}    /* parse it yourself */
  919. Xforward:    chp=buf;*buf2='\0';
  920. X        while(i= *chp)     /* find the implicit lockfile name ('>>name') */
  921. X          if(chp++,i=='>'&&*chp=='>'){
  922. X         while((i= *++chp)==' '||i=='\t');
  923. X         sscanf(chp,EOFName,buf2);break;}
  924. X        lcllock();inittmout(buf);
  925. X        if(strchr(flags,'f')){
  926. X           if(startchar==themail&&tobesent!=filled){      /* if only 'h' */
  927. X          long dfilled=0;
  928. X          if(pipthrough(buf,startchar,tobesent))
  929. X             continue;
  930. X          chp=readdyn(malloc(1),&dfilled);filled-=tobesent;
  931. X          if(tobesent<dfilled)       /* adjust buffer size (grow only) */
  932. X             themail=realloc(themail,dfilled+filled);
  933. X          tmemmove(themail+dfilled,thebody,filled);
  934. X          tmemmove(themail,chp,dfilled);free(chp);
  935. X          themail=realloc(themail,1+(filled+=dfilled));goto onlyhead;}
  936. X           if(pipthrough(buf,startchar,tobesent))
  937. X          continue;
  938. X           filled=startchar-themail;goto changedmail;}
  939. X        if(!pipin(buf,startchar,tobesent)&&!strchr(flags,'c'))
  940. X           goto mailed;}}
  941. X      else{           /* dump the mail into a mailbox file or directory */
  942. X     readparse(buf,getb,0);chp2=chp=strchr(buf,'\0')+1;
  943. X     while(*chp!=TMNATE){          /* concatenate all other arguments */
  944. X        while(*chp++);
  945. X        chp[-1]=' ';}
  946. X     *chp=chp[-1]='\0';
  947. X     if(*chp2)
  948. X        skipped(chp2);                 /* report any leftovers */
  949. X     if(i){
  950. X        strcpy(buf2,buf);lcllock();strcpy(buf2,buf);
  951. X        if(dump(deliver(buf2),startchar,tobesent))
  952. X           writeerr(buf);
  953. X        else if(!strchr(flags,'c'))
  954. X           goto mailed;}}}
  955. X   else if(testb('#'))                       /* no comment :-) */
  956. X      getbl(buf);
  957. X   else{                    /* then it must be an assignment */
  958. X      for(*(chp=buf)='\0';;){                /* get the variable name */
  959. X     switch(i=getb()){
  960. X        case ' ':case '\t':skipspace();i=testb('=')?'=':0;
  961. X        case '\n':case '=':case EOF:
  962. X           *chp='\0';goto eofvarname;}
  963. X     if(!alphanum(*chp++=i))
  964. X        for(;;*chp++=i)             /* it was garbage after all */
  965. X           switch(i=getb()){
  966. X          case ' ':case '\t':case '\n':case EOF:*chp='\0';
  967. X             skipped(buf);goto mainloop;}}
  968. Xeofvarname:
  969. X      if(i!='='){                   /* removal or assignment? */
  970. X     sputenv(buf);continue;}
  971. X      *chp='=';readparse(++chp,getb,1);
  972. Xargenv:
  973. X      sputenv(buf);chp[-1]='\0';
  974. X      if(!strcmp(buf,linebufs)){
  975. X     if((linebuf=renvint(0L,chp)+XTRAlinebuf)<MINlinebuf+XTRAlinebuf)
  976. X        linebuf=MINlinebuf+XTRAlinebuf;           /* check minimum size */
  977. X     free(buf);free(buf2);buf=malloc(linebuf);buf2=malloc(linebuf);}
  978. X      else if(!strcmp(buf,maildir)){
  979. X     if(chdir(chp)){
  980. X        log("Couldn't chdir to");logqnl(chp);}}
  981. X      else if(!strcmp(buf,logfile)){
  982. X     close(STDERR);
  983. X     if(0>opena(chp))
  984. X        if(0>opena(console))
  985. X           retval=EX_OSFILE;      /* bad news, but can't tell anyone */
  986. X        else
  987. X           writeerr(chp);}
  988. X      else if(!strcmp(buf,Log))
  989. X     log(chp);
  990. X      else if(!strcmp(buf,lockfile))
  991. X     lockit(chp,&globlock);
  992. X      else if(!strcmp(buf,eumask)){
  993. X     sscanf(chp,"%o",&i);umask(i);}
  994. X      else if(!strcmp(buf,host)){
  995. X     if(strcmp(chp,chp2=(char*)hostname())){
  996. X        yell("HOST mismatched",chp2);
  997. X        if(rc<0||!nextrcfile()){          /* if no rcfile opened yet */
  998. X           retval=EX_OK;terminate();}      /* exit gracefully as well */
  999. X        rclose(rc);rc= -1;}}
  1000. X      else{
  1001. X     i=MAXvarvals;
  1002. X     do                      /* several numeric assignments */
  1003. X        if(!strcmp(buf,strenvvar[i].name)){
  1004. X           strenvvar[i].val=renvint(strenvvar[i].val,chp);break;}
  1005. X     while(i--);}}
  1006. Xmainloop:
  1007. X    ;}
  1008. X while(rc<0||!testb(EOF));                /* main interpreter loop */
  1009. Xnomore_rc:
  1010. X if(dump(deliver(tgetenv(defaultf)),themail,filled)){          /* default */
  1011. X   writeerr(buf);        /* if it fails, don't panic, try the last resort */
  1012. X   if(dump(deliver(tgetenv(orgmail)),themail,filled))
  1013. X      writeerr(buf);goto mailerr;}            /* now you can panic */
  1014. Xmailed:
  1015. X retval=EX_OK;                  /* we're home free, mail delivered */
  1016. Xmailerr:
  1017. X unlock(&loclock);*thebody='\0';       /* Terminate the header, just in case */
  1018. X if(!strncmp(From,chp=themail,STRLEN(From))){  /* Check for a "From " header */
  1019. X   if(chp=strchr(themail,'\n'))
  1020. X      *chp++='\0';
  1021. X   else
  1022. X      chp=thebody;
  1023. X   log(themail);log(newline);} /* preserve mailbox format (arbitrary length) */
  1024. X while(chp<thebody){
  1025. X   if(0<sscanf(chp,SSUBJECT_S,buf2)){        /* case insensitive "Subject:" ? */
  1026. X      log(SSUBJECT);log(buf2);log(newline);}          /* log the Subject */
  1027. X   chp=findnl(chp,thebody);}
  1028. X log(sfolder);i=strlen(strncpy(buf,lastfolder,MAXfoldlen))+STRLEN(sfolder);
  1029. X buf[MAXfoldlen]='\0';
  1030. X while(chp=strchr(buf,'\t'))
  1031. X   *chp=' ';                        /* take out all tabs */
  1032. X log(buf);i-=i%TABWIDTH;             /* tell where we last dumped it */
  1033. X do log(TABCHAR);
  1034. X while((i+=TABWIDTH)<LENoffset);
  1035. X ultstr(7,lastdump,buf);log(buf);log(newline);terminate();}
  1036. X
  1037. Xdirmail(){char*chp;struct stat stbuf;    /* buf should contain directory name */
  1038. X if((chp=strchr(buf,'\0')-1)-1>=buf&&chp[-1]==*MCDIRSEP&&*chp=='.'){
  1039. X   *chp='\0';strcpy(buf2,buf);}                   /* it ended in /. */
  1040. X else{
  1041. X   chp=0;strcpy(buf2,strcat(buf,MCDIRSEP));}
  1042. X if(unique(buf2,strchr(buf2,'\0'),0666)){
  1043. X   if(chp){unsigned long i=0;
  1044. X      do ultstr(0,++i,chp);               /* find first empty MH folder */
  1045. X      while(link(buf2,buf));
  1046. X      unlink(buf2);goto opn;}
  1047. X   stat(buf2,&stbuf);
  1048. X   ultoan((unsigned long)stbuf.st_ino,          /* filename with i-node number */
  1049. X      strchr(strcat(buf,tgetenv(msgprefix)),'\0'));
  1050. X   if(!myrename(buf2,buf))           /* rename it, we need the same i-node */
  1051. Xopn:  return opena(buf);}
  1052. X return -1;}
  1053. SHAR_EOF
  1054. chmod 0644 procmail/procmail.c ||
  1055. echo 'restore of procmail/procmail.c failed'
  1056. Wc_c="`wc -c < 'procmail/procmail.c'`"
  1057. test 13100 -eq "$Wc_c" ||
  1058.     echo 'procmail/procmail.c: original size 13100, current size' "$Wc_c"
  1059. fi
  1060. # ============= procmail/nonint.c ==============
  1061. if test -f 'procmail/nonint.c' -a X"$1" != X"-c"; then
  1062.     echo 'x - skipping procmail/nonint.c (File already exists)'
  1063. else
  1064. echo 'x - extracting procmail/nonint.c (Text)'
  1065. sed 's/^X//' << 'SHAR_EOF' > 'procmail/nonint.c' &&
  1066. X/************************************************************************
  1067. X *    Collection of routines that don't return int            *
  1068. X *                                    *
  1069. X *    Copyright (c) 1990-1991, S.R.van den Berg, The Netherlands    *
  1070. X *    The sources can be freely copied for non-commercial use.    *
  1071. X *    #include "README"                        *
  1072. X *                                    *
  1073. X *    #include "STYLE"                        *
  1074. X *                                    *
  1075. X ************************************************************************/
  1076. X#ifdef    RCS
  1077. Xstatic char rcsid[]="$Id: nonint.c,v 2.3 1991/07/08 10:47:56 berg Rel $";
  1078. X#endif
  1079. X#include "config.h"
  1080. X#include "procmail.h"
  1081. X
  1082. X#define nomemretry    noresretry
  1083. X#define noforkretry    noresretry
  1084. X
  1085. Xvoid*tmalloc(len)const size_t len;{void*p;int i;  /* this malloc can survive */
  1086. X if(p=malloc(len))        /* a temporary "out of swap space" condition */
  1087. X   return p;
  1088. X if(p=malloc(1))
  1089. X   free(p);               /* works on some systems with latent free */
  1090. X for(lcking=2,i=nomemretry;i<0||i--;){
  1091. X   suspend();             /* problems?  don't panic, wait a few secs till */
  1092. X   if(p=malloc(len)){         /* some other process has paniced (and died 8-) */
  1093. X      lcking=0;return p;}}
  1094. X nomemerr();}
  1095. X
  1096. Xvoid*trealloc(old,len)void*const old;const size_t len;{void*p;int i;
  1097. X if(p=realloc(old,len))
  1098. X    return p;                    /* for comment see tmalloc above */
  1099. X if(p=malloc(1))
  1100. X   free(p);
  1101. X for(lcking=2,i=nomemretry;i<0||i--;){
  1102. X   suspend();
  1103. X   if(p=realloc(old,len)){
  1104. X      lcking=0;return p;}}
  1105. X nomemerr();}
  1106. X               /* line buffered to keep concurrent entries untangled */
  1107. Xlog(new)const char*const new;{int lnew,i;static lold;static char*old;char*p;
  1108. X if(lnew=strlen(new)){                        /* anything? */
  1109. X   if(nextexit)
  1110. X      goto direct;                  /* carefull, in terminate code */
  1111. X   i=lold+lnew;
  1112. X   if(p=lold?realloc(old,i):malloc(i)){
  1113. X      memmove((old=p)+lold,new,(size_t)lnew);               /* append */
  1114. X      if(p[(lold=i)-1]=='\n'){                         /* EOL? */
  1115. X     rwrite(STDERR,p,i);lold=0;free(p);}}        /* flush the line(s) */
  1116. X   else{                       /* no memory, force flush */
  1117. X      if(lold){
  1118. X     rwrite(STDERR,old,i);lold=0;free(old);}
  1119. Xdirect:
  1120. X      rwrite(STDERR,new,lnew);}}}
  1121. X
  1122. X#include "shell.h"
  1123. X
  1124. Xpid_t sfork(){pid_t i;int r;        /* this fork can survive a temporary */
  1125. X r=noforkretry;                   /* "process table full" condition */
  1126. X while((i=fork())==-1){
  1127. X   lcking=3;
  1128. X   if(!(r<0||r--))
  1129. X      break;
  1130. X   suspend();}
  1131. X lcking=0;return i;}
  1132. X
  1133. Xextern char*lastexec,*backblock;        /* see retint.c for comment */
  1134. Xextern long backlen;
  1135. Xextern pid_t pidfilt,pidchild;
  1136. Xextern pbackfd[2];
  1137. X
  1138. Xvoid sterminate(){static const char*const msg[]={newline,0,
  1139. X "memory\n","fork\n","file descriptor\n"};
  1140. X signal(SIGTERM,SIG_IGN);signal(SIGHUP,SIG_IGN);signal(SIGINT,SIG_IGN);
  1141. X if((long)pidchild>0)        /* don't kill what is not ours, we might be root */
  1142. X   kill(pidchild,SIGTERM);
  1143. X if(!nextexit){
  1144. X   nextexit=1;log("Terminating prematurely");
  1145. X   if(1!=lcking){
  1146. X      if(1<lcking)
  1147. X     log(whilstwfor);
  1148. X      log(msg[lcking]);terminate();}}}
  1149. X
  1150. Xvoid stermchild(){
  1151. X signal(SIGHUP,SIG_IGN);signal(SIGINT,SIG_IGN);signal(SIGQUIT,SIG_IGN);
  1152. X signal(SIGTERM,SIG_IGN);
  1153. X if((long)pidfilt>0)        /* don't kill what is not ours, we might be root */
  1154. X   kill(pidfilt,SIGTERM);
  1155. X kill(thepid,SIGQUIT);log("Rescue of unfiltered data ");
  1156. X if(dump(PWRB,backblock,backlen)) /* pump back the data through the backpipe */
  1157. X    log("failed\n");
  1158. X else
  1159. X    log("succeeded\n");
  1160. X exit(EX_UNAVAILABLE);}
  1161. X
  1162. Xvoid flagger(){                       /* hey, we received a SIGQUIT */
  1163. X flaggerd=1;signal(SIGQUIT,flagger);}
  1164. X
  1165. Xvoid ftimeout(){
  1166. X alarm(0);alrmtime=0;
  1167. X if((long)pidchild>0)        /* don't kill what is not ours, we might be root */
  1168. X   if(!kill(pidchild,SIGTERM)){
  1169. X      log("Timeout, terminating");logqnl(lastexec);}
  1170. X signal(SIGALRM,ftimeout);}
  1171. X
  1172. Xlong dump(s,source,len)const int s;const char*source;long len;{int i;
  1173. X if(s>=0){
  1174. X    lastdump=len;
  1175. X    while(i=rwrite(s,source,BLKSIZ<len?BLKSIZ:(int)len)){
  1176. X       if(i<0){
  1177. X      i=0;goto writefin;}
  1178. X       len-=i;source+=i;}
  1179. X    if(!len&&(lastdump<2||!(source[-1]=='\n'&&source[-2]=='\n')))
  1180. X       lastdump++,rwrite(s,newline,1); /* message always ends with a newline */
  1181. X    mboxseparator(s);             /* and an optional custom separator */
  1182. Xwritefin:
  1183. X    rclose(s);return len-i;}
  1184. X return len?len:-1;}       /* return an error even if nothing was to be sent */
  1185. X
  1186. Xlong pipin(line,source,len)char*const line;char*source;long len;{
  1187. X int poutfd[2];
  1188. X rpipe(poutfd);
  1189. X if(!(pidchild=sfork())){                    /* spawn program */
  1190. X   rclose(PWRO);rclose(rc);getstdin(PRDO);callnewprog(line);}
  1191. X rclose(PRDO);
  1192. X if(forkerr(pidchild,line))
  1193. X   return 1;
  1194. X if(len=dump(PWRO,source,len))                /* dump mail in the pipe */
  1195. X   writeerr(line);               /* pipe was shut in our face, get mad */
  1196. X if(pwait&&waitfor(pidchild)!=EX_OK){        /* optionally check the exitcode */
  1197. X   progerr(line);len=1;}
  1198. X pidchild=0;
  1199. X if(!sh)
  1200. X   for(source=line;;)        /* change back the \0's into blanks for printing */
  1201. X      if(!*source++)
  1202. X     if(*source!=TMNATE)
  1203. X        source[-1]=' ';
  1204. X     else
  1205. X        break;
  1206. X lastfolder=cstr(lastfolder,line);return len;}
  1207. X
  1208. Xchar*readdyn(bf,filled)char*bf;long*const filled;{int i;long oldsize;
  1209. X oldsize= *filled;goto jumpin;
  1210. X do{
  1211. X   *filled+=i;                    /* change listed buffer size */
  1212. Xjumpin:
  1213. X   bf=realloc(bf,*filled+BLKSIZ);      /* dynamically adjust the buffer size */
  1214. Xjumpback:;}
  1215. X while(0<(i=rread(STDIN,bf+*filled,BLKSIZ)));            /* read mail */
  1216. X switch(flaggerd){
  1217. X   case 0:waitflagger();            /* wait for the filter to finish */
  1218. X   case 1:getstdin(PRDB);               /* filter ready, get backpipe */
  1219. X      if(1==rread(STDIN,buf,1)){              /* backup pipe closed? */
  1220. X     bf=realloc(bf,(*filled=oldsize+1)+BLKSIZ);bf[oldsize]= *buf;flaggerd=2;
  1221. X     goto jumpback;}}               /* filter goofed, rescue data */
  1222. X pidchild=0;                    /* child must be gone by now */
  1223. X if(!*filled)
  1224. X   return realloc(bf,1);             /* +1 for housekeeping purposes */
  1225. X return realloc(bf,*filled+1);}            /* minimize the buffer space */
  1226. X
  1227. Xchar*fromprog(name,dest)char*const name;char*dest;{int pinfd[2];long nls;
  1228. X rpipe(pinfd);inittmout(name);
  1229. X if(!(pidchild=fork())){                    /* spawn program */
  1230. X   rclose(STDIN);opena(devnull);rclose(PRDI);rclose(rc);rclose(STDOUT);
  1231. X   rdup(PWRI);rclose(PWRI);callnewprog(name);}
  1232. X rclose(PWRI);nls=0;
  1233. X if(!forkerr(pidchild,name)){
  1234. X    while(0<rread(PRDI,dest,1))                    /* read its lips */
  1235. X       if(*dest=='\n')                   /* carefull with newlines */
  1236. X      nls++;            /* trailing newlines should be discarded */
  1237. X       else{
  1238. X      if(nls)
  1239. X         for(dest[nls]= *dest;*dest++='\n',--nls;);         /* fill them in */
  1240. X      dest++;}
  1241. X    waitfor(pidchild);}
  1242. X pidchild=0;rclose(PRDI);*dest='\0';return dest;}
  1243. X
  1244. Xchar*cat(a,b)const char*const a,*const b;{
  1245. X return strcat(strcpy(buf,a),b);}
  1246. X
  1247. Xchar*findnl(start,end)register const char*start,*end;{
  1248. X while(start<end)                   /* find the first newline */
  1249. X   if(*start++=='\n')
  1250. X      return(char*)start;
  1251. X return(char*)end;}
  1252. X
  1253. Xchar*tstrdup(a)const char*const a;{int i;
  1254. X i=strlen(a)+1;return tmemmove(malloc(i),a,i);}
  1255. X
  1256. Xconst char*tgetenv(a)const char*const a;{const char*b;
  1257. X return(b=getenv(a))?b:"";}
  1258. X
  1259. Xchar*cstr(a,b)const char*const a,*const b;{    /* dynamic buffer management */
  1260. X if(a)
  1261. X   free(a);
  1262. X return tstrdup(b);}
  1263. X
  1264. Xlong renvint(i,env)long i;const char*const env;{
  1265. X sscanf(env,"%ld",&i);return i;}           /* parse it like a decimal nr */
  1266. SHAR_EOF
  1267. chmod 0644 procmail/nonint.c ||
  1268. echo 'restore of procmail/nonint.c failed'
  1269. Wc_c="`wc -c < 'procmail/nonint.c'`"
  1270. test 7135 -eq "$Wc_c" ||
  1271.     echo 'procmail/nonint.c: original size 7135, current size' "$Wc_c"
  1272. fi
  1273. true || echo 'restore of procmail/retint.c failed'
  1274. echo End of part 2, continue with part 3
  1275. exit 0
  1276.  
  1277. exit 0 # Just in case...
  1278. -- 
  1279. Kent Landfield                   INTERNET: kent@sparky.IMD.Sterling.COM
  1280. Sterling Software, IMD           UUCP:     uunet!sparky!kent
  1281. Phone:    (402) 291-8300         FAX:      (402) 291-4362
  1282. Please send comp.sources.misc-related mail to kent@uunet.uu.net.
  1283.