home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / misc / volume20 / procmail / part02 < prev    next >
Encoding:
Text File  |  1991-06-18  |  43.8 KB  |  1,147 lines

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