home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / misc / volume25 / procmail / part02 < prev    next >
Text File  |  1991-11-03  |  55KB  |  1,681 lines

  1. Newsgroups: comp.sources.misc
  2. From: berg@messua.informatik.rwth-aachen.de (Stephen R. van den Berg)
  3. Subject:  v25i002:  procmail - mail processing program v2.31, Part02/04
  4. Message-ID: <1991Nov3.230004.9816@sparky.imd.sterling.com>
  5. X-Md4-Signature: 7bdbc968ca0a90061d1344ebc28bccb8
  6. Date: Sun, 3 Nov 1991 23:00:04 GMT
  7. Approved: kent@sparky.imd.sterling.com
  8.  
  9. Submitted-by: berg@messua.informatik.rwth-aachen.de (Stephen R. van den Berg)
  10. Posting-number: Volume 25, Issue 2
  11. Archive-name: procmail/part02
  12. Environment: UNIX, sendmail, smail, MMDF
  13. Supersedes: procmail2.10: Volume 20, Issue 89-91
  14.  
  15. #! /bin/sh
  16. # This is a shell archive.  Remove anything before this line, then feed it
  17. # into a shell via "sh file" or similar.  To overwrite existing files,
  18. # type "sh file -c".
  19. # The tool that generated this appeared in the comp.sources.unix newsgroup;
  20. # send mail to comp-sources-unix@uunet.uu.net if you want that tool.
  21. # Contents:  procmail/README procmail/examples/mailinglist
  22. #   procmail/formail.c procmail/regexp.c procmail/retint.c
  23. # Wrapped by kent@sparky on Sun Nov  3 16:50:05 1991
  24. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  25. echo If this archive is complete, you will see the following message:
  26. echo '          "shar: End of archive 2 (of 4)."'
  27. if test -f 'procmail/README' -a "${1}" != "-c" ; then 
  28.   echo shar: Will not clobber existing file \"'procmail/README'\"
  29. else
  30.   echo shar: Extracting \"'procmail/README'\" \(3992 characters\)
  31.   sed "s/^X//" >'procmail/README' <<'END_OF_FILE'
  32. XProcmail & formail mail processing package.
  33. XCopyright (c) 1990-1991, S.R.van den Berg, The Netherlands.
  34. X
  35. XSome legal stuff:
  36. X
  37. XUse this software package at your own risk.  The programmer can not
  38. Xbe held liable for any incurred damages, directly or indirectly due to
  39. Xthe use of this software.
  40. X
  41. XYou are encouraged to distribute this package freely.  This package is
  42. Xhowever not to be sold (minor transfer costs excepted) or included in
  43. Xany commercially sold software package (if you want to do this anyway,
  44. Xcontact me (address below), and we'll work something out).
  45. X
  46. XIf you distribute it, please leave the package intact.    You are allowed to
  47. Xtake parts from this distribution and distribute these separately as long
  48. Xas you retain the copyright messages.  If you redistribute any part of this
  49. Xpackage in a modified form, be sure to mark the parts you changed.
  50. XIf you have some important changes that might be usefull to the rest of the
  51. Xworld, contact me instead.
  52. X
  53. X-------------------------- SYSTEM REQUIREMENTS -------------------------------
  54. X
  55. XAny *NIX-alike system.
  56. X
  57. XSendmail, smail, MMDF or compatible mailers.
  58. X
  59. XThe most important system calls that need to be supported (among others):
  60. Xdup(),wait(),getpwent(),fork(),pipe()
  61. X
  62. XFor a more complete list of all library references see "includes.h"
  63. X
  64. X------------------------------ DESCRIPTION -----------------------------------
  65. X
  66. XThe procmail mail processing program. (v2.31 1991/10/22)
  67. X
  68. XCan be used to create mail-servers, mailing lists, sort your incoming mail
  69. Xinto separate folders/files (real convenient when subscribing to one or more
  70. Xmailing lists), preprocess your mail, or selectively forward certain incoming
  71. Xmail automatically to someone.
  72. X
  73. XThe accompanying formail program enables you to generate autoreplies, split up
  74. Xdigests/mailboxes into the original messages, do some very simple
  75. Xheader-munging, or force mail into mail-format (with leading From line).
  76. X
  77. XFor installation instructions see the INSTALL file.
  78. X
  79. X----------------------
  80. X
  81. XI made the utmost effort to make procmail as robust as any program can be
  82. X(every conceivable system error is caught *and* handled).
  83. X
  84. XProcmail was designed to deliver the mail under the worst conditions
  85. X(file system full, out of swap space, process table full, file table full,
  86. Xmissing support files, unavailable executables; it all doesn't matter).
  87. XShould (in the unlikely event) procmail be unable to deliver your mail
  88. Xsomewhere, the mail will bounce back to the sender or reenter the mailqueue
  89. X(your choice).
  90. X
  91. XFor a more extensive list of features see the FEATURES file.
  92. X
  93. X----------------------
  94. X
  95. XHowever, as with any program, bugs can not be completely ruled out.
  96. XI tested the program extensively, and believe it should be relatively
  97. Xbug free (no known bug at the time).  Should, however, anyone find any
  98. Xbugs (highly unlikely :-), I would be pleased (well, sort of :-) to hear
  99. Xabout it.  Please send me the patches or bug report.
  100. XI'll look at them and will try to fix it in a future release.
  101. X(BTW, if you should find any spelling or grammar errors in these files,
  102. Xit's not priority one, but if you were sending me mail anyway, don't hesitate
  103. Xto point them out to me; I like correct English just as much as you do).
  104. X
  105. XPlease note that this program essentially is supposed to be static, that
  106. Xmeans no extra features (honouring the VNIX spirit) are supposed to be
  107. Xadded (though any usefull suggestions will be appreciated and evaluated if
  108. Xtime permits).
  109. X
  110. XCheers,
  111. X       Stephen R. van den Berg    at RWTH-Aachen, Germany.
  112. X
  113. XInternet E-mail:        berg@messua.informatik.rwth-aachen.de
  114. X                berg@physik.tu-muenchen.de
  115. X
  116. XOr:    P.O.Box 21074
  117. X    6369 ZG Simpelveld
  118. X    The Netherlands
  119. X
  120. X----------------------
  121. XA recent version can be picked up at various comp.sources.misc archives.
  122. XThe latest version can be obtained directly from the ftp-archive at:
  123. X
  124. X    amaru.informatik.rwth-aachen.de (137.226.112.31)
  125. X
  126. X    as compressed tar file:        pub/unix/procmail.tar.Z
  127. X    or in compressed shar format:    pub/unix/procmail.0?.Z
  128. X----------------------
  129. END_OF_FILE
  130.   if test 3992 -ne `wc -c <'procmail/README'`; then
  131.     echo shar: \"'procmail/README'\" unpacked with wrong size!
  132.   fi
  133.   # end of 'procmail/README'
  134. fi
  135. if test -f 'procmail/examples/mailinglist' -a "${1}" != "-c" ; then 
  136.   echo shar: Will not clobber existing file \"'procmail/examples/mailinglist'\"
  137. else
  138.   echo shar: Extracting \"'procmail/examples/mailinglist'\" \(11152 characters\)
  139.   sed "s/^X//" >'procmail/examples/mailinglist' <<'END_OF_FILE'
  140. X$Id: mailinglist,v 2.3 1991/10/18 15:39:20 berg Rel $
  141. X
  142. X                        How to set up mailing lists
  143. X                        ---------------------------
  144. X
  145. X                Written by Stephen R. van den Berg.
  146. X                                        berg@messua.informatik.rwth-aachen.de
  147. X                                        berg@physik.tu-muenchen.de
  148. X
  149. XThis document mainly describes a sendmail environment, much of it applies
  150. Xto non-sendmail mail agents as well.
  151. X
  152. X
  153. XContents:
  154. X---------       1. Intro
  155. X                2. Bouncing mail
  156. X                3. The disadvantages
  157. X                4. How to circumvent these disadvantages
  158. X                5. Why use procmail to filter the mailinglist mail?
  159. X                6. How do I use procmail to filter the mailinglist mail?
  160. X                7. Now, what does the above all do?
  161. X                8. The result of this exercise
  162. X
  163. X1. Intro
  164. X   -----
  165. X
  166. XThe simplest and most direct way to do it is by insert a line in
  167. Xthe /usr/lib/aliases file looking like:
  168. X
  169. Xmylist: fred,john, wilma, barney@bedrock, pebbles
  170. X
  171. XNow all the mail arriving at your machine for "mylist" (either local or
  172. Xmylist@your.domain) will be automatically forwarded to all the mentioned
  173. Xaddresses (fred, john, etc.).
  174. X
  175. XThe address mylist@your.domain is intended for submissions to the list that
  176. Xare supposed to be forwarded to all the subscribers.  For the administrative
  177. Xtasks like removals from the list, new subscribtions to the list, or address
  178. Xchanges of subscribers one should create a second entry in the /usr/lib/aliases
  179. Xfile:
  180. X
  181. Xmylist-request: your_login_name@your.domain
  182. X
  183. X
  184. X2. Bouncing mail
  185. X   -------------
  186. X
  187. XIn order to deal with bouncing mail gracefully, an extra precaution should
  188. Xbe taken.  If for example mail to wilma bounces (user non-existent, mail
  189. Xfilesystem full, etc.), it will bounce back to the original sender.
  190. XNow, the only person that should be concerned with distribution failures
  191. Xshould be the mylist-request holder.  Therefore you should be using a
  192. Xsendmail special alias like:
  193. X
  194. Xowner-mylist: mylist-request@your.domain
  195. X
  196. XThis way local mail will bounce back to mylist-request@your.domain.
  197. X
  198. X
  199. X3. The disadvantages
  200. X   -----------------
  201. X
  202. XIf you are using the above methods, some obvious disadvantages come to mind
  203. Xhowever:
  204. X
  205. Xa. The subscriber list can not exceed 1000 bytes (on most sendmails).
  206. Xb. The subscriber list can not be changed on-the-fly (/usr/lib/aliases needs
  207. X   to be edited, and newaliases has to be run).
  208. Xc. People can not be prevented from submitting messages like "Please remove
  209. X   me from this mailinglist" to mylist (and thereby annoying all subscribers).
  210. Xd. People can not be guarded from themselves in case they insert
  211. X   "Return-Receipt-To:" fields in their headers (if they are particularly
  212. X   unlucky, they will receive an acknowledge mail from *every* subscriber's
  213. X   sendmail).
  214. Xe. People including "Errors-To:" or "Sender:" fields can cause the bounce
  215. X   messages to bypass owner-mylist anyway.
  216. Xf. There is no way of limiting the number of submitters, i.e. every person
  217. X   who knows the name of the mailing list and who can send mail to your.domain
  218. X   is able to submit messages to the list.  This means, for example, that you
  219. X   can not limit a mailing list to local users (i.e. only local users can
  220. X   submit).
  221. Xg. You are unable to insert a "Reply-To: mylist@your.domain" in case you
  222. X   would want to (this makes replying to the list easier).
  223. X
  224. X
  225. X4. How to circumvent these disadvantages
  226. X  -------------------------------------
  227. X
  228. Xa. Can be circumvented by using nested aliases like:
  229. X        mylist: mylist1, mylist2
  230. X        mylist1: fred,john
  231. X        mylist2: wilma,barney@bedrock,pebbles
  232. X   This can however, become extremely messy to maintain.
  233. X
  234. Xb. This can partly be avoided if you use aliases like:
  235. X        mylist: :input:/path/to/the/memberfile
  236. X   The memberfile should contain:
  237. X        fred,john,wilma,barney@bedrock,pebbles
  238. X   You can not avoid using newaliases however, and *will* get extremely messy
  239. X   if you have to start using nested aliases.
  240. X
  241. Xc. Can only be taken care of by using a mailfilter like procmail.
  242. X
  243. Xd. Can only be taken care of by using a mailfilter like procmail.
  244. X
  245. Xe. Can only be taken care of by using a mailfilter like procmail.
  246. X
  247. Xf. Can only be taken care of by using a mailfilter like procmail.
  248. X
  249. Xh. Can only be taken care of by using a mailfilter like procmail.
  250. X
  251. X
  252. X5. Why use procmail to filter the mailinglist mail?
  253. X   ------------------------------------------------
  254. X
  255. XInstead of using a mailfilter you could also take care of most of the problems
  256. Xthree till seven by editing the sendmail.cf file.  I strongly would recommend
  257. Xagainst this approach however, since this will be too much of a customizing
  258. Xoperation and surely will not be a trivial task (in all cases).  As a general
  259. Xrule: don't mess with a sendmail.cf file once it is working :-).
  260. X
  261. XNow, you could, instead of procmail, simply use immediate VNIX commands
  262. Xlike grep, sed, awk to do the mail filtering.  Again, there are some obvious
  263. Xdisadvantages with this approach:
  264. X
  265. XA. In case any system resources go out (no more file descriptors, no more
  266. X   swap space, process table full, file system full (for temporary files))
  267. X   your awk or shell script will fail generously (i.e. several bad things
  268. X   could happen: mail munged, truncated, lost, hanging awk or sh programs,
  269. X   etc., you get the picture).
  270. X
  271. XB. All mail headers (including From: and Reply-To:) could very well be
  272. X   multi-line headers; it will be very difficult to make it understandable
  273. X   to awk that somehow the header line could continue on the next line
  274. X   (in case you want to remove a header, or do some complicated substitution).
  275. X
  276. XC. Another hairy problem will be determining the end of the header, of course
  277. X   that is solvable, but you have to make some extra precautions in your
  278. X   awk script to ensure that any substitutions/changes will not occur in
  279. X   the body of the message.
  280. X
  281. Xprocmail does not *directly* allow you to change any headers, but that
  282. Xfeature is not really necessary since you can tell procmail to send ONLY the
  283. Xheader through some filter of your choice.
  284. X
  285. XTo comment on the previously mentioned three disadvantages:
  286. X
  287. XA. procmail takes care of that.  Should the filter have problems anyway,
  288. X   procmail will graciously notice that the filter was in some kind of
  289. X   trouble, and will try something else with the original unmunged mail
  290. X   (you can specify what it should do of course, obvious choices: try
  291. X   the same filter again, drop the mail in a file and send you a notice,
  292. X   forward the mail to you instead (unfiltered), etc.)
  293. X
  294. XB. procmail will concatenate any headers that were continued according to
  295. X   the RCF 822 recommendations, i.e. your filters will see one line per header.
  296. X
  297. XC. procmail can be told to send the header, the body or both through the
  298. X   filter, hence your filter need not watch out to avoid doing any
  299. X   substitutions in the body, and the filter can therefore be a lot simpler.
  300. X
  301. XProcmail has some additional advantages too:
  302. X
  303. X -- It will probably all go a bit faster, since only the header of the mail
  304. X    is being piped through the filter.  Also, procmail reads in the mail in
  305. X    16KB chunks, not line by line as sed does.
  306. X
  307. X -- You could use procmail to filter out any messages to the normal mailing
  308. X    list that should have gone to the mylist-request and remail them to
  309. X    mylist-request.
  310. X
  311. XWell, anyway, as you see, procmail does not give you everything you would want,
  312. Xbut this was intentional in accordance to the true VNIX spirit (modularity).
  313. XWhat procmail does provide is a *very* reliable hook (you might say it
  314. Xprovides an anchor :-) for any mail processing you might do.  For the more
  315. Xcomplex things you still have to use shell scripts or call other programs
  316. Xfrom within procmail, but then again, that saves you from learning any
  317. Xparticular syntax procmail would have had to do the same.
  318. X
  319. XAs it happens, the accompanying formail program is able to cater to most
  320. X(if not all) of your needs regarding mail munging.
  321. X
  322. X
  323. X6. How do I use procmail to filter the mailinglist mail?
  324. X   -----------------------------------------------------
  325. X
  326. XFirst you have to create these two entries in your /usr/lib/aliases file of
  327. Xmachine "your.domain" (the mylist: line should be typed in as one long line):
  328. X
  329. Xmylist: "|IFS=' ';exec /usr/local/bin/procmail /some/path/listrc subscribers=/some/path/memberlist list=mylist@your.domain listreq=mylist-request@your.domain"
  330. Xmylist-request: your_login_name@your.domain
  331. Xowner-mylist: mylist-request
  332. X
  333. XCreate a file named /some/path/memberlist which contains the names of the
  334. Xsubscribers separated by whitespace (blanks, tabs or newlines) like:
  335. X
  336. X fred john  wilma  barney@bedrock  pebbles
  337. X
  338. XThe /some/path/listrc file you should look like the sample listrc file
  339. Xsupplied in this directory.  This listrc file need only be present once,
  340. Xit will cater for all the mailinglists you like to create.
  341. X
  342. X
  343. X7. Now, what does the above all do?
  344. X   --------------------------------
  345. X
  346. XIf mail arrives at mylist, first of all procmail will be started using
  347. X/some/path/listrc as the rcfile.  Then it will grep the header to check if
  348. Xit could be a bounced message after all (from postmaster or mailer-daemon),
  349. Xor if it probably is a request message.  If neither applies, procmail will
  350. Xfilter just the header of the message through formail.
  351. X
  352. Xformail will remove any "Return-Receipt-To:" fields, and will provide plain
  353. Xsubstitutes for "Errors-To:" and "Sender:".  Then it will look for
  354. Xany "Reply-To:" fields which are already in the header and rewrite them
  355. Xas "Old-Reply-To:";  after having done this it will add your "Reply-To:"
  356. Xfield.  BTW, the "Return-Receipt-To:" and "Errors-To:" fields are not
  357. Xrecommended by the RFC-822, they are however commonly supported by most
  358. Xsendmails;  if they are not supported however, they won't hurt, they will
  359. Xsimply be ignored.
  360. X
  361. XThen, the mail is piped into $SENDMAIL which receives, as command line
  362. Xarguments, the addresses of all subscribers.  The option -f will only
  363. Xtake effect if sendmail is running under daemon privileges; this only
  364. Xoccurs if the sender of the mail is *not* a local user; if the sender
  365. Xis a local user, then sendmail (and procmail) runs as the local user.
  366. X
  367. X*********************************** WARNING **********************************
  368. X*                                                                            *
  369. X* For this reason it might be wise to allow writing of the memberlist file   *
  370. X* only (to a list maintainer), keep the listrc file under *root supervision* *
  371. X* (i.e. owned by a very reliable person (e.g. root), world readable, but NOT *
  372. X* world writeable).                                                          *
  373. X*                                                                            *
  374. X******************************************************************************
  375. X
  376. X
  377. X8. The result of this exercise
  378. X   ---------------------------
  379. X
  380. XAs you can see, we have addressed and solved every single one of the original
  381. Xseven problems (well, ok, except problem f, that one is left as an excercise
  382. Xto the reader; shouldn't be too difficult).
  383. X
  384. X
  385. XP.S. Any suggestions/corrections/improvements on this document are welcome.
  386. END_OF_FILE
  387.   if test 11152 -ne `wc -c <'procmail/examples/mailinglist'`; then
  388.     echo shar: \"'procmail/examples/mailinglist'\" unpacked with wrong size!
  389.   fi
  390.   # end of 'procmail/examples/mailinglist'
  391. fi
  392. if test -f 'procmail/formail.c' -a "${1}" != "-c" ; then 
  393.   echo shar: Will not clobber existing file \"'procmail/formail.c'\"
  394. else
  395.   echo shar: Extracting \"'procmail/formail.c'\" \(12561 characters\)
  396.   sed "s/^X//" >'procmail/formail.c' <<'END_OF_FILE'
  397. X/************************************************************************
  398. X *    formail.c    a mail (re)formatter                *
  399. X *                                    *
  400. X *    Seems to be relatively bug free.                *
  401. X *                                    *
  402. X *    Copyright (c) 1990-1991, S.R.van den Berg, The Netherlands    *
  403. X *    The sources can be freely copied for non-commercial use.    *
  404. X *    #include "README"                        *
  405. X *                                    *
  406. X ************************************************************************/
  407. X#ifdef RCS
  408. Xstatic char rcsid[]="$Id: formail.c,v 2.11 1991/10/18 15:33:23 berg Rel $";
  409. X#endif
  410. Xstatic char rcsdate[]="$Date: 1991/10/18 15:33:23 $";
  411. X#include "config.h"                      /* slight overkill */
  412. X#include "includes.h"
  413. X
  414. Xchar*pstrspn();
  415. X
  416. X#define BSIZE        4096
  417. X
  418. X#define NAMEPREFIX    "formail: "
  419. X#define HEAD_DELIMITER    ':'
  420. X
  421. X#define Re        (re+1)
  422. X#define Nextchar(x)    do{x=getchar();if(feof(stdin))goto foundeof;}while(0)
  423. X#define putssn(a,l)    tputssn(a,(size_t)(l))
  424. X#define putcs(a)    (errout=putc(a,mystdout))
  425. X#define PRDO        poutfd[0]
  426. X#define PWRO        poutfd[1]
  427. X
  428. Xstatic const char From[]=FROM,replyto[]="Reply-To:",Fromm[]="From:",
  429. X returnpath[]="Return-Path",sender[]="Sender:",outofmem[]="Out of memory\n",
  430. X subject[]="Subject:",re[]=" Re:",couldntw[]="Couldn't write to stdout",
  431. X references[]="References:",messageid[]="Message-ID:",Date[]="Date:",
  432. X article[]="Article ",Path[]="Path:",Received[]="Received:",To[]="To: ",
  433. X OldP[]=OLD_PREFIX,inreplyto[]="In-Reply-To:",errorsto[]="Errors-To",
  434. X retreceiptto[]="Return-Receipt-To";
  435. Xconst char binsh[]=BinSh;
  436. X/*
  437. X *    sender determination fields in order of importance reliability
  438. X *    reply-address determination fields (wrepl specifies the weight)
  439. X */
  440. Xstatic const struct {const char*head;int len,wrepl;}sest[]=
  441. X{ {errorsto,STRLEN(errorsto),5},{retreceiptto,STRLEN(retreceiptto),6},
  442. X  {sender,STRLEN(sender),0},{replyto,STRLEN(replyto),4},
  443. X  {Fromm,STRLEN(Fromm),2},{returnpath,STRLEN(returnpath),1}
  444. X};
  445. X/*
  446. X *    digest splitting fields
  447. X */
  448. Xstatic const struct {const char*hedr;int lnr;}cdigest[]=
  449. X{ {Fromm,STRLEN(Fromm)},{Date,STRLEN(Date)},{subject,STRLEN(subject)},
  450. X  {article,STRLEN(article)},{Path,STRLEN(Path)},{Received,STRLEN(Received)}
  451. X};
  452. X
  453. Xstatic struct {const char*const headr;const int lenr;char*rexp;}rex[]=
  454. X{ {subject,STRLEN(subject)},{references,STRLEN(references)},
  455. X  {messageid,STRLEN(messageid)}
  456. X};
  457. X#define subj    rex[0]
  458. X#define refr    rex[1]
  459. X#define msid    rex[2]
  460. X#define mxl(a,b)    mx(STRLEN(a),STRLEN(b))
  461. X#ifndef MAILBOX_SEPARATOR
  462. X#define dig_HDR_LEN    mx(mxl(From,Fromm),mxl(Date,subject))
  463. X#define mboxseparator    From
  464. X#define flushseparator(i,p)
  465. X#else
  466. Xstatic const char mboxseparator[]=MAILBOX_SEPARATOR;
  467. X#define flushseparator(i,p)    \
  468. X do{i=p;p=0;do{int x;Nextchar(x);}while(--i);}while(0)
  469. X#define dig_HDR_LEN    \
  470. X mx(mx(mxl(From,Fromm),mxl(Date,subject)),STRLEN(mboxseparator))
  471. X#endif
  472. Xstatic struct hedit{char*hline;long hlen;struct hedit*next;}*hlist;
  473. Xstatic errout,oldstdout,quiet;
  474. Xstatic pid_t child= -1;
  475. Xstatic FILE*mystdout;
  476. Xstatic size_t nrskip,nrtotal= -1;
  477. X
  478. X#ifdef    NOstrstr
  479. Xchar*strstr(whole,part)const char*whole,*const part;
  480. X{ register const char*w,*p;
  481. X  do
  482. X   { w=whole;p=part;
  483. X     do
  484. X    if(!*p)
  485. X       return(char*)whole;
  486. X     while(*w++==*p++);}
  487. X  while(*whole++);
  488. X  return(char*)0;
  489. X}
  490. X#endif
  491. X
  492. Xvoid*tmalloc(len)const size_t len;
  493. X{ void*p;
  494. X  if(p=malloc(len))
  495. X     return p;
  496. X  nlog(outofmem);exit(EX_OSERR);
  497. X}
  498. X
  499. Xvoid*trealloc(old,len)void*old;const size_t len;
  500. X{ if(old=realloc(old,len))
  501. X     return old;
  502. X  nlog(outofmem);exit(EX_OSERR);
  503. X}
  504. X
  505. X#include "shell.h"
  506. X
  507. Xstruct hedit*overrideh(target)const char*const target;
  508. X{ const struct hedit*hlp;size_t len;
  509. X  for(hlp=hlist;hlp;hlp=hlp->next)
  510. X   { len=hlp->hlen;
  511. X     if(hlp->hlen<0)
  512. X    len= -hlp->hlen;                     /* absolute */
  513. X     if(!strnicmp(hlp->hline,target,len))             /* header found */
  514. X    return (struct hedit*)hlp;
  515. X   }
  516. X  return(struct hedit*)0;                  /* no header found */
  517. X}
  518. X
  519. Xmain(lastm,argv)const char*const argv[];
  520. X{ int i,ch,nowm,split=0,force=0,bogus=1,every=0,areply=0,trust=0,digest=0,
  521. X   nowait=0,keepb=0;
  522. X  size_t buflen,p=0,lnl=0,ll;time_t t;char*buf,*chp,*namep;struct hedit*hlp;
  523. X  while(chp=(char*)*++argv)
  524. X   { if((lastm= *chp++)==FM_SKIP)
  525. X    goto number;
  526. X     else if(lastm!=FM_TOTAL)
  527. X    goto usg;
  528. X     for(;;)
  529. X      { switch(lastm= *chp++)
  530. X     { case FM_TRUST:trust=1;continue;
  531. X       case FM_REPLY:areply=1;continue;
  532. X       case FM_FORCE:force=1;continue;
  533. X       case FM_EVERY:every=1;bogus=0;continue;
  534. X       case FM_DIGEST:digest=1;continue;
  535. X       case FM_NOWAIT:nowait=1;continue;
  536. X       case FM_KEEPB:keepb=1;continue;
  537. X       case FM_QUIET:quiet=1;continue;
  538. X       case FM_SPLIT:split=1;
  539. X          if(!*chp&&*++argv)
  540. X         goto parsedoptions;
  541. X          goto usg;
  542. Xnumber:       default:
  543. X          if(*chp-'0'>(unsigned)9)
  544. X           {
  545. Xusg:         log(FM_USAGE);return EX_USAGE;
  546. X           }
  547. X          ll=strtol(chp,(char**)0,10);
  548. X          if(lastm==FM_SKIP)
  549. X         nrskip=ll;
  550. X          else
  551. X         nrtotal=ll;
  552. X          break;
  553. X       case FM_BOGUS:bogus=0;continue;
  554. X       case FM_REN_INSERT:case FM_DEL_INSERT:hlp=hlist;
  555. X          (hlist=malloc(sizeof*hlist))->next=hlp;
  556. X          if(!*chp&&!(chp=(char*)*++argv))    /* concatenated or seperate? */
  557. X         goto usg;
  558. X          hlist->hline=chp;                /* add header string */
  559. X          if(!(buf=strchr(chp,HEAD_DELIMITER)))
  560. X           { nlog("Invalid field-name:");logqnl(chp);goto usg;
  561. X           }
  562. X          buflen=buf-chp+1;
  563. X          hlist->hlen=lastm==FM_REN_INSERT?buflen:-(long)buflen;
  564. X       case '\0':;
  565. X     }
  566. X    break;
  567. X      }
  568. X   }
  569. Xparsedoptions:
  570. X#ifdef MAILBOX_SEPARATOR
  571. X  if(split)
  572. X   { bogus=0;every=1;
  573. X   }
  574. X#endif
  575. X  mystdout=stdout;signal(SIGPIPE,SIG_IGN);
  576. X  if(split)
  577. X   { oldstdout=dup(STDOUT);fclose(stdout);startprog(argv);
  578. X   }
  579. X  else if(every)
  580. X     goto usg;
  581. X  *(namep=malloc(1))='\0';buf=malloc(buflen=BSIZE);t=time((time_t*)0);
  582. X  i=maxindex(rex);
  583. X  do *(rex[i].rexp=malloc(1))='\0';
  584. X  while(i--);
  585. X  while('\n'==(ch=getchar()));
  586. X  for(;;)                     /* start parsing the header */
  587. X   { if((buf[p++]=ch)=='\n')
  588. X      { if(lnl==p-1)                    /* end of header reached */
  589. X       break;
  590. X    switch(ch=getchar())              /* concatenate continued lines */
  591. X     { case ' ':case '\t':p--;continue;
  592. X     }
  593. X    chp=buf+lnl;
  594. X#ifdef MAILBOX_SEPARATOR
  595. X    if(!strncmp(mboxseparator,chp,STRLEN(mboxseparator)))
  596. X     { if(!lnl)
  597. X        { if(split)
  598. X           { p=0;goto redigest;
  599. X           }
  600. X          force=1;         /* separator up front, don't add a 'From ' line */
  601. X        }
  602. X       else if(bogus)
  603. X          *chp=' ';
  604. X     }
  605. X#endif
  606. X    i=maxindex(rex);
  607. X    while(strnicmp(rex[i].headr,chp,ll=rex[i].lenr)&&i--);
  608. X    if(i>=0)                  /* found anything already? */
  609. X     { ll=p-lnl-ll;
  610. X       ((char*)tmemmove(rex[i].rexp=realloc(rex[i].rexp,ll),
  611. X        buf+lnl+rex[i].lenr,ll))[ll-1]='\0';
  612. X     }
  613. X    else if(!strncmp(From,chp,STRLEN(From)))
  614. X     { if(!lnl)                /* was the real "From " line */
  615. X        { nowm=trust?1:3/*wreply*/;ll=lnl+STRLEN(From);goto foundfrom;
  616. X        }
  617. X#ifndef MAILBOX_SEPARATOR
  618. X       if(bogus)
  619. X        { tmemmove(chp+1,chp,p++-lnl);*chp=ESCAP;           /* disarm */
  620. X        }
  621. X#endif
  622. X     }
  623. X    else
  624. X     { i=maxindex(sest);
  625. X       do
  626. X          if(!strnicmp(sest[i].head,chp,sest[i].len))
  627. X           { nowm=areply?keepb&&sest[i].head==replyto?
  628. X          maxindex(sest)+1:sest[i].wrepl:i;
  629. X         ll=lnl+sest[i].len;
  630. Xfoundfrom:     buf[p]='\0';
  631. X         if(chp=strchr(buf+ll,'<'))          /* extract the address */
  632. X            ll=chp-buf+1;
  633. X         if((i=strcspn(chp=pstrspn(buf+ll," \t"),">(\n \t"))&&
  634. X          (!*namep||nowm>lastm))
  635. X          { ((char*)tmemmove(namep=realloc(namep,i+1),chp,i))[i]='\0';
  636. X            lastm=strstr(chp,".UUCP")?nowm-maxindex(sest)-1:nowm;
  637. X          }
  638. X         break;
  639. X        }
  640. X       while(i--);
  641. X     }
  642. X    if(hlp=overrideh(buf+lnl))        /* replace or delete header? */
  643. X     { if(hlp->hlen<0)                   /* just delete it */
  644. X        { p=lnl;continue;
  645. X        }
  646. X       if(p+2>=buflen)            /* trouble if BSIZE<STRLEN(OldP) */
  647. X          buf=realloc(buf,buflen+=BSIZE);
  648. X       tmemmove(buf+lnl+STRLEN(OldP),buf+lnl,p-lnl);
  649. X       tmemmove(buf+lnl,OldP,STRLEN(OldP));p+=STRLEN(OldP);
  650. X     }
  651. X    lnl=p;continue;
  652. X      }
  653. X     if(p>=buflen-2)
  654. X    buf=realloc(buf,buflen+=BSIZE);
  655. Xredigest:
  656. X     ch=getchar();
  657. X     if(feof(stdin))
  658. X    ch='\n';        /* make sure the header ends with 2 newlines */
  659. X   }
  660. X  if(areply||!force&&strncmp(buf,From,STRLEN(From)))
  661. X   { if(!areply||!overrideh(To))
  662. X      { putss(areply?(areply=2),To:From);
  663. X    if(*namep)                /* found any sender address? */
  664. X       putss(namep);
  665. X    else
  666. X       putss(UNKNOWN);}
  667. X     if(areply)
  668. X      { if(areply==2)
  669. X       putnl();
  670. X    if(*subj.rexp&&!overrideh(subject))           /* any Subject: ? */
  671. X     { putss(subject);chp=subj.rexp;
  672. X       if(strnicmp(pstrspn(chp," "),Re,STRLEN(Re)))
  673. X          putss(re);               /* no Re: , add one ourselves */
  674. X       putss(chp);putnl();
  675. X     }
  676. X    if(*refr.rexp||*msid.rexp)     /* any Message-ID: or References: ? */
  677. X     { if(!overrideh(references))
  678. X        { putss(references);
  679. X          if(*refr.rexp)
  680. X           { putss(refr.rexp);
  681. X         if(*msid.rexp)
  682. X            putnl();
  683. X           }
  684. X          if(*msid.rexp)
  685. X           { putss(msid.rexp);putnl();
  686. X           }
  687. X        }
  688. X       if(*msid.rexp&&!overrideh(inreplyto))
  689. X        { putss(inreplyto);putss(msid.rexp);putnl();
  690. X        }
  691. X     }
  692. X      }
  693. X     else
  694. X      { putcs(' ');putss(ctime(&t));
  695. X      }
  696. X   }
  697. X  if(!areply)
  698. X     putssn(buf,p-1);
  699. X  for(hlp=hlist;hlp;hlp=hlp->next)
  700. X   { ll=hlp->hlen;
  701. X     if(hlp->hlen<0)
  702. X    ll= -hlp->hlen;
  703. X     if(hlp->hline[ll])
  704. X      { putss(hlp->hline);putnl();           /* inject our new headers */
  705. X      }
  706. X   }
  707. X  putnl();
  708. X  if(areply)
  709. X   { if(!keepb)
  710. X      { if(mystdout!=stdout)
  711. X       closemine();
  712. X    opensink();                     /* discard the body */
  713. X      }
  714. X   }
  715. X  p=0;lnl=1;                     /* clear buffer, important! */
  716. X  if(!bogus&&!split)
  717. X     for(;;putcs(i))
  718. X    Nextchar(i);
  719. X  for(;;)                           /* continue the quest */
  720. X   {
  721. X     do                         /* read line until not From */
  722. X      { if(p==buflen-1)
  723. X       buf=realloc(buf,++buflen);
  724. X    Nextchar(i=buf[p]);
  725. X    if(++p==STRLEN(mboxseparator))
  726. X       if(!strncmp(mboxseparator,buf,STRLEN(mboxseparator)))
  727. X        { if(every)
  728. X           { flushseparator(i,p);goto splitit;     /* optionally flush */
  729. X           }
  730. X          else if(split&&lnl)
  731. X         lnl=2;               /* mark line as possible postmark */
  732. X          else if(bogus)                       /* disarm */
  733. X           {
  734. X#ifndef MAILBOX_SEPARATOR
  735. X         putcs(ESCAP);break;
  736. X#else
  737. X         Nextchar(i);*buf=' ';putssn(buf,p);*buf=i;p=1;continue;
  738. X#endif
  739. X           }
  740. X        }
  741. X    if((i=='\n'||p!=1)&&areply)
  742. X     { if(bogus)
  743. X          putcs(ESCAP);
  744. X       break;
  745. X     }
  746. X    if(lnl==1&&digest)
  747. X     { ll=maxindex(cdigest);
  748. X       do                      /* check for new digest header */
  749. X          if(p==cdigest[ll].lnr&&!strncmp(buf,cdigest[ll].hedr,p))
  750. X           { *namep=lnl=0;goto splitit;      /* pretend we started over */
  751. X           }
  752. X       while(ll--);
  753. X     }
  754. X      }
  755. X     while(i!='\n'&&(lnl==2||p<dig_HDR_LEN));
  756. X     if(lnl==2)
  757. X      { buf[p]='\0';         /* perform more thorough check for postmark */
  758. X    if((ll=strcspn(chp=pstrspn(buf+STRLEN(From)," ")," \t\n"))&&
  759. X     *(chp+=ll)==' '&&(ll= *(chp=pstrspn(chp," ")))!='\t'&&ll!='\n')
  760. X     {
  761. Xsplitit:   if((fclose(mystdout)==EOF||errout==EOF)&&!quiet)
  762. X        { nlog(couldntw);log(", continuing...\n");split= -1;
  763. X        }
  764. X       if(!nowait)
  765. X          waitforit();
  766. X       startprog(argv);
  767. X       if(!lnl)                        /* digest split? */
  768. X          goto redigest;
  769. X       i='\n';
  770. X     }
  771. X      }
  772. X     lnl=p==1;putssn(buf,p);p=0;
  773. X     if(i!='\n')
  774. X    do Nextchar(i);
  775. X    while(putcs(i),i!='\n');
  776. X   }
  777. Xfoundeof:
  778. X  putssn(buf,p);closemine();child= -1;waitforit();    /* wait for everyone */
  779. X  return split<0?EX_IOERR:EX_OK;
  780. X}
  781. X
  782. Xlog(a)const char*const a;
  783. X{ fputs(a,stderr);
  784. X}
  785. X
  786. Xlogqnl(a)const char*a;
  787. X{ log(" \"");log(a);log("\"\n");
  788. X}
  789. X
  790. Xputss(a)const char*a;
  791. X{ while(*a)
  792. X     putcs(*a++);
  793. X}
  794. X
  795. Xtputssn(a,l)const char*a;size_t l;
  796. X{ while(l--)
  797. X     putcs(*a++);
  798. X}
  799. X
  800. Xstartprog(argv)const char*const*const argv;
  801. X{ int poutfd[2];
  802. X  if(!nrtotal)
  803. X     goto squelch;
  804. X  if(nrskip)
  805. X   { --nrskip;
  806. Xsquelch:
  807. X     opensink();return;
  808. X   }
  809. X  if(nrtotal>0)
  810. X     --nrtotal;
  811. X  dup(oldstdout);pipe(poutfd);
  812. X  if(!(child=fork()))
  813. X   { close(oldstdout);close(PWRO);fclose(stdin);dup(PRDO);close(PRDO);
  814. X     shexec(argv);
  815. X   }
  816. X  close(STDOUT);close(PRDO);
  817. X  if(STDOUT!=dup(PWRO)||!(mystdout=fdopen(STDOUT,"a")))
  818. X     nofild();
  819. X  close(PWRO);
  820. X  if(-1==child)
  821. X   { nlog("Can't fork\n");exit(EX_OSERR);
  822. X   }
  823. X}
  824. X
  825. Xnofild()
  826. X{ nlog("File table full\n");exit(EX_OSERR);
  827. X}
  828. X
  829. Xwaitforit()
  830. X{ int i;pid_t j;
  831. X  while(child!=(j=wait(&i))||(i&127)==127)
  832. X    if(-1==j)
  833. X       return;
  834. X}
  835. X
  836. Xnlog(a)const char*const a;
  837. X{ log(NAMEPREFIX);log(a);
  838. X}
  839. X
  840. Xclosemine()
  841. X{ if((fclose(mystdout)==EOF||errout==EOF)&&!quiet)
  842. X   { nlog(couldntw);log("\n");;exit(EX_IOERR);
  843. X   }
  844. X}
  845. X
  846. Xopensink()
  847. X{ if(!(mystdout=fopen(DevNull,"a")))
  848. X     nofild();
  849. X}
  850. X
  851. Xputnl()
  852. X{ putcs('\n');
  853. X}
  854. X
  855. Xstrnicmp(a,b,l)register const char*a,*b;register unsigned l;
  856. X{ int i,j;
  857. X  if(l)                         /* case insensitive strncmp */
  858. X     do
  859. X      { while(*a&&*a==*b&&--l)
  860. X       ++a,++b;
  861. X    if(!l)
  862. X       break;
  863. X    if((i= *a++)>='A'&&i<='Z')
  864. X       i+='a'-'A';
  865. X    if((j= *b++)>='A'&&j<='Z')
  866. X       j+='a'-'A';
  867. X    if(j!=i)
  868. X       return i>j?1:-1;
  869. X      }
  870. X     while(i&&j&&--l);
  871. X  return 0;
  872. X}
  873. END_OF_FILE
  874.   if test 12561 -ne `wc -c <'procmail/formail.c'`; then
  875.     echo shar: \"'procmail/formail.c'\" unpacked with wrong size!
  876.   fi
  877.   # end of 'procmail/formail.c'
  878. fi
  879. if test -f 'procmail/regexp.c' -a "${1}" != "-c" ; then 
  880.   echo shar: Will not clobber existing file \"'procmail/regexp.c'\"
  881. else
  882.   echo shar: Extracting \"'procmail/regexp.c'\" \(10952 characters\)
  883.   sed "s/^X//" >'procmail/regexp.c' <<'END_OF_FILE'
  884. X/************************************************************************
  885. X *    Custom regular expression library, *fully* egrep compatible    *
  886. X *                                    *
  887. X *    Copyright (c) 1990-1991, S.R.van den Berg, The Netherlands    *
  888. X *    The sources can be freely copied for non-commercial use.    *
  889. X *    #include "README"                        *
  890. X *                                    *
  891. X ************************************************************************/
  892. X#ifdef RCS
  893. Xstatic char rcsid[]="$Id: regexp.c,v 2.4 1991/10/18 15:34:23 berg Rel $";
  894. X#endif
  895. X#include "config.h"
  896. X#include "procmail.h"
  897. X#include "shell.h"
  898. X
  899. X#define R_BEG_GROUP    '('
  900. X#define R_END_GROUP    ')'
  901. X#define R_OR        '|'
  902. X#define R_0_OR_MORE    '*'
  903. X#define R_0_OR_1    '?'
  904. X#define R_1_OR_MORE    '+'
  905. X#define R_DOT        '.'
  906. X#define R_SOL        '^'
  907. X#define R_EOL        '$'
  908. X#define R_BEG_CLASS    '['
  909. X#define R_NOT_CLASS    '^'
  910. X#define R_RANGE        '-'
  911. X#define R_END_CLASS    ']'
  912. X#define R_ESCAPE    '\\'
  913. X
  914. X#define OPB    256
  915. Xenum opcode {OPC_EPS=OPB,OPC_CLASS,OPC_DOT,OPC_FIN};
  916. X
  917. X#define bit_type        unsigned
  918. X#define bit_bits        (sizeof(bit_type)*8)
  919. X#define bit_index(which)    ((unsigned)(which)/bit_bits)
  920. X#define bit_mask(which)        ((unsigned)1<<(unsigned)(which)%bit_bits)
  921. X#define bit_toggle(name,which)    (name[bit_index(which)]^=bit_mask(which))
  922. X#define bit_test(name,which)    (!!(name[bit_index(which)]&bit_mask(which)))
  923. X#define bit_set(name,which,value)    \
  924. X (value?(name[bit_index(which)]|=bit_mask(which)):\
  925. X (name[bit_index(which)]&=~bit_mask(which)))
  926. X#define bit_field(name,size)    bit_type name[((size)+bit_bits-1)/bit_bits]
  927. X
  928. X#define SZ(x)        (sizeof(struct x))
  929. X#define Ceps        (struct eps*)
  930. X
  931. X/* the spawn and stack members are reused in the normal opcodes as pc fields */
  932. Xstatic struct eps{int opc;struct eps*next,*spawn,*stack;}*r,aleps;
  933. Xstatic uchar*p;
  934. Xstatic ignore_case;
  935. X
  936. Xstruct chclass {int opc_;struct eps*next_,*spawn_,*stack_;bit_field(c,256);};
  937. X
  938. Xstatic puteps(spot,to,aswell)struct eps*const spot;    /* epsilon transition */
  939. X const struct eps*const to,*const aswell;
  940. X{ spot->opc=OPC_EPS;spot->next=to!=spot?Ceps to:Ceps aswell;
  941. X  spot->spawn=aswell!=spot?Ceps aswell:Ceps to;spot->stack=0;
  942. X}
  943. X
  944. Xstatic putneps(spot,to)struct eps*const spot;const struct eps*const to;
  945. X{ puteps(spot,to,spot+1);
  946. X}
  947. X
  948. X#define rAc    (((struct chclass*)r)->c)
  949. X
  950. Xstatic bseti(i,j)unsigned i;const int j;
  951. X{ bit_set(rAc,i,j);               /* mark 'i' as being in the class */
  952. X  if(ignore_case)                  /* mark the other case too */
  953. X   { if(i-'A'<26)                        /* uppercase */
  954. X    i+='a'-'A';
  955. X     else if(i-'a'<26)                        /* lowercase */
  956. X    i-='a'-'A';
  957. X     else return;                          /* no case */
  958. X     bit_set(rAc,i,j);
  959. X   }
  960. X}
  961. X
  962. Xstatic por();
  963. X
  964. Xstatic psimp(e)struct eps const*const e;
  965. X{ switch(*p)
  966. X   { case R_BEG_GROUP:                  /* not so simple after all */
  967. X    ++p;por(e);return;
  968. X     case R_BEG_CLASS:                       /* a simple class */
  969. X      { uchar i,j=R_NOT_CLASS==*++p;               /* char to save space */
  970. X    if(e)
  971. X     { r->opc=OPC_CLASS;r->next=Ceps e;r->spawn=r->stack=0;
  972. X       i=maxindex(rAc);
  973. X       do rAc[i]=j?~0:0;                 /* preset the bit field */
  974. X       while(i--);
  975. X     }
  976. X    if(j)                      /* skip the 'not' modifier */
  977. X     { ++p;bit_toggle(rAc,'\n');
  978. X     }
  979. X    if(*p==R_END_CLASS)     /* right at the start, can not mean the end */
  980. X     { ++p;
  981. X       if(e)
  982. X        { i=R_END_CLASS;bit_toggle(rAc,R_END_CLASS);
  983. X        }
  984. X     }
  985. X    else if(*p==R_RANGE)                /* take it literally */
  986. X     { ++p;
  987. X       if(e)
  988. X        { i=R_RANGE;bit_toggle(rAc,R_RANGE);
  989. X        }
  990. X     }
  991. X    for(;;++p)
  992. X     { switch(*p)
  993. X        { case R_END_CLASS:++p;
  994. X          case '\0':r=Ceps((char*)r+SZ(chclass));return;
  995. X                /* add code here to take care of special escapes */
  996. X          case R_RANGE:
  997. X         switch(*++p)
  998. X          { default:
  999. X               if(e)
  1000. X              while(++i<*p)            /* mark all in the range */
  1001. X                 bseti(i,!j);
  1002. X               break;
  1003. X            case '\0':case R_END_CLASS:--p;        /* literally */
  1004. X          }
  1005. X        }
  1006. X       if(e)
  1007. X          bseti(i= *p,!j);              /* a normal character, mark it */
  1008. X     }
  1009. X      }
  1010. X     case '\0':return;
  1011. X     case R_DOT:             /* matches everything but a newline */
  1012. X    if(e)
  1013. X     { r->opc=OPC_DOT;goto fine;
  1014. X     }
  1015. X    goto fine2;
  1016. X     case R_SOL:case R_EOL:              /* match a newline (in effect) */
  1017. X    if(e)
  1018. X     { r->opc='\n';goto fine;
  1019. X     }
  1020. X    goto fine2;
  1021. X     case R_ESCAPE:                      /* quote something */
  1022. X    if(!*++p)                     /* nothing to quote */
  1023. X       --p;
  1024. X                /* add code here to take care of special escapes */
  1025. X   }
  1026. X  if(e)                              /* a regular character */
  1027. X   { r->opc=ignore_case&&(unsigned)*p-'A'<26?*p+'a'-'A':*p;
  1028. Xfine:
  1029. X     r->next=Ceps e;r->spawn=r->stack=0;
  1030. X   }
  1031. Xfine2:
  1032. X  ++p;++r;
  1033. X}
  1034. X
  1035. Xstatic skipent()
  1036. X{ switch(*p++)
  1037. X   { case '\0':p--;break;
  1038. X     case R_ESCAPE:                      /* something is quoted */
  1039. X                /* add code here to take care of special escapes */
  1040. X    if(*p)
  1041. X       ++p;
  1042. X    break;
  1043. X     case R_BEG_GROUP:                 /* something big lies ahead */
  1044. X    for(;;)
  1045. X     { switch(*p)
  1046. X        { case R_END_GROUP:++p;          /* back in the civilised world */
  1047. X          case '\0':return;
  1048. X        }
  1049. X       skipent();                 /* skip it one entity at a time */
  1050. X     }
  1051. X     case R_BEG_CLASS:                       /* skip class :-) */
  1052. X    if(*p==R_NOT_CLASS)
  1053. X       ++p;
  1054. X    if(*p==R_END_CLASS)
  1055. X       ++p;
  1056. X    for(;;)
  1057. X       switch(*p++)
  1058. X        { case '\0':--p;
  1059. X          case R_END_CLASS:return;
  1060. X                /* add code here to take care of special escapes */
  1061. X        }
  1062. X   }
  1063. X}
  1064. X                    /* EOS is needed to save stack space */
  1065. X#define EOS(x)    (p[1]==R_OR||p[1]==R_END_GROUP||!p[1]?Ceps e:(x))
  1066. X
  1067. Xstatic pnorm(e)struct eps const*const e;
  1068. X{ void*pold;struct eps*rold;
  1069. X  for(;;)
  1070. X   { pold=p;skipent();rold=r;       /* skip it first, so we can look if it is */
  1071. X     switch(*p)             /* followed by any of the postfix operators */
  1072. X      { case R_0_OR_MORE:p=pold;++r;
  1073. X       if(e)              /* first an epsilon, then the rest */
  1074. X        { psimp(rold);putneps(rold,EOS(r));
  1075. X        }
  1076. X       else
  1077. X          psimp((struct eps*)0);
  1078. X       goto incagoon;
  1079. X    case R_1_OR_MORE:p=pold;psimp((struct eps*)0);       /* first the rest */
  1080. X       if(e)                      /* and then an epsilon */
  1081. X        { puteps(r,rold,EOS(r+1));p=pold;pold=r;r=rold;psimp(pold);
  1082. X        }
  1083. X       ++r;goto incagoon;
  1084. X    case R_0_OR_1:p=pold;++r;psimp((struct eps*)0);
  1085. X       if(e)              /* first an epsilon, then the rest */
  1086. X        { putneps(rold,r=EOS(r));p=pold;pold=r;r=rold+1;psimp(pold);
  1087. X        }
  1088. Xincagoon:  switch(*++p)            /* at the end of this group already? */
  1089. X        { case R_OR:case R_END_GROUP:case '\0':return;
  1090. X        }
  1091. X       continue;                 /* regular end of the group */
  1092. X    case R_OR:case R_END_GROUP:case '\0':p=pold;psimp(e);return;
  1093. X      }
  1094. X     p=pold;psimp((struct eps*)0);
  1095. X     if(e)            /* no fancy postfix operators, plain vanilla */
  1096. X      { p=pold;pold=r;r=rold;psimp(pold);
  1097. X      }
  1098. X   }
  1099. X}
  1100. X
  1101. Xstatic por(e)struct eps const*const e;
  1102. X{ uchar*pold;struct eps*rold;
  1103. X  for(;;)
  1104. X     for(pold=p;;)
  1105. X      { switch(*p)
  1106. X     { default:skipent();continue;         /* still in this 'or' group */
  1107. X       case '\0':case R_END_GROUP:           /* found the end of the group */
  1108. X          if(p==pold)                 /* empty 'or' group */
  1109. X           { if(e)
  1110. X            puteps(r,e,e);        /* misused epsilon as branch */
  1111. X         ++r;
  1112. X           }
  1113. X          else
  1114. X           { p=pold;pnorm(e);            /* normal last group */
  1115. X           }
  1116. X          if(*p)
  1117. X         ++p;
  1118. X          return;
  1119. X       case R_OR:rold=r++;
  1120. X          if(p==pold)                 /* empty 'or' group */
  1121. X           { if(e)
  1122. X            putneps(rold,e);              /* special epsilon */
  1123. X           }
  1124. X          else
  1125. X           { p=pold;pnorm(e);          /* normal 'or' group, first an */
  1126. X         if(e)                   /* epsilon, then the rest */
  1127. X            putneps(rold,r);
  1128. X           }
  1129. X          ++p;
  1130. X     }
  1131. X    break;
  1132. X      }
  1133. X}
  1134. X
  1135. Xstatic findandrep(old,new)register struct eps*const*const old;
  1136. X struct eps*const new;
  1137. X{ register struct eps*i;
  1138. X  for(i=r;;++i)                 /* change all pointers from *old to new */
  1139. X   { if(&i->next!=old&&i->next==*old)
  1140. X    i->next=new;
  1141. X     if(&i->spawn!=old&&i->spawn==*old)
  1142. X    i->spawn=new;
  1143. X     switch(i->opc)
  1144. X      { case OPC_FIN:return;                  /* last one, ready */
  1145. X    case OPC_CLASS:i=Ceps((char*)(i-1)+SZ(chclass));
  1146. X      }
  1147. X   }
  1148. X}
  1149. X    /* break up any closed epsilon circles, otherwise they can't be executed */
  1150. Xstatic fillout(stack)struct eps**const stack;
  1151. X{ if((*stack)->opc!=OPC_EPS||(*stack)->stack)
  1152. X     return 0;
  1153. X  (*stack)->stack=(struct eps*)p;            /* mark this one as used */
  1154. X#define RECURS(nxt,spwn)    \
  1155. X  do\
  1156. X     if((*stack)->nxt->stack==(struct eps*)p)\
  1157. X      { findandrep(*stack,(*stack)->nxt);*stack=(*stack)->spwn;return 1;\
  1158. X      }\
  1159. X  while(fillout(&(*stack)->nxt));
  1160. X  RECURS(next,spawn);RECURS(spawn,next);return 0;          /* recurse */
  1161. X}
  1162. X
  1163. Xvoid*regcomp(a,ign_case)char const*const a;
  1164. X{ struct eps*st;size_t i;      /* first a trial run, determine memory needed */
  1165. X  p=(uchar*)a;ignore_case=ign_case;r= &aleps+2;por((struct eps*)0);p=(uchar*)a;
  1166. X  st=malloc(i=(char*)r-(char*)&aleps);putneps(st,r=st+1);  /* really compile */
  1167. X  por(Ceps((char*)st+i-SZ(eps)));r->opc=OPC_FIN;r->stack=0;      /* add end */
  1168. X  for(r=st;;++st)             /* simplify the compiled code (i.e. */
  1169. X     switch(st->opc)              /* take out cyclic epsilon references) */
  1170. X      { case OPC_FIN:return r;                     /* finished */
  1171. X    case OPC_EPS:p=(uchar*)st;fillout(&st);break;           /* check tree */
  1172. X    case OPC_CLASS:st=Ceps((char*)(st-1)+SZ(chclass));         /* skip */
  1173. X      }
  1174. X}
  1175. X
  1176. Xchar*regexec(code,text,len,ign_case)struct eps*code;const uchar*text;
  1177. X long len;const int ign_case;
  1178. X{ register struct eps*reg,*t,*stack,*other,*this;int i,th1,ot1;
  1179. X  if(code[1].opc==OPC_EPS)
  1180. X     ++code;
  1181. X  (this=code)->stack=0;th1=offsetof(struct eps,spawn);
  1182. X  ot1=offsetof(struct eps,stack);
  1183. X#define XOR1        (offsetof(struct eps,spawn)^offsetof(struct eps,stack))
  1184. X#define PC(this,t)    (*(struct eps**)((char*)(this)+(t)))
  1185. X  i='\n';goto setups;          /* make sure any beginning-of-line-hooks catch */
  1186. X  do
  1187. X   { i= *text++;             /* get the next real-text character */
  1188. Xlastrun:                     /* switch this & other pc-stack */
  1189. X     th1^=XOR1;ot1^=XOR1;this=other;
  1190. Xsetups:
  1191. X     reg=(other=stack=code)->next;goto nostack;
  1192. X     do                     /* pop next entry off this pc-stack */
  1193. X      { reg=(t=this)->next;this=PC(t,th1);PC(t,th1)=0;goto nostack;
  1194. X    do                /* pop next entry off the work-stack */
  1195. X     { stack=(t=stack)->stack;t->stack=0;reg=t->spawn;
  1196. Xnostack:   switch(reg->opc-OPB)        /* push spawned branch on the work-stack */
  1197. X        { default:
  1198. X         if(ign_case&&(unsigned)i-'A'<26)
  1199. X            i+='a'-'A';             /* transmogrify it to lowercase */
  1200. X         if(i==reg->opc)          /* regular character match */
  1201. X            goto yep;
  1202. X         break;
  1203. X          case OPC_EPS-OPB:reg->stack=stack;reg=(stack=reg)->next;
  1204. X         goto nostack;
  1205. X          case OPC_FIN-OPB:           /* hurray!  complete regexp match */
  1206. X         return (char*)text-1;        /* return one past the match */
  1207. X          case OPC_CLASS-OPB:
  1208. X         if(bit_test(((struct chclass*)reg)->c,i))
  1209. X            goto yep;                   /* character in class */
  1210. X         break;
  1211. X          case OPC_DOT-OPB:                     /* dot-wildcard */
  1212. X         if(i!='\n')
  1213. Xyep:            if(!PC(reg,ot1))             /* state not yet pushed */
  1214. X             { PC(reg,ot1)=other;other=reg;    /* push location onto */
  1215. X             }                       /* other pc-stack */
  1216. X        }
  1217. X     }
  1218. X    while(stack);                  /* the work-stack is not empty */
  1219. X      }
  1220. X     while(this!=code);                   /* this pc-stack is not empty */
  1221. X   }
  1222. X  while(--len>=0);                     /* still text to search */
  1223. X  if(i>=0)
  1224. X   { ++text;i= -1;goto lastrun;        /* out of text, check if we just matched */
  1225. X   }
  1226. X  return 0;                             /* no match */
  1227. X}
  1228. END_OF_FILE
  1229.   if test 10952 -ne `wc -c <'procmail/regexp.c'`; then
  1230.     echo shar: \"'procmail/regexp.c'\" unpacked with wrong size!
  1231.   fi
  1232.   # end of 'procmail/regexp.c'
  1233. fi
  1234. if test -f 'procmail/retint.c' -a "${1}" != "-c" ; then 
  1235.   echo shar: Will not clobber existing file \"'procmail/retint.c'\"
  1236. else
  1237.   echo shar: Extracting \"'procmail/retint.c'\" \(11077 characters\)
  1238.   sed "s/^X//" >'procmail/retint.c' <<'END_OF_FILE'
  1239. X/************************************************************************
  1240. X *    Collection of routines that return an int (sort of anyway :-)    *
  1241. X *                                    *
  1242. X *    Copyright (c) 1990-1991, S.R.van den Berg, The Netherlands    *
  1243. X *    The sources can be freely copied for non-commercial use.    *
  1244. X *    #include "README"                        *
  1245. X *                                    *
  1246. X ************************************************************************/
  1247. X#ifdef RCS
  1248. Xstatic char rcsid[]="$Id: retint.c,v 2.12 1991/10/22 15:31:26 berg Rel $";
  1249. X#endif
  1250. X#include "config.h"
  1251. X#include "procmail.h"
  1252. X#include "shell.h"
  1253. X
  1254. Xsetdef(name,contents)const char*const name,*const contents;
  1255. X{ strcat(strcat(strcpy(sgetcp=buf2,name),"="),contents);
  1256. X  readparse(buf,sgetc,0);sputenv(buf);
  1257. X}
  1258. X
  1259. Xchar*lastexec,*backblock;
  1260. Xlong backlen;               /* length of backblock, filter recovery block */
  1261. Xpid_t pidfilt,pidchild;
  1262. Xint pbackfd[2];                       /* the emergency backpipe :-) */
  1263. X
  1264. Xpipthrough(line,source,len)char*line,*source;const long len;
  1265. X{ int pinfd[2],poutfd[2];
  1266. X  rpipe(pbackfd);rpipe(pinfd);                 /* main pipes setup */
  1267. X  if(!(pidchild=sfork()))            /* create a sending procmail */
  1268. X   { backblock=source;backlen=len;signal(SIGTERM,stermchild);
  1269. X     signal(SIGINT,stermchild);signal(SIGHUP,stermchild);
  1270. X     signal(SIGQUIT,stermchild);rclose(rc);rclose(PRDI);rclose(PRDB);
  1271. X     rpipe(poutfd);rclose(STDOUT);
  1272. X     if(!(pidfilt=sfork()))                /* create the filter */
  1273. X      { rclose(PWRO);rclose(PWRB);rdup(PWRI);rclose(PWRI);getstdin(PRDO);
  1274. X    callnewprog(line);
  1275. X      }
  1276. X     rclose(PWRI);rclose(PRDO);
  1277. X     if(forkerr(pidfilt,line))
  1278. X      { rclose(PWRO);stermchild();
  1279. X      }
  1280. X     if(dump(PWRO,source,len))          /* send in the text to be filtered */
  1281. X      { writeerr(line);stermchild();
  1282. X      }
  1283. X     if(pwait&&waitfor(pidfilt)!=EX_OK)     /* check the exitcode of the filter */
  1284. X      { progerr(line);stermchild();
  1285. X      }
  1286. X     rclose(PWRB);exit(EX_OK);              /* allow parent to proceed */
  1287. X   }
  1288. X  rclose(PWRI);rclose(PWRB);getstdin(PRDI);
  1289. X  if(forkerr(pidchild,procmailn))
  1290. X     return 1;
  1291. X  return 0;            /* we stay behind to read back the filtered text */
  1292. X}
  1293. X
  1294. Xwaitfor(pid)const pid_t pid;              /* wait for a specific process */
  1295. X{ int i;pid_t j;
  1296. X  while(pid!=(j=wait(&i))||(i&127)==127)
  1297. X     if(-1==j)
  1298. X    return EX_UNAVAILABLE;
  1299. X  return i>>8&255;
  1300. X}
  1301. X
  1302. Xgetstdin(pip)const int pip;
  1303. X{ rclose(STDIN);rdup(pip);rclose(pip);
  1304. X}
  1305. X
  1306. Xcallnewprog(newname)const char*const newname;
  1307. X{ if(sh)                     /* should we start a shell? */
  1308. X   { const char*newargv[4];
  1309. X     yell(executing,newname);newargv[3]=0;newargv[2]=newname;
  1310. X     newargv[1]=tgetenv(shellflags);*newargv=tgetenv(shell);shexec(newargv);
  1311. X   }
  1312. X {register const char*p;int argc;const char**newargv;
  1313. X  argc=1;p=newname;         /* If no shell, chop up the arguments ourselves */
  1314. X  if(verbose)
  1315. X   { log(executing);log(oquote);goto no_1st_comma;
  1316. X   }
  1317. X  do                         /* show chopped up command line */
  1318. X   { if(verbose)
  1319. X      { log(",");
  1320. Xno_1st_comma:
  1321. X    log(p);
  1322. X      }
  1323. X     while(*p++);
  1324. X   }
  1325. X  while(argc++,*p!=TMNATE);
  1326. X  if(verbose)
  1327. X     log(cquote);
  1328. X  newargv=malloc(argc*sizeof*newargv);p=newname;argc=0;     /* alloc argv array */
  1329. X  do
  1330. X   { newargv[argc++]=p;
  1331. X     while(*p++);
  1332. X   }
  1333. X  while(*p!=TMNATE);
  1334. X  newargv[argc]=0;shexec(newargv);
  1335. X }
  1336. X}
  1337. X
  1338. Xwriteerr(line)const char*const line;
  1339. X{ log("Error while writing to");logqnl(line);
  1340. X}
  1341. X
  1342. Xforkerr(pid,a)const pid_t pid;const char*const a;
  1343. X{ if(pid==-1)
  1344. X   { log("Failed forking");logqnl(a);return 1;
  1345. X   }
  1346. X  return 0;
  1347. X}
  1348. X
  1349. Xprogerr(line)const char*const line;
  1350. X{ log("Program failure of");logqnl(line);
  1351. X}
  1352. X
  1353. Xopena(a)const char*const a;
  1354. X{ lastfolder=cstr(lastfolder,a);yell("Opening",a);
  1355. X#ifdef O_CREAT
  1356. X  return ropen(a,O_WRONLY|O_APPEND|O_CREAT,0666);
  1357. X#else
  1358. X {int fd;
  1359. X  return(fd=ropen(a,O_WRONLY))<0?creat(a,0666):fd;
  1360. X }
  1361. X#endif
  1362. X}
  1363. X
  1364. Xyell(a,b)const char*const a,*const b;             /* log if -d option set */
  1365. X{ if(verbose)
  1366. X   { log(a);logqnl(b);
  1367. X   }
  1368. X}
  1369. X
  1370. Xunlock(lockp)const char**const lockp;
  1371. X{ lcking=1;
  1372. X  if(*lockp)
  1373. X   { yell("Unlocking",*lockp);
  1374. X     if(unlink(*lockp))
  1375. X      { log("Couldn't unlock");logqnl(*lockp);
  1376. X      }
  1377. X     free(*lockp);*lockp=0;
  1378. X   }
  1379. X  lcking=0;
  1380. X  if(nextexit==1)        /* make sure we are not inside terminate already */
  1381. X   { log(newline);terminate();
  1382. X   }
  1383. X}
  1384. X
  1385. Xnomemerr()
  1386. X{ log("Out of memory\nbuffer 0: \"");buf[linebuf-1]=buf2[linebuf-1]='\0';
  1387. X  log(buf);log("\"\nbuffer 1:");logqnl(buf2);retval=EX_OSERR;terminate();
  1388. X}
  1389. X
  1390. Xlogqnl(a)const char*const a;
  1391. X{ log(oquote);log(a);log(cquote);
  1392. X}
  1393. X
  1394. Xnextrcfile()            /* next rcfile specified on the command line */
  1395. X{ const char*p;
  1396. X  while(p= *gargv)
  1397. X   { gargv++;
  1398. X     if(!strchr(p,'='))
  1399. X      { rcfile=p;return 1;
  1400. X      }
  1401. X   }
  1402. X  return 0;
  1403. X}
  1404. X
  1405. Xrclose(fd)const int fd;              /* a sysV secure close (signal immune) */
  1406. X{ int i;
  1407. X  while((i=close(fd))&&errno==EINTR);
  1408. X  return i;
  1409. X}
  1410. X
  1411. Xrwrite(fd,a,len)const int fd,len;void*const a;          /* a sysV secure write */
  1412. X{ int i;
  1413. X  while(0>(i=write(fd,a,(size_t)len))&&errno==EINTR);
  1414. X  return i;
  1415. X}
  1416. X
  1417. Xrread(fd,a,len)const int fd,len;void*const a;           /* a sysV secure read */
  1418. X{ int i;
  1419. X  while(0>(i=read(fd,a,(size_t)len))&&errno==EINTR);
  1420. X  return i;
  1421. X}
  1422. X
  1423. Xropen(name,mode,mask)const char*const name;const int mode;const mode_t mask;
  1424. X{ int i,r;                           /* a sysV secure open */
  1425. X  for(lcking=4,r=noresretry;0>(i=open(name,mode,mask));)
  1426. X     if(errno!=EINTR&&!((errno==EMFILE||errno==ENFILE)&&(r<0||r--)))
  1427. X    break;         /* survives a temporary "file table full" condition */
  1428. X  lcking=0;return i;
  1429. X}
  1430. X
  1431. Xrdup(p)const int p;
  1432. X{ int i,r;
  1433. X  for(lcking=4,r=noresretry;0>(i=dup(p));)      /* catch "file table full" */
  1434. X     if(!((errno==EMFILE||errno==ENFILE)&&(r<0||r--)))
  1435. X    break;
  1436. X  lcking=0;return i;
  1437. X}
  1438. X
  1439. Xrpipe(fd)int fd[2];
  1440. X{ int i,r;
  1441. X  for(lcking=4,r=noresretry;0>(i=pipe(fd));)      /* catch "file table full" */
  1442. X     if(!((errno==EMFILE||errno==ENFILE)&&(r<0||r--)))
  1443. X      { *fd=fd[1]= -1;break;
  1444. X      }
  1445. X  lcking=0;return i;
  1446. X}
  1447. X
  1448. Xlockit(name,lockp)char*name;const char**const lockp;
  1449. X{ int i;struct stat stbuf;
  1450. X  unlock(lockp);               /* unlock any previous lockfile FIRST */
  1451. X  if(!*name)
  1452. X     return;
  1453. X  for(lcking=1;;)          /* to prevent deadlocks (I hate deadlocks) */
  1454. X   { yell("Locking",name);
  1455. X     if(!NFSxopen(name))
  1456. X      { *lockp=tstrdup(name);               /* lock acquired, hurray! */
  1457. Xterm:    lcking=0;
  1458. X    if(nextexit)
  1459. X     { log(whilstwfor);log("lockfile");logqnl(name);terminate();
  1460. X     }
  1461. X    return;               /* check if it's time for a lock override */
  1462. X      }
  1463. X     if(errno==EEXIST&&!stat(name,&stbuf)&&!stbuf.st_size)
  1464. X      { time_t t;
  1465. X    if(locktimeout&&(t=time((time_t*)0),!stat(name,&stbuf)))     /* stat */
  1466. X       if(locktimeout<t-stbuf.st_mtime)  /* till unlink should be atomic */
  1467. X        { if(unlink(name))             /* but can't guarantee that */
  1468. X           { log("Forced unlock denied on");logqnl(name);
  1469. X           }
  1470. X          else
  1471. X           { log("Forcing lock on");logqnl(name);suspend();
  1472. X           }
  1473. X        }
  1474. X      }
  1475. X     else               /* maybe filename too long, shorten and retry */
  1476. X      { if(errno!=ENOTDIR&&0<(i=strlen(name)-1)&&!strchr(dirsep,name[i-1]))
  1477. X     { name[i]='\0';continue;
  1478. X     }
  1479. X    log("Lockfailure on");logqnl(name);return;
  1480. X      }
  1481. X     sleep((unsigned)locksleep);
  1482. X     if(nextexit)
  1483. X    goto term;
  1484. X   }
  1485. X}
  1486. X
  1487. Xlcllock()                   /* lock a local file (if need be) */
  1488. X{ if(locknext)
  1489. X     if(tolock)
  1490. X    lockit(tolock,&loclock);
  1491. X     else
  1492. X    lockit(strcat(buf2,tgetenv(lockext)),&loclock);
  1493. X}
  1494. X
  1495. Xterminate()
  1496. X{ nextexit=2;            /* prevent multiple invocations of terminate */
  1497. X  if(getpid()==thepid)
  1498. X   { if(retval!=EX_OK)
  1499. X      { log(Mail);
  1500. X    log(fakedelivery?"lost\n":
  1501. X     retval==EX_TEMPFAIL?"requeued\n":"bounced\n");
  1502. X      }
  1503. X     unlock(&loclock);unlock(&globlock);unlockfd();
  1504. X   }
  1505. X  exit(retval);
  1506. X}
  1507. X
  1508. Xignoreterm()
  1509. X{ signal(SIGTERM,SIG_IGN);signal(SIGHUP,SIG_IGN);signal(SIGINT,SIG_IGN);
  1510. X  signal(SIGQUIT,SIG_IGN);
  1511. X}
  1512. X
  1513. Xsuspend()
  1514. X{ long t;
  1515. X  sleep((unsigned)suspendv);
  1516. X  if(alrmtime)
  1517. X     if((t=alrmtime-time((time_t*)0))<=1)      /* if less than 1s timeout */
  1518. X    ftimeout();                  /* activate it by hand now */
  1519. X     else            /* set it manually again, to avoid problems with */
  1520. X    alarm((unsigned)t);    /* badly implemented sleep library functions */
  1521. X}
  1522. X
  1523. Xinittmout(progname)const char*const progname;
  1524. X{ lastexec=cstr(lastexec,progname);
  1525. X  alrmtime=timeoutv?time((time_t*)0)+(unsigned)timeoutv:0;
  1526. X  alarm((unsigned)timeoutv);
  1527. X}
  1528. X
  1529. Xskipspace()
  1530. X{ while(testb(' ')||testb('\t'));
  1531. X}
  1532. X
  1533. Xsgetc()                        /* a fake fgetc for a string */
  1534. X{ return *sgetcp?*(uchar*)sgetcp++:EOF;
  1535. X}
  1536. X
  1537. Xskipped(x)const char*const x;
  1538. X{ log("Skipped");logqnl(x);
  1539. X}
  1540. X
  1541. Xconcatenate(old)char*const old;
  1542. X{ register char*p=old;
  1543. X  while(*p!=TMNATE)              /* concatenate all other arguments */
  1544. X   { while(*p++);
  1545. X     p[-1]=' ';
  1546. X   }
  1547. X  *p=p[-1]='\0';return*old;
  1548. X}
  1549. X
  1550. Xdetab(p)char*p;
  1551. X{ while(p=strchr(p,'\t'))
  1552. X     *p=' ';                        /* take out all tabs */
  1553. X}
  1554. X
  1555. Xstatic uchar rcbuf[STDBUF],*rcbufp,*rcbufend;     /* buffers for custom stdio */
  1556. Xstatic ungetb;                         /* pushed back char */
  1557. X
  1558. Xbopen(name)const char*const name;                 /* my fopen */
  1559. X{ rcbufp=rcbufend=0;ungetb= -1;yell("Rcfile:",name);
  1560. X  return rc=ropen(name,O_RDONLY);
  1561. X}
  1562. X
  1563. Xgetbl(p)char*p;                              /* my gets */
  1564. X{ int i;char*q;
  1565. X  for(q=p;;)
  1566. X   { switch(i=getb())
  1567. X      { case '\n':case EOF:
  1568. X       *p='\0';return p!=q;             /* did we read anything at all? */
  1569. X      }
  1570. X     *p++=i;
  1571. X   }
  1572. X}
  1573. X
  1574. Xgetb()                                 /* my fgetc */
  1575. X{ if(ungetb>=0)                        /* anything pushed back? */
  1576. X   { int i;
  1577. X     i=ungetb;ungetb= -1;return i;
  1578. X   }
  1579. X  if(rcbufp==rcbufend)
  1580. X   { rcbufend=rcbuf+rread(rc,rcbufp=rcbuf,STDBUF);           /* refill */
  1581. X   }
  1582. X  return rcbufp<rcbufend?*rcbufp++:EOF;
  1583. X}
  1584. X
  1585. Xtestb(x)const int x;           /* fgetc that only succeeds if it matches */
  1586. X{ int i;
  1587. X  if((i=getb())==x)
  1588. X     return 1;
  1589. X  ungetb=i;return 0;
  1590. X}
  1591. X
  1592. Xalphanum(c)const int c;
  1593. X{ return c>='0'&&c<='9'||c>='a'&&c<='z'||c>='A'&&c<='Z'||c=='_';
  1594. X}
  1595. X                       /* open file or new file in directory */
  1596. Xdeliver(boxname)char*const boxname;
  1597. X{ struct stat stbuf;
  1598. X  strcpy(buf,boxname);             /* boxname can be found back in buf */
  1599. X  return stat(buf,&stbuf)||!S_ISDIR(stbuf.st_mode)?
  1600. X   (tofolder=1,opena(buf)):dirmail();
  1601. X}
  1602. X
  1603. X#ifndef lockfd
  1604. Xstatic oldlockfd;                    /* the fd we locked last */
  1605. X#ifdef F_SETLKW
  1606. Xstatic struct flock flck;        /* why can't it be a local variable? */
  1607. X
  1608. Xlockfd(fd)                       /* the POSIX-fcntl() lock */
  1609. X{ flck.l_type=F_WRLCK;flck.l_whence=SEEK_SET;flck.l_len=0;
  1610. X  flck.l_start=tell(fd);lcking=5;fd=fcntl(oldlockfd=fd,F_SETLKW,&flck);
  1611. X  lcking=0;return fd;
  1612. X}
  1613. X
  1614. Xunlockfd()
  1615. X{ flck.l_type=F_UNLCK;return fcntl(oldlockfd,F_SETLK,&flck);
  1616. X}
  1617. X#else
  1618. X#ifdef F_LOCK
  1619. Xstatic long oldlockoffset;
  1620. X
  1621. Xlockfd(fd)                         /* the sysV-lockf() */
  1622. X{ oldlockoffset=tell(fd);lcking=5;fd=lockf(oldlockfd=fd,F_LOCK,0L);lcking=0;
  1623. X  return fd;
  1624. X}
  1625. X
  1626. Xunlockfd()
  1627. X{ lseek(oldlockfd,oldlockoffset,SEEK_SET);return lockf(oldlockfd,F_ULOCK,0L);
  1628. X}
  1629. X#else
  1630. X#ifdef LOCK_EX
  1631. Xlockfd(fd)                          /* the BSD-flock() */
  1632. X{ lcking=5;fd=flock(oldlockfd=fd,LOCK_EX);lcking=0;return fd;
  1633. X}
  1634. X
  1635. Xunlockfd()
  1636. X{ return flock(oldlockfd,LOCK_UN);
  1637. X}
  1638. X#endif
  1639. X#endif
  1640. X#endif
  1641. X#endif
  1642. X
  1643. X#include "exopen.h"
  1644. X
  1645. XNFSxopen(name)char*name;        /* an NFS secure exclusive file open */
  1646. X{char*p,*q;int j= -2,i;
  1647. X  for(q=name;p=strpbrk(q,dirsep);q=p+1);         /* find last DIRSEP */
  1648. X  i=q-name;strncpy(p=malloc(i+UNIQnamelen),name,i);
  1649. X  if(unique(p,p+i,0))
  1650. X     j=myrename(p,name);     /* try and rename it, fails if nonexclusive */
  1651. X  free(p);return j;
  1652. X}
  1653. END_OF_FILE
  1654.   if test 11077 -ne `wc -c <'procmail/retint.c'`; then
  1655.     echo shar: \"'procmail/retint.c'\" unpacked with wrong size!
  1656.   fi
  1657.   # end of 'procmail/retint.c'
  1658. fi
  1659. echo shar: End of archive 2 \(of 4\).
  1660. cp /dev/null ark2isdone
  1661. MISSING=""
  1662. for I in 1 2 3 4 ; do
  1663.     if test ! -f ark${I}isdone ; then
  1664.     MISSING="${MISSING} ${I}"
  1665.     fi
  1666. done
  1667. if test "${MISSING}" = "" ; then
  1668.     echo You have unpacked all 4 archives.
  1669.     rm -f ark[1-9]isdone
  1670. else
  1671.     echo You still must unpack the following archives:
  1672.     echo "        " ${MISSING}
  1673. fi
  1674. exit 0
  1675. exit 0 # Just in case...
  1676. -- 
  1677. Kent Landfield                   INTERNET: kent@sparky.IMD.Sterling.COM
  1678. Sterling Software, IMD           UUCP:     uunet!sparky!kent
  1679. Phone:    (402) 291-8300         FAX:      (402) 291-4362
  1680. Please send comp.sources.misc-related mail to kent@uunet.uu.net.
  1681.