home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1994 March / Source_Code_CD-ROM_Walnut_Creek_March_1994.iso / compsrcs / misc / volume31 / procmail / part03 < prev    next >
Encoding:
Text File  |  1992-07-15  |  56.3 KB  |  1,601 lines

  1. Newsgroups: comp.sources.misc
  2. From: berg@pool.informatik.rwth-aachen.de (Stephen R. van den Berg)
  3. Subject:  v31i042:  procmail - mail processing program v2.71, Part03/05
  4. Message-ID: <1992Jul16.204555.20464@sparky.imd.sterling.com>
  5. X-Md4-Signature: f8343592e71805c3c339495257c01e3a
  6. Date: Thu, 16 Jul 1992 20:45:55 GMT
  7. Approved: kent@sparky.imd.sterling.com
  8.  
  9. Submitted-by: berg@pool.informatik.rwth-aachen.de (Stephen R. van den Berg)
  10. Posting-number: Volume 31, Issue 42
  11. Archive-name: procmail/part03
  12. Environment: UNIX, sendmail, smail, MMDF
  13. Supersedes: procmail: Volume 29, Issue 90-94
  14.  
  15. #! /bin/sh
  16. # This is a shell archive.  Remove anything before this line, then unpack
  17. # it by saving it into a file and typing "sh file".  To overwrite existing
  18. # files, type "sh file -c".  You can also feed this as standard input via
  19. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  20. # will see the following message at the end:
  21. #        "End of archive 3 (of 5)."
  22. # Contents:  procmail/autoconf procmail/config.h
  23. #   procmail/examples/3procmailrc procmail/examples/mailinglist
  24. #   procmail/goodies.c procmail/regexp.c
  25. # Wrapped by berg@minipicc on Thu Jul 16 14:34:21 1992
  26. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  27. if test -f 'procmail/autoconf' -a "${1}" != "-c" ; then 
  28.   echo shar: Will not clobber existing file \"'procmail/autoconf'\"
  29. else
  30. echo shar: Extracting \"'procmail/autoconf'\" \(9448 characters\)
  31. sed "s/^X//" >'procmail/autoconf' <<'END_OF_FILE'
  32. X
  33. X#$Id: autoconf,v 2.22 1992/06/30 16:42:26 berg Rel $
  34. X
  35. XSHELL=$4 || exec $4 autoconf $* # we're in a csh, feed myself to sh
  36. X
  37. X# All possible entries in autoconf.h:
  38. X
  39. X#    #define UNISTD_H_MISSING
  40. X#    #define STDDEF_H_MISSING
  41. X#    #define STDLIB_H_MISSING
  42. X#    #define DIRENT_H_MISSING
  43. X#    #define SYS_DIRENT_H_MISSING
  44. X#    #define NDIR_H_MISSING
  45. X#    #define SYS_DIR_H_MISSING
  46. X#    #define SYS_WAIT_H_MISSING
  47. X#    #define SYS_UTSNAME_H_MISSING
  48. X#    #define STRING_H_MISSING
  49. X#    #define SYSEXITS_H_MISSING
  50. X#    #define SYS_FILE_H_MISSING
  51. X#    #define const
  52. X#    #define volatile
  53. X#    #define void char
  54. X#    typedef int mode_t;
  55. X#    typedef int pid_t;
  56. X#    typedef int uid_t;
  57. X#    typedef int gid_t;
  58. X#    typedef unsigned size_t;
  59. X#    typedef long time_t;
  60. X#    #define NOmemmove
  61. X#    #define NObcopy
  62. X#    #define NOstrcspn
  63. X#    #define NOstrpbrk
  64. X#    #define NOopendir
  65. X#    #define NOrename
  66. X#    #define NOuname
  67. X#    #define strchr(s,c) index(s,c)
  68. X#    #define endpwent()
  69. X#    #define endgrent()
  70. X#    #define strtol(str,ptr,base) ((long)atoi(str))
  71. X#    #define WMACROS_NON_POSIX
  72. X#    #define oBRAIN_DAMAGE
  73. X#    #define LD_ENV_FIX
  74. X#    #define SMALLHEAP
  75. X#    #define SYSTEM_MAILBOX "/usr/spool/mail/$USER"
  76. X#    #define SENDMAIL "/usr/lib/sendmail"
  77. X
  78. X# A conforming ANSI compiler and POSIX library should only produce seven
  79. X# entries in autoconf.h: SYS_FILE_H_MISSING, endpwent(), endgrent(), rename(),
  80. X# SYSTEM_MAILBOX, LD_ENV_FIX, SENDMAIL (and perhaps SMALLHEAP)
  81. X# Anything else indicates failure of your installation to comply with either
  82. X# the ANSI or POSIX standards (but procmail should be installable anyway).
  83. X
  84. XPATH=:$PATH
  85. XACONF=$3
  86. XMAKE="$2"
  87. XRM="$5"
  88. XUSRINC=$6
  89. XDEVNULL=/dev/null
  90. Xexport SHELL PATH
  91. Xif test -f $ACONF
  92. Xthen
  93. X trap "exit 1" 1 2 3 15
  94. Xelse
  95. X trap "$RM $ACONF; exit 1" 1 2 3 15
  96. Xfi
  97. X
  98. Xif test -n "$LD_LIBRARY_PATH"
  99. Xthen
  100. X echo '***************************** WARNING *********************************'
  101. X echo '* You seem to have set the LD_LIBRARY_PATH variable, this might cause *'
  102. X echo '* some trouble during the execution of this autoconf script.  If you  *'
  103. X echo '* encounter errors about "_autotst not found" or any other         *'
  104. X echo '* irregularities, stop the make, do a: "make clean",             *'
  105. X echo '* clear LD_LIBRARY_PATH from the environment, and start over.         *'
  106. X echo '***************************** WARNING *********************************'
  107. Xfi
  108. X
  109. Xcat >grepfor <<HERE
  110. Xfgrep -e "\$1" _autotst.rrr >$DEVNULL && echo "\$2" >>$ACONF
  111. XHERE
  112. Xchmod 0755 grepfor
  113. X
  114. Xcat >$ACONF <<HERE
  115. X/* This file was automagically generated by autoconf */
  116. X
  117. XHERE
  118. X
  119. Xif test ! -f $USRINC/stdio.h
  120. Xthen echo 2>&1 "Panic!       I can't find your system include-files."
  121. X  echo 2>&1 "I already looked in \"$USRINC\".  Please edit the Makefile"
  122. X  echo 2>&1 "and make sure that the definition of USRINCLUDE is correct,"
  123. X  echo 2>&1 "before retrying another make."
  124. X  exit 1
  125. Xfi
  126. Xtest -f $USRINC/unistd.h || echo "#define UNISTD_H_MISSING" >>$ACONF
  127. Xtest -f $USRINC/stddef.h || echo "#define STDDEF_H_MISSING" >>$ACONF
  128. Xtest -f $USRINC/stdlib.h || echo "#define STDLIB_H_MISSING" >>$ACONF
  129. Xif test ! -f $USRINC/dirent.h
  130. Xthen echo "#define DIRENT_H_MISSING" >>$ACONF
  131. X   if test ! -f $USRINC/sys/dirent.h
  132. X      then echo "#define SYS_DIRENT_H_MISSING" >>$ACONF
  133. X     if test ! -f $USRINC/ndir.h
  134. X        then echo "#define NDIR_H_MISSING" >>$ACONF
  135. X           test -f $USRINC/sys/dir.h ||
  136. X        echo "#define SYS_DIR_H_MISSING" >>$ACONF
  137. X        fi
  138. X      fi
  139. Xfi
  140. Xtest -f $USRINC/dirent.h || echo "#define DIRENT_H_MISSING" >>$ACONF
  141. Xtest -f $USRINC/sys/wait.h || echo "#define SYS_WAIT_H_MISSING" >>$ACONF
  142. Xtest -f $USRINC/sys/utsname.h || echo "#define SYS_UTSNAME_H_MISSING" >>$ACONF
  143. Xtest -f $USRINC/string.h || echo "#define STRING_H_MISSING" >>$ACONF
  144. Xtest -f $USRINC/sysexits.h || echo "#define SYSEXITS_H_MISSING" >>$ACONF
  145. Xtest -f $USRINC/sys/file.h || echo "#define SYS_FILE_H_MISSING" >>$ACONF
  146. X
  147. Xcat >_autotst.c <<HERE
  148. Xmain()
  149. X{ char*const*p;char*q;static struct{const int a;int b;}c[2];
  150. X  --(c+1)->b;                 /* AIX 3.1.5 machines can't do this */
  151. X  p= &q;return 0;
  152. X}
  153. XHERE
  154. X
  155. Xecho 'Testing for const'
  156. Xif ${MAKE} _autotst.$1 >_autotst.rrr 2>&1 && test -f _autotst.$1
  157. Xthen
  158. X grepfor const '#define const'
  159. Xelse
  160. X echo '#define const' >>$ACONF
  161. Xfi
  162. X${RM} _autotst.$1
  163. X
  164. Xcat >_autotst.c <<HERE
  165. Xmain(){volatile int i;return(i=0);}
  166. XHERE
  167. X
  168. Xecho 'Testing for volatile'
  169. Xif ${MAKE} _autotst.$1 >$DEVNULL 2>&1 && test -f _autotst.$1
  170. Xthen
  171. X:
  172. Xelse
  173. X echo '#define volatile' >>$ACONF
  174. Xfi
  175. X${RM} _autotst.$1
  176. X
  177. Xcat >_autotst.c <<HERE
  178. X#include "includes.h"
  179. Xvoid*vvoid;
  180. Xmain(){int i;char*p="t";
  181. X {size_t vsize_t;i=vsize_t=1;}
  182. X {pid_t vpid_t;i=vpid_t=1;}
  183. X {time_t vtime_t;i=vtime_t=1;}
  184. X {mode_t vmode_t;i=vmode_t=1;}
  185. X {uid_t vuid_t;i=vuid_t=1;}
  186. X {gid_t vgid_t;i=vgid_t=1;}
  187. X vvoid=p;
  188. X return !vvoid;}
  189. XHERE
  190. X
  191. Xecho 'Testing for void*,size_t,pid_t,time_t,mode_t,uid_t,gid_t'
  192. X${MAKE} _autotst.$1 >_autotst.rrr 2>&1
  193. X${RM} _autotst.$1
  194. X
  195. Xgrepfor void '#define void char'
  196. Xgrepfor size_t 'typedef unsigned size_t;'
  197. Xgrepfor pid_t 'typedef int pid_t;'
  198. Xgrepfor time_t 'typedef long time_t;'
  199. Xgrepfor mode_t 'typedef int mode_t;'
  200. Xgrepfor uid_t 'typedef int uid_t;'
  201. Xgrepfor gid_t 'typedef int gid_t;'
  202. X
  203. Xcat >_autotst.c <<HERE
  204. X#include "includes.h"
  205. Xmain(){int i;i=1;
  206. X i+=WIFEXITED(i);
  207. X i+=WIFSTOPPED(i);
  208. X i+=WEXITSTATUS(i);
  209. X return i;}
  210. XHERE
  211. X
  212. Xecho 'Testing for WIFEXITED(), WIFSTOPPED() & WEXITSTATUS()'
  213. Xif ${MAKE} _autotst.$1 >_autotst.rrr 2>&1
  214. Xthen
  215. X   grepfor struct '#define WMACROS_NON_POSIX' ||
  216. X    grepfor union '#define WMACROS_NON_POSIX'
  217. Xelse
  218. X   echo '#define WMACROS_NON_POSIX' >>$ACONF
  219. Xfi
  220. X${RM} _autotst.$1
  221. X
  222. Xcat >_autotst.c <<HERE
  223. X#include "includes.h"
  224. Xmain(){char a[2];
  225. X endpwent();endgrent();memmove(a,"0",1);bcopy("0",a,1);strcspn(a,"0");
  226. X strtol("0",(char**)0,10);strchr("0",'0');strpbrk(a,"0");rename(a,"0");
  227. X opendir("0");
  228. X#ifndef NOuname
  229. X {struct utsname b;uname(&b);}
  230. X#endif
  231. X return 0;}
  232. XHERE
  233. X
  234. Xecho 'Testing for memmove, strchr, strpbrk, strcspn, strtol & opendir'
  235. Xif ${MAKE} _autotst.$1 >_autotst.rrr 2>&1
  236. Xthen
  237. X:
  238. Xelse
  239. X  echo 2>&1 "Whoeaaa!  There's something fishy going on here."
  240. X  echo 2>&1 "You have a look and see if you detect anything uncanny:"
  241. X  echo 2>&1 "-------------------------------------------------------"
  242. X  cat 2>&1 _autotst.rrr
  243. X  echo 2>&1 "-------------------------------------------------------"
  244. X  echo 2>&1 "I suggest you take a look at the definition of CFLAGS and CC"
  245. X  echo 2>&1 "in the Makefile before you try make again."
  246. X  exit 1
  247. Xfi
  248. X${MAKE} _autotst >_autotst.rrr 2>&1
  249. X${RM} _autotst _autotst.$1
  250. X
  251. Xgrepfor strcspn '#define NOstrcspn'
  252. Xgrepfor strpbrk '#define NOstrpbrk'
  253. Xgrepfor opendir "
  254. X#define NOopendir    /* the readdir library does not seem to be available */
  255. X            /* this will slightly affect the way a filenumber is */
  256. X            /* selected in MH-folders by procmail */
  257. X"
  258. Xgrepfor rename '#define NOrename'
  259. Xgrepfor strchr '#define strchr(s,c) index(s,c)'
  260. Xgrepfor uname "\
  261. X#define NOuname         \
  262. X/* the include files define it, the libraries don't */"
  263. Xgrepfor setpwent '#define setpwent()'
  264. Xgrepfor endpwent '#define endpwent()'
  265. Xgrepfor endgrent '#define endgrent()'
  266. Xgrepfor strtol '#define strtol(str,ptr,base) ((long)atoi(str))'
  267. Xgrepfor memmove '#define NOmemmove' &&
  268. Xif fgrep -e bcopy _autotst.rrr >$DEVNULL
  269. Xthen
  270. X echo '#define NObcopy' >>$ACONF
  271. X
  272. X echo 'Testing for brain damage'
  273. X cat >_autotst.c <<HERE
  274. X#include "includes.h"
  275. Xstruct tests{int a,b;};
  276. Xmain(){
  277. X return offsetof(struct tests,b);}
  278. XHERE
  279. X if ${MAKE} _autotst.$1 >$DEVNULL 2>&1
  280. X then
  281. X    :
  282. X else
  283. X    echo 'Yep, it is'            # ISC chokes on its own offsetof()
  284. X    echo '#define oBRAIN_DAMAGE' >>$ACONF
  285. X fi
  286. X ${RM} _autotst.$1
  287. X
  288. Xelse
  289. X
  290. X cat >_autotst.c <<HERE
  291. X#include "includes.h"
  292. X#define M256    256
  293. X#define F33    33
  294. Xmain(){int j=0,i=M256-1;static char a[M256];
  295. X do a[i]=i;while(i--);
  296. X bcopy(a+F33,a,M256-F33);bcopy(a,a+F33,M256-F33);i=F33-1;
  297. X do j|=a[i]!=(char)(i+F33);while(i--);i=M256-1;
  298. X do j|=a[i]!=(char)i;while(--i!=F33-1);return!j;}
  299. XHERE
  300. X
  301. X echo 'Testing for bcopy handling overlaps'
  302. X ${MAKE} _autotst >$DEVNULL 2>&1
  303. X
  304. X if _autotst
  305. X then
  306. X   echo 'Sorry, incompetent bcopy'
  307. X   echo '#define NObcopy' >>$ACONF
  308. X fi
  309. X ${RM} _autotst
  310. Xfi
  311. X
  312. Xfgrep -e LD_ /bin/ld >/dev/null 2>&1 && echo "#define LD_ENV_FIX" >>$ACONF
  313. X
  314. Xcat >_autotst.c <<HERE
  315. X#include "includes.h"
  316. Xmain(){unsigned long s=(size_t)~0;int i;
  317. X for(i=1;s>>=1;++i);
  318. X if(i<=16)
  319. X    puts("#define SMALLHEAP");
  320. X return 0;}
  321. XHERE
  322. X
  323. Xecho 'Determining the most applicable block size'
  324. X
  325. X${MAKE} _autotst >$DEVNULL 2>&1
  326. X_autotst >>$ACONF
  327. X${RM} _autotst
  328. X
  329. Xif test -d /usr/spool/mail
  330. Xthen
  331. X echo '#define SYSTEM_MAILBOX "/usr/spool/mail/$USER"' >>$ACONF
  332. Xelif test -d /usr/mail
  333. Xthen
  334. X echo '#define SYSTEM_MAILBOX "/usr/mail/$USER"' >>$ACONF
  335. Xelse
  336. X echo '#define SYSTEM_MAILBOX "$HOME/.mail"' >>$ACONF
  337. X echo Could not find the system-mailbox directory, supplied substitute
  338. Xfi
  339. X
  340. Xcat >lookfor <<HERE
  341. Xfor a in /usr/lib /lib /usr/etc /etc /usr/bin /bin /usr/local/bin /usr/lbin \
  342. X /usr/local/lib /usr/local /usr/.lib
  343. Xdo
  344. X if test -f "\$a/\$1"
  345. X then
  346. X    echo "#define SENDMAIL \"\$a/\$1\"" >>$ACONF
  347. X    exit 0
  348. X fi
  349. Xdone
  350. Xexit 1
  351. XHERE
  352. Xchmod 0755 lookfor
  353. X
  354. Xif lookfor sendmail || lookfor smail
  355. Xthen
  356. X:
  357. Xelse
  358. X echo 'Could not find any mailer.  It should be a mailer accepting at least'
  359. X echo "one plain destination address as it's only argument (any sendmail"
  360. X echo 'compatible mailer will do), and the mail-to-be-sent on stdin.'
  361. X echo 'What is your mailer called?  (You can override this in config.h)'
  362. X read a
  363. X echo "#define SENDMAIL \"$a\"" >>$ACONF
  364. Xfi
  365. X
  366. X${RM} _autotst* lookfor grepfor
  367. X
  368. Xecho -----------------------------autoconf.h-----------------------------------
  369. Xcat $ACONF >&2
  370. Xecho --------------------------------------------------------------------------
  371. END_OF_FILE
  372. if test 9448 -ne `wc -c <'procmail/autoconf'`; then
  373.     echo shar: \"'procmail/autoconf'\" unpacked with wrong size!
  374. fi
  375. # end of 'procmail/autoconf'
  376. fi
  377. if test -f 'procmail/config.h' -a "${1}" != "-c" ; then 
  378.   echo shar: Will not clobber existing file \"'procmail/config.h'\"
  379. else
  380. echo shar: Extracting \"'procmail/config.h'\" \(9697 characters\)
  381. sed "s/^X//" >'procmail/config.h' <<'END_OF_FILE'
  382. X/*$Id: config.h,v 2.22 1992/06/30 17:43:44 berg Rel $*/
  383. X
  384. X/*#define KERNEL_LOCKS    /* uncomment if you want to use kernel locks on file
  385. X               descriptors (not recommended if your system uses a
  386. X    buggy lockd across a net, or if your mailer uses tmp files in updating
  387. X    mailboxes and moves them into place); only advisable if your mailreader
  388. X    can't be convinced to use "dotfile"-locks */
  389. X
  390. X/*#define sMAILBOX_SEPARATOR    "\1\1\1\1\n"    /* sTART- and eNDing separ.  */
  391. X/*#define eMAILBOX_SEPARATOR    "\1\1\1\1\n"    /* uncomment (one or both)
  392. X                           if your mail system uses
  393. X    nonstandard mail separators (non sendmail or smail compatible mailers
  394. X    like MMDF), if yours is even different, uncomment and change the
  395. X    value of course */
  396. X
  397. X/* KEEPENV and PRESTENV should be defined as a comma-separated null-terminated
  398. X   list of strings */
  399. X
  400. X/* every environment variable appearing in KEEPENV will not be thrown away
  401. X * upon startup of procmail, e.g. you could define KEEPENV as follows:
  402. X * #define KEEPENV    {"TZ","LANG",0}
  403. X */
  404. X#define KEEPENV        {"TZ",0}
  405. X
  406. X/* every environment variable appearing in PRESTENV will be set or wiped
  407. X * out of the environment (variables without an '=' sign will be thrown
  408. X * out), e.g. you could define PRESTENV as follows:
  409. X * #define PRESTENV    {"IFS","PATH=$HOME/bin:/bin:/usr/bin",0}
  410. X * any side effects (like setting the umask after an assignment to UMASK) will
  411. X * *not* take place
  412. X */
  413. X#define PRESTENV    {"IFS",0}
  414. X
  415. X/*****************************************************************
  416. X * Only edit below this line if you have edited this file before *
  417. X *****************************************************************/
  418. X
  419. X/* every user & group appearing in TRUSTED_IDS is allowed to use the -f option
  420. X   if the list is empty (just a terminating 0), everyone can use it
  421. X   TRUSTED_IDS should be defined as a comma-separated null-terminated
  422. X   list of strings */
  423. X
  424. X#define TRUSTED_IDS    {"root","daemon","uucp","mail","x400",0}
  425. X
  426. X/*#define NO_USER_TO_LOWERCASE_HACK    /* uncomment if your getpwnam() is
  427. X                       case insensitive or if procmail
  428. X    will always be supplied with the correct case in the explicit
  429. X    delivery mode argument */
  430. X
  431. X/*#define NO_NFS_ATIME_HACK    /* uncomment if you're definitely not using
  432. X                   NFS mounted filesystems and can't afford
  433. X    procmail to sleep for 1 sec. before writing a mailbox */
  434. X
  435. X/*#define SYSTEM_MBOX    "$HOME/.mbox"    /* uncomment and/or change if the
  436. X                       preset default mailbox is *not*
  437. X    either /usr/spool/mail/$USER or /usr/mail/$USER (it will supersede
  438. X    the value of SYSTEM_MAILBOX) */
  439. X
  440. X/*#define DEFsendmail    "/bin/mail"    /* uncomment and/or change if the
  441. X                       preset default SENDMAIL is not
  442. X    suitable */
  443. X
  444. X/*#define console    "/dev/console"    /* uncomment if you want procmail to
  445. X                       use the console (or any other
  446. X    terminal) to print any error messages that could not be dumped in the
  447. X    "logfile".  (Only recommended for debugging purposes, if you have
  448. X    trouble creating a "logfile") */
  449. X
  450. X/************************************************************************
  451. X * Only edit below this line if you *think* you know what you are doing *
  452. X ************************************************************************/
  453. X
  454. X#define NOBODY_uid    0xfffe          /* default uid when no valid recipient */
  455. X#define NOBODY_gid    0xfffe          /* default gid when no valid recipient */
  456. X#define ROOT_uid    0
  457. X
  458. X#define INIT_UMASK    (S_IRWXG|S_IRWXO)               /* == 077 */
  459. X#define NORMperm    (S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH)
  460. X         /* == 0666, normal mode bits used to create files, before umask */
  461. X#define LOCKperm    0      /* mode bits used while creating lockfiles */
  462. X#define MAX_LOCK_SIZE    0      /* lockfiles are expected not to be longer */
  463. X#ifndef SMALLHEAP
  464. X#define DEFlinebuf    2048         /* default max expanded line length */
  465. X#define BLKSIZ        16384          /* blocksize while reading/writing */
  466. X#define STDBUF        1024             /* blocksize for emulated stdio */
  467. X#else           /* and some lower defaults for the unfortunate amongst us */
  468. X#define DEFlinebuf    512
  469. X#define BLKSIZ        1024
  470. X#define STDBUF        128
  471. X#endif /* SMALLHEAP */
  472. X#define HOSTNAMElen    9      /* nr of significant chararacters for HOST */
  473. X#define BOGUSprefix    "BOGUS."         /* prepended to bogus mailboxes */
  474. X#define PROCMAILRC    ".procmailrc"
  475. X#define DEFsuspend    16         /* multi-purpose 'idle loop' period */
  476. X#define DEFlocksleep    8
  477. X#define TOkey        "^TO"
  478. X#define TOsubstitute    "^(To|Cc|Apparently-To):.*"
  479. X#define DEFshellmetas    "&|<>~;?*[]="            /* never put '$' in here */
  480. X#define DEFmaildir    "$HOME"
  481. X#define DEFdefault    "$ORGMAIL"
  482. X#define DEFdefaultlock    "LOCKFILE=$DEFAULT$LOCKEXT"
  483. X#define DEFmsgprefix    "msg."
  484. X#define DEFlockext    ".lock"
  485. X#define DEFshellflags    "-c"
  486. X#define DEFlocktimeout    3600                 /* defaults to one hour */
  487. X#define DEFtimeout    (DEFlocktimeout-60)       /* 60 seconds to clean up */
  488. X#define DEFnoresretry    4      /* default nr of retries if no resources left */
  489. X
  490. X#define BinSh        "/bin/sh"
  491. X#define Tmp        "/tmp"
  492. X#define DEBUGPREFIX    ':'             /* debug prefix for LOGFILE */
  493. X#define DevNull        "/dev/null"
  494. X#define chCURDIR    '.'                /* the current directory */
  495. X#define DIRSEP        "/"         /* directory separator symbols, the */
  496. X                   /* last one should be the most common one */
  497. X
  498. X#define EOFName        " \t\n#`'\");"
  499. X
  500. X#define HELPOPT1    'h'         /* options to get command line help */
  501. X#define HELPOPT2    '?'
  502. X
  503. X#define VERSIONOPT    'v'            /* option to display version */
  504. X#define PRESERVOPT    'p'                 /* preserve environment */
  505. X#define TEMPFAILOPT    't'              /* return EX_TEMPFAIL on error */
  506. X#define FROMWHOPT    'f'               /* set name on From_ line */
  507. X#define ALTFROMWHOPT    'r'        /* alternate and obsolete form of -f */
  508. X#define DELIVEROPT    'd'          /* deliver mail to named recipient */
  509. X#define PM_USAGE    \
  510. X "Usage: procmail [-vpt] [-f fromwhom] [parameter=value | rcfile] ...\
  511. X\n   Or: procmail [-vpt] [-f fromwhom] -d recipient ...\n"
  512. X#define PM_HELP        \
  513. X "\t-v\t\tdisplay the version number and exit\
  514. X\n\t-p\t\tpreserve (most of) the environment upon startup\
  515. X\n\t-t\t\tfail softly if mail is undeliverable\
  516. X\n\t-f fromwhom\t(re)generate the leading 'From ' line\
  517. X\n\t-d recipient\texplicit delivery mode\n"
  518. X#define PM_QREFERENCE    \
  519. X "\nRecipe flags quick reference:\
  520. X\n\tH\tegrep the header (default)\
  521. X\n\tB\tegrep the body\
  522. X\n\tD\tdistinguish case\
  523. X\n\tA\talso execute this recipe if the common condition matched\
  524. X\n\ta\tsame as 'A', but only if the previous recipe was succesful\
  525. X\n\th\tfeed the header to the pipe (default)\
  526. X\n\tb\tfeed the body to the pipe (default)\
  527. X\n\tf\tfilter\
  528. X\n\tc\tcontinue with the next recipe in any case\
  529. X\n\tw\twait for a filter or program\
  530. X\n\tW\tsame as 'w', but suppresses 'Program failure' messages\
  531. X\n\ti\tignore write errors\n"
  532. X
  533. X#define MINlinebuf    128    /* minimal LINEBUF length (don't change this) */
  534. X#define FROM_EXPR    "\nFrom "
  535. X#define FROM        "From "
  536. X#define NSUBJECT    "^Subject:.*$"
  537. X#define MAXSUBJECTSHOW    78
  538. X#define FOLDER        "  Folder: "
  539. X#define LENtSTOP    9 /* tab stop at which message length will be logged */
  540. X
  541. X#define TABCHAR        "\t"
  542. X#define TABWIDTH    8
  543. X
  544. X#define RECFLAGS    "HBDAahbfcwWi"
  545. X#define HEAD_GREP     0
  546. X#define BODY_GREP      1
  547. X#define DISTINGUISH_CASE   2
  548. X#define ALSO_NEXT_RECIPE    3
  549. X#define ALSO_N_IF_SUCC         4
  550. X#define PASS_HEAD          5
  551. X#define PASS_BODY           6
  552. X#define FILTER            7
  553. X#define CONTINUE         8
  554. X#define WAIT_EXIT          9
  555. X#define WAIT_EXIT_QUIET           10
  556. X#define IGNORE_WRITERR            11
  557. X
  558. X#define UNIQ_PREFIX    '_'      /* prepended to temporary unique filenames */
  559. X#define ESCAP        '>'
  560. X
  561. X        /* some formail-specific configuration options: */
  562. X
  563. X#define UNKNOWN        "foo@bar"      /* formail default originator name */
  564. X#define OLD_PREFIX    "Old-"             /* formail field-Old-prefix */
  565. X
  566. X#define FM_SKIP        '+'              /* skip the first nnn messages */
  567. X#define FM_TOTAL    '-'        /* only spit out a total of nnn messages */
  568. X#define FM_BOGUS    'b'             /* leave bogus Froms intact */
  569. X#define FM_FORCE    'f'   /* force formail to accept an arbitrary format */
  570. X#define FM_REPLY    'r'            /* generate an auto-reply header */
  571. X#define FM_KEEPB    'k'           /* keep the header, when replying */
  572. X#define FM_TRUST    't'    /* trust the sender to supply a valid header */
  573. X#define FM_SPLIT    's'                      /* split it up */
  574. X#define FM_NOWAIT    'n'              /* don't wait for the programs */
  575. X#define FM_EVERY    'e'    /* don't require empty lines leading headers */
  576. X#define FM_MINFIELDS    'm'    /* the number of fields that have to be found */
  577. X#define DEFminfields    2        /* before a header is recognised as such */
  578. X#define FM_DIGEST    'd'                 /* split up digests */
  579. X#define FM_QUIET    'q'            /* ignore write errors on stdout */
  580. X#define FM_EXTRACT    'x'               /* extract field contents */
  581. X#define FM_ADD_IFNOT    'a'         /* add a field if not already there */
  582. X#define FM_ADD_ALWAYS    'A'               /* add this field in any case */
  583. X#define FM_REN_INSERT    'i'            /* rename and insert a field */
  584. X#define FM_DEL_INSERT    'I'            /* delete and insert a field */
  585. X#define FM_USAGE    "Usage: \
  586. Xformail [+nn] [-nn] [-bfrktnedq] [-m nn] [-xaAiI field] [-s prg arg ...]\n"
  587. X#define FM_HELP        \
  588. X "\t-b\tdon't escape bogus mailbox headers\
  589. X\n\t-f\tforce formail to pass along any non-mailbox format\
  590. X\n\t-r\tgenerate an auto-reply header, preserve fields with -i\
  591. X\n\t-k\ton auto-reply keep the body, prevent escaping with -b\
  592. X\n\t-t\ttrust the sender for his return address\
  593. X\n\t-q\tbe quiet about write errors on stdout\
  594. X\n\t-s prg arg\tsplit the mail, startup prg for every message\
  595. X\n\t-n\tdon't wait for every prg while splitting\
  596. X\n\t-e\tdon't require empty lines to preceed a header\
  597. X\n\t-d\taccept digest format\
  598. X\n\t-m nn\tmin fields threshold (default 2) for start of message\
  599. X\n\t+nn\tskip the first nn messages while splitting\
  600. X\n\t-nn\toutput at most nn messages while splitting\
  601. X\n\t-x field\textract\
  602. X\n\t-a field\tadd if not present\
  603. X\n\t-A field\tadd in any case\
  604. X\n\t-i field\trename and insert\
  605. X\n\t-I field\tdelete and insert\n"
  606. END_OF_FILE
  607. if test 9697 -ne `wc -c <'procmail/config.h'`; then
  608.     echo shar: \"'procmail/config.h'\" unpacked with wrong size!
  609. fi
  610. # end of 'procmail/config.h'
  611. fi
  612. if test -f 'procmail/examples/3procmailrc' -a "${1}" != "-c" ; then 
  613.   echo shar: Will not clobber existing file \"'procmail/examples/3procmailrc'\"
  614. else
  615. echo shar: Extracting \"'procmail/examples/3procmailrc'\" \(1517 characters\)
  616. sed "s/^X//" >'procmail/examples/3procmailrc' <<'END_OF_FILE'
  617. X# Please check if all the paths in PATH are reachable, remove the ones that
  618. X# are not.
  619. X
  620. XPATH=$HOME/bin:/usr/bin:/global/bin:/usr/ucb:/bin:/usr/local/bin:
  621. XMAILDIR =    $HOME/Mail    # You'd better make sure it exists
  622. XDEFAULT =    $MAILDIR/mbox
  623. XLOGFILE =    $MAILDIR/from
  624. XLOCKFILE=    $HOME/.lockmail
  625. X
  626. X            # This will create a local lockfile named todd.lock
  627. X::            # *if* the condition matches
  628. X^From.*thf
  629. Xtodd
  630. X
  631. XLOCKFILE=$MAILDIR/whatever    # This will remove the global lockfile
  632. X                # $HOME/.lockmail and the new lockfile
  633. X                # will be $MAILDIR/whatever
  634. X
  635. X
  636. X                # The next recipe will
  637. X                # filter out all messages from "at"
  638. X                # jobs and will put them in a terse format
  639. X                # (only the date and the body) in
  640. X                # a file called $MAILDIR/atjunk
  641. X: 2 fh
  642. X^From root
  643. X^Subject: Output from "at" job
  644. X|egrep "^Date:"
  645. X                # The next recipe will only be used if
  646. X                # the previous one matched
  647. X:A
  648. Xatjunk
  649. X
  650. X
  651. X
  652. XMAILDIR=$HOME/News    # This will change the current directory
  653. X
  654. X
  655. X            # The next recipe will create a local lockfile
  656. X            # named $HOME/News/dustbin.lock (*if* the condition
  657. X            # matches), and will feed the body of the message
  658. X            # through `sort` (sorry, couldn't come up with anything
  659. X            # better :-), after which the result will be
  660. X            # appended to $HOME/News/dustbin
  661. X:b:
  662. X^Subject:.*rubbish
  663. X|sort >>dustbin
  664. X
  665. X            # The next recipe will use the play directory as a MH
  666. X            # folder (of course you need MH to read the mail then)
  667. X:
  668. X^Subject:.*games
  669. Xgames/.
  670. X
  671. X# Anything not delivered by now will go to $HOME/Mail/mbox
  672. X# Using LOCKFILE=$HOME/Mail/mbox.lock
  673. END_OF_FILE
  674. if test 1517 -ne `wc -c <'procmail/examples/3procmailrc'`; then
  675.     echo shar: \"'procmail/examples/3procmailrc'\" unpacked with wrong size!
  676. fi
  677. # end of 'procmail/examples/3procmailrc'
  678. fi
  679. if test -f 'procmail/examples/mailinglist' -a "${1}" != "-c" ; then 
  680.   echo shar: Will not clobber existing file \"'procmail/examples/mailinglist'\"
  681. else
  682. echo shar: Extracting \"'procmail/examples/mailinglist'\" \(11170 characters\)
  683. sed "s/^X//" >'procmail/examples/mailinglist' <<'END_OF_FILE'
  684. X$Id: mailinglist,v 2.6 1992/04/09 16:17:41 berg Rel $
  685. X
  686. X            How to set up mailing lists
  687. X            ---------------------------
  688. X
  689. X        Written by Stephen R. van den Berg.
  690. X                    berg@messua.informatik.rwth-aachen.de
  691. X                    berg@physik.tu-muenchen.de
  692. X
  693. XThis document mainly describes a sendmail environment, much of it applies
  694. Xto non-sendmail mail agents as well.
  695. X
  696. X
  697. XContents:
  698. X---------    1. Intro
  699. X        2. Bouncing mail
  700. X        3. The disadvantages
  701. X        4. How to circumvent these disadvantages
  702. X        5. Why use procmail to filter the mailinglist mail?
  703. X        6. How do I use procmail to filter the mailinglist mail?
  704. X        7. Now, what does the above all do?
  705. X        8. The result of this exercise
  706. X
  707. X1. Intro
  708. X   -----
  709. X
  710. XThe simplest and most direct way to do it is by insert a line in
  711. Xthe /usr/lib/aliases file looking like:
  712. X
  713. Xmylist: fred,john, wilma, barney@bedrock, pebbles
  714. X
  715. XNow all the mail arriving at your machine for "mylist" (either local or
  716. Xmylist@your.domain) will be automatically forwarded to all the mentioned
  717. Xaddresses (fred, john, etc.).
  718. X
  719. XThe address mylist@your.domain is intended for submissions to the list that
  720. Xare supposed to be forwarded to all the subscribers.  For the administrative
  721. Xtasks like removals from the list, new subscribtions to the list, or address
  722. Xchanges of subscribers one should create a second entry in the /usr/lib/aliases
  723. Xfile:
  724. X
  725. Xmylist-request: your_login_name@your.domain
  726. X
  727. X
  728. X2. Bouncing mail
  729. X   -------------
  730. X
  731. XIn order to deal with bouncing mail gracefully, an extra precaution should
  732. Xbe taken.  If for example mail to wilma bounces (user non-existent, mail
  733. Xfilesystem full, etc.), it will bounce back to the original sender.
  734. XNow, the only person that should be concerned with distribution failures
  735. Xshould be the mylist-request holder.  Therefore you should be using a
  736. Xsendmail special alias like:
  737. X
  738. Xowner-mylist: mylist-request@your.domain
  739. X
  740. XThis way local mail will bounce back to mylist-request@your.domain.
  741. X
  742. X
  743. X3. The disadvantages
  744. X   -----------------
  745. X
  746. XIf you are using the above methods, some obvious disadvantages come to mind
  747. Xhowever:
  748. X
  749. Xa. The subscriber list cannot exceed 1000 bytes (on most sendmails).
  750. Xb. The subscriber list cannot be changed on-the-fly (/usr/lib/aliases needs
  751. X   to be edited, and newaliases has to be run).
  752. Xc. People cannot be prevented from submitting messages like "Please remove
  753. X   me from this mailinglist" to mylist (and thereby annoying all subscribers).
  754. Xd. People cannot be guarded from themselves in case they insert
  755. X   "Return-Receipt-To:" fields in their headers (if they are particularly
  756. X   unlucky, they will receive an acknowledge mail from *every* subscriber's
  757. X   sendmail).
  758. Xe. People including "Errors-To:" or "Sender:" fields can cause the bounce
  759. X   messages to bypass owner-mylist anyway.
  760. Xf. There is no way of limiting the number of submitters, i.e. every person
  761. X   who knows the name of the mailing list and who can send mail to your.domain
  762. X   is able to submit messages to the list.  This means, for example, that you
  763. X   cannot limit a mailing list to local users (i.e. only local users can
  764. X   submit).
  765. Xg. You are unable to insert a "Reply-To: mylist@your.domain" in case you
  766. X   would want to (this makes replying to the list easier).
  767. X
  768. X
  769. X4. How to circumvent these disadvantages
  770. X  -------------------------------------
  771. X
  772. Xa. Can be circumvented by using nested aliases like:
  773. X    mylist: mylist1, mylist2
  774. X    mylist1: fred,john
  775. X    mylist2: wilma,barney@bedrock,pebbles
  776. X   This can however, become extremely messy to maintain.
  777. X
  778. Xb. This can partly be avoided if you use aliases like:
  779. X    mylist: :include:/path/to/the/memberfile
  780. X   The memberfile should contain:
  781. X    fred,john,wilma,barney@bedrock,pebbles
  782. X   You cannot avoid using newaliases however, and it *will* get extremely messy
  783. X   if you have to start using nested aliases.
  784. X
  785. Xc. Can only be taken care of by using a mailfilter like procmail.
  786. X
  787. Xd. Can only be taken care of by using a mailfilter like procmail.
  788. X
  789. Xe. Can only be taken care of by using a mailfilter like procmail.
  790. X
  791. Xf. Can only be taken care of by using a mailfilter like procmail.
  792. X
  793. Xh. Can only be taken care of by using a mailfilter like procmail.
  794. X
  795. X
  796. X5. Why use procmail to filter the mailinglist mail?
  797. X   ------------------------------------------------
  798. X
  799. XInstead of using a mailfilter you could also take care of most of the problems
  800. Xthree till seven by editing the sendmail.cf file.  I would strongly recommend
  801. Xagainst this approach however, since this will be too much of a customising
  802. Xoperation and surely will not be a trivial task (in all cases).     As a general
  803. Xrule: don't mess with a sendmail.cf file once it is working :-).
  804. X
  805. XNow, you could, instead of procmail, simply use immediate VNIX commands
  806. Xlike grep, sed, awk to do the mail filtering.  Again, there are some obvious
  807. Xdisadvantages with this approach:
  808. X
  809. XA. In case any system resources go out (no more file descriptors, no more
  810. X   swap space, process table full, file system full (for temporary files))
  811. X   your awk or shell script will fail generously (i.e. several bad things
  812. X   could happen: mail munged, truncated, lost, hanging awk or sh programs,
  813. X   etc., you get the picture).
  814. X
  815. XB. All mail headers (including From: and Reply-To:) could very well be
  816. X   multi-line headers; it will be very difficult to make it understandable
  817. X   to awk that somehow the header line could continue on the next line
  818. X   (in case you want to remove a header, or do some complicated substitution).
  819. X
  820. XC. Another hairy problem will be determining the end of the header, of course
  821. X   that is solvable, but you have to make some extra precautions in your
  822. X   awk script to ensure that any substitutions/changes will not occur in
  823. X   the body of the message.
  824. X
  825. XProcmail does not *directly* allow you to change any headers, but that
  826. Xfeature is not really necessary since you can tell procmail to send ONLY the
  827. Xheader through some filter of your choice.
  828. X
  829. XTo comment on the previously mentioned three disadvantages:
  830. X
  831. XA. procmail takes care of that.     Should the filter have problems anyway,
  832. X   procmail will graciously notice that the filter was in some kind of
  833. X   trouble, and will try something else with the original unmunged mail
  834. X   (you can specify what it should do of course, obvious choices: try
  835. X   the same filter again, drop the mail in a file and send you a notice,
  836. X   forward the mail to you instead (unfiltered), etc.)
  837. X
  838. XB. procmail will concatenate any headers that were continued according to
  839. X   the RCF 822 recommendations, i.e. your filters will see one line per header.
  840. X
  841. XC. procmail can be told to send the header, the body or both through the
  842. X   filter, hence your filter need not watch out to avoid doing any
  843. X   substitutions in the body, and the filter can therefore be a lot simpler.
  844. X
  845. XProcmail has some additional advantages too:
  846. X
  847. X -- It will probably all go a bit faster, since only the header of the mail
  848. X    is being piped through the filter.    Also, procmail reads in the mail in
  849. X    16KB chunks, not line by line as sed does.
  850. X
  851. X -- You could use procmail to filter out any messages to the normal mailing
  852. X    list that should have gone to the mylist-request and remail them to
  853. X    mylist-request.
  854. X
  855. XWell, anyway, as you see, procmail does not give you everything you would want,
  856. Xbut this was intentional in accordance to the true VNIX spirit (modularity).
  857. XWhat procmail does provide is a *very* reliable hook (you might say it
  858. Xprovides an anchor :-) for any mail processing you might do.  For the more
  859. Xcomplex things you still have to use shell scripts or call other programs
  860. Xfrom within procmail, but then again, that saves you from learning any
  861. Xparticular syntax procmail would have had to do the same.
  862. X
  863. XAs it happens, the accompanying formail program is able to cater to most
  864. X(if not all) of your needs regarding mail munging.
  865. X
  866. XIf, on the other hand, you want to do more complex things like moderated
  867. Xmailing lists with several moderators, etc., if would suggest you take
  868. Xa look at the more complex/specialised mail-server packages like:
  869. Xlistserv available on cs.bu.edu, author: tasos@cs.bu.edu
  870. XOf course, most of what these packages can do, can be done with procmail as
  871. Xwell; it is just that you might be forced to write some additional shell
  872. Xscripts/programs to accomplish the same.
  873. X
  874. X
  875. X6. How do I use procmail to filter the mailinglist mail?
  876. X   -----------------------------------------------------
  877. X
  878. XFirst you have to create these two entries in your /usr/lib/aliases file of
  879. Xmachine "your.domain" (the mylist: line should be typed in as one long line):
  880. X
  881. Xmylist: "|IFS=' ';exec /usr/local/bin/procmail /some/path/listrc subscribers=/some/path/memberlist list=mylist@your.domain listreq=mylist-request@your.domain"
  882. Xmylist-request: your_login_name@your.domain
  883. Xowner-mylist: mylist-request
  884. X
  885. XCreate a file named /some/path/memberlist which contains the names of the
  886. Xsubscribers separated by whitespace (blanks, tabs or newlines) like:
  887. X
  888. X fred john  wilma  barney@bedrock  pebbles
  889. X
  890. XThe /some/path/listrc file should look like the sample listrc file
  891. Xsupplied in this directory.  This listrc file need only be present once,
  892. Xit will cater for all the mailinglists you'd like to create.
  893. X
  894. X
  895. X7. Now, what does the above all do?
  896. X   --------------------------------
  897. X
  898. XIf mail arrives at mylist, first of all procmail will be started using
  899. X/some/path/listrc as the rcfile.  Then it will grep the header to check if
  900. Xit could be a bounced message after all (from postmaster or mailer-daemon),
  901. Xor if it probably is a request message.     If neither applies, procmail will
  902. Xfilter just the header of the message through formail.
  903. X
  904. Xformail will remove any "Return-Receipt-To:" fields, and will provide plain
  905. Xsubstitutes for "Errors-To:" and "Sender:".  Then it will look for
  906. Xany "Reply-To:" fields which are already in the header and rewrite them
  907. Xas "Old-Reply-To:";  after having done this it will add your "Reply-To:"
  908. Xfield.    BTW, the "Return-Receipt-To:" and "Errors-To:" fields are not
  909. Xrecommended by the RFC-822, they are however commonly supported by most
  910. Xsendmails;  if they are not supported however, they won't hurt, they will
  911. Xsimply be ignored.
  912. X
  913. XThen, the mail is piped into $SENDMAIL which receives, as command line
  914. Xarguments, the addresses of all subscribers.  The option -f will only
  915. Xtake effect if sendmail is running under daemon privileges; this only
  916. Xoccurs if the sender of the mail is *not* a local user; if the sender
  917. Xis a local user, then sendmail (and procmail) runs as the local user.
  918. X
  919. X*********************************** WARNING **********************************
  920. X*                                         *
  921. X* For this reason it might be wise to allow writing of the memberlist file   *
  922. X* only (to a list maintainer), keep the listrc file under *root supervision* *
  923. X* (i.e. owned by a very reliable person (e.g. root), world readable, but NOT *
  924. X* world writeable).                                 *
  925. X*                                         *
  926. X******************************************************************************
  927. X
  928. X
  929. X8. The result of this exercise
  930. X   ---------------------------
  931. X
  932. XAs you can see, we have addressed and solved every single one of the original
  933. Xseven problems (well, ok, except problem f, that one is left as an excercise
  934. Xto the reader; shouldn't be too difficult).
  935. X
  936. X
  937. XP.S. Any suggestions/corrections/improvements on this document are welcome.
  938. END_OF_FILE
  939. if test 11170 -ne `wc -c <'procmail/examples/mailinglist'`; then
  940.     echo shar: \"'procmail/examples/mailinglist'\" unpacked with wrong size!
  941. fi
  942. # end of 'procmail/examples/mailinglist'
  943. fi
  944. if test -f 'procmail/goodies.c' -a "${1}" != "-c" ; then 
  945.   echo shar: Will not clobber existing file \"'procmail/goodies.c'\"
  946. else
  947. echo shar: Extracting \"'procmail/goodies.c'\" \(9223 characters\)
  948. sed "s/^X//" >'procmail/goodies.c' <<'END_OF_FILE'
  949. X/************************************************************************
  950. X *    Collection of library-worthy routines                *
  951. X *                                    *
  952. X *    Copyright (c) 1990-1992, S.R. van den Berg, The Netherlands    *
  953. X *    The sources can be freely copied for non-commercial use.    *
  954. X *    #include "README"                        *
  955. X *                                    *
  956. X ************************************************************************/
  957. X#ifdef RCS
  958. Xstatic char rcsid[]="$Id: goodies.c,v 2.17 1992/06/03 13:17:41 berg Rel $";
  959. X#endif
  960. X#include "config.h"
  961. X#include "procmail.h"
  962. X#include "shell.h"
  963. X
  964. X#define NOTHING_YET    (-1)    /* readparse understands a very complete    */
  965. X#define SKIPPING_SPACE    0    /* subset of the standard /bin/sh syntax    */
  966. X#define NORMAL_TEXT    1    /* that includes single-, double- and back- */
  967. X#define DOUBLE_QUOTED    2    /* quotes, backslashes and $subtitutions    */
  968. X#define SINGLE_QUOTED    3
  969. X
  970. X#define fgetc() (*fpgetc)()       /* some compilers previously choked on it */
  971. X
  972. X/* sarg==0 : normal parsing, split up arguments like in /bin/sh
  973. X * sarg==1 : environment assignment parsing, parse up till first whitespace
  974. X * sarg==2 : normal parsing, split up arguments by single spaces
  975. X */
  976. Xreadparse(p,fpgetc,sarg)register char*p;int(*const fpgetc)();const int sarg;
  977. X{ static i;int got;char*startb;
  978. X  for(got=NOTHING_YET;;)            /* buf2 is used as scratch space */
  979. Xloop:
  980. X   { i=fgetc();
  981. X     if(buf+linebuf-3<p)        /* doesn't catch everything, just a hint */
  982. X      { log("Exceeded LINEBUF\n");p=buf+linebuf-3;goto ready;
  983. X      }
  984. Xnewchar:
  985. X     switch(i)
  986. X      { case EOF:    /* check sarg too to prevent warnings in the recipe- */
  987. X       if(sarg!=2&&got>NORMAL_TEXT)         /* condition expansion code */
  988. Xearly_eof:    log(unexpeof);
  989. Xready:       if(got!=SKIPPING_SPACE||sarg)  /* not terminated yet or sarg==2 ? */
  990. X          *p++='\0';
  991. X       *p=TMNATE;return;
  992. X    case '\\':
  993. X       if(got==SINGLE_QUOTED)
  994. X          break;
  995. X       switch(i=fgetc())
  996. X        { case EOF:goto early_eof;              /* can't quote EOF */
  997. X          case '\n':continue;            /* concatenate lines */
  998. X          case '#':
  999. X         if(got>SKIPPING_SPACE) /* escaped comment at start of word? */
  1000. X            goto noesc;            /* apparently not, literally */
  1001. X          case ' ':case '\t':case '\'':
  1002. X         if(got==DOUBLE_QUOTED)
  1003. X            goto noesc;
  1004. X          case '"':case '\\':case '$':case '`':goto nodelim;
  1005. X        }
  1006. X       if(got>NORMAL_TEXT)
  1007. Xnoesc:          *p++='\\';        /* nothing to escape, just echo both */
  1008. X       break;
  1009. X    case '`':
  1010. X       if(got==SINGLE_QUOTED)
  1011. X          goto nodelim;
  1012. X       for(startb=p;;)                   /* mark your position */
  1013. X        { switch(i=fgetc())             /* copy till next backquote */
  1014. X           { case '\\':
  1015. X            switch(i=fgetc())
  1016. X             { case EOF:log(unexpeof);goto forcebquote;
  1017. X               case '\n':continue;
  1018. X               case '"':
  1019. X              if(got!=DOUBLE_QUOTED)
  1020. X                 break;
  1021. X               case '\\':case '$':case '`':goto escaped;
  1022. X             }
  1023. X            *p++='\\';break;
  1024. X         case '"':
  1025. X            if(got!=DOUBLE_QUOTED)    /* missing closing backquote? */
  1026. X               break;
  1027. Xforcebquote:     case EOF:case '`':
  1028. X          { int osh=sh;
  1029. X            *p='\0';
  1030. X            if(!(sh=!!strpbrk(startb,tgetenv(shellmetas))))
  1031. X             { const char*save=sgetcp;
  1032. X               sgetcp=p=tstrdup(startb);readparse(startb,sgetc,0);
  1033. X               free(p);sgetcp=save;               /* chopped up */
  1034. X             }            /* drop source buffer, read from program */
  1035. X            startb=fromprog(p=startb,startb);sh=osh;   /* restore sh */
  1036. X            if(!sarg&&got!=DOUBLE_QUOTED)
  1037. X             { i=0;startb=p;goto simplsplit;          /* split it up */
  1038. X             }
  1039. X            if(i=='"'||got<=SKIPPING_SPACE)   /* missing closing ` ? */
  1040. X               got=NORMAL_TEXT;                 /* or sarg!=0 ? */
  1041. X            p=startb;goto loop;
  1042. X          }
  1043. X         case '\n':i=';';           /* newlines separate commands */
  1044. X           }
  1045. Xescaped:      *p++=i;
  1046. X        }
  1047. X    case '"':
  1048. X       switch(got)
  1049. X        { case DOUBLE_QUOTED:got=NORMAL_TEXT;continue;    /* closing " */
  1050. X          case SINGLE_QUOTED:goto nodelim;
  1051. X        }
  1052. X       got=DOUBLE_QUOTED;continue;                /* opening " */
  1053. X    case '\'':
  1054. X       switch(got)
  1055. X        { case DOUBLE_QUOTED:goto nodelim;
  1056. X          case SINGLE_QUOTED:got=NORMAL_TEXT;continue;}    /* closing ' */
  1057. X       got=SINGLE_QUOTED;continue;                /* opening ' */
  1058. X    case '#':
  1059. X       if(got>SKIPPING_SPACE)        /* comment at start of word? */
  1060. X          break;
  1061. X       while((i=fgetc())!=EOF&&i!='\n');            /* skip till EOL */
  1062. X       goto ready;
  1063. X    case '$':
  1064. X       if(got==SINGLE_QUOTED)
  1065. X          break;
  1066. X       if(EOF==(i=fgetc()))
  1067. X        { *p++='$';goto ready;
  1068. X        }
  1069. X       startb=buf2;
  1070. X       if(i=='{')                          /* ${name} */
  1071. X        { while(EOF!=(i=fgetc())&&alphanum(i))
  1072. X         *startb++=i;
  1073. X          *startb='\0';
  1074. X          if(i!='}')
  1075. X           { log("Bad substitution of");logqnl(buf2);continue;
  1076. X           }
  1077. X          i='\0';
  1078. X        }
  1079. X       else if(alphanum(i))                        /* $name */
  1080. X        { do *startb++=i;
  1081. X          while(EOF!=(i=fgetc())&&alphanum(i));
  1082. X          if(i==EOF)
  1083. X         i='\0';
  1084. X          *startb='\0';
  1085. X        }
  1086. X       else if(i=='$')                      /* $$ =pid */
  1087. X        { ultstr(0,(unsigned long)thepid,p);goto ieofstr;
  1088. X        }
  1089. X       else if(i=='-')                   /* $- =lastfolder */
  1090. X        { strcpy(p,lastfolder);
  1091. Xieofstr:      i='\0';goto eofstr;
  1092. X        }
  1093. X       else
  1094. X        { *p++='$';goto newchar;               /* not a substitution */
  1095. X        }
  1096. X       startb=(char*)tgetenv(buf2);
  1097. X       if(!sarg&&got!=DOUBLE_QUOTED)
  1098. Xsimplsplit:   for(;;startb++)          /* simply split it up in arguments */
  1099. X           { switch(*startb)
  1100. X          { case ' ':case '\t':case '\n':
  1101. X               if(got<=SKIPPING_SPACE)
  1102. X              continue;
  1103. X               *p++='\0';got=SKIPPING_SPACE;continue;
  1104. X            case '\0':goto eeofstr;
  1105. X          }
  1106. X         *p++= *startb;got=NORMAL_TEXT;
  1107. X           }
  1108. X       else
  1109. X        { strcpy(p,startb);                   /* simply copy it */
  1110. Xeofstr:          if(got<=SKIPPING_SPACE)        /* can only occur if sarg!=0 */
  1111. X         got=NORMAL_TEXT;
  1112. X          p=strchr(p,'\0');
  1113. X        }
  1114. Xeeofstr:   if(i)                 /* already read next character? */
  1115. X          goto newchar;
  1116. X       continue;
  1117. X    case ' ':case '\t':
  1118. X       switch(got)
  1119. X        { case NORMAL_TEXT:
  1120. X         if(sarg==1)
  1121. X            goto ready;        /* already fetched a single argument */
  1122. X         got=SKIPPING_SPACE;*p++=sarg?' ':'\0';     /* space or \0 sep. */
  1123. X          case NOTHING_YET:case SKIPPING_SPACE:continue;    /* skip space */
  1124. X        }
  1125. X    case '\n':
  1126. X       if(got<=NORMAL_TEXT)
  1127. X          goto ready;                /* EOL means we're ready */
  1128. X      }
  1129. Xnodelim:
  1130. X     *p++=i;                       /* ah, a normal character */
  1131. X     if(got<=SKIPPING_SPACE)         /* should we bother to change mode? */
  1132. X    got=NORMAL_TEXT;
  1133. X   }
  1134. X}
  1135. X
  1136. Xultstr(minwidth,val,dest)unsigned long val;char*dest;
  1137. X{ int i;unsigned long j;
  1138. X  j=val;i=0;                       /* a beauty, isn't it :-) */
  1139. X  do i++;                       /* determine needed width */
  1140. X  while(j/=10);
  1141. X  while(--minwidth>=i)                 /* fill up any excess width */
  1142. X     *dest++=' ';
  1143. X  *(dest+=i)='\0';
  1144. X  do *--dest='0'+val%10;              /* display value backwards */
  1145. X  while(val/=10);
  1146. X}
  1147. X
  1148. Xsputenv(a)char*a;          /* smart putenv, the way it was supposed to be */
  1149. X{ static struct lienv{struct lienv*next;char name[255];}*myenv;
  1150. X  static alloced;int i,remove;char*split,**preenv;struct lienv*curr,**last;
  1151. X  yell("Assigning",a);remove=0;
  1152. X  if(!(split=strchr(a,'=')))               /* assignment or removal? */
  1153. X     remove=1,split=strchr(a,'\0');
  1154. X  i=split-a;
  1155. X  for(curr= *(last= &myenv);curr;curr= *(last= &curr->next))    /* is it one */
  1156. X     if(!strncmp(a,curr->name,i)&&curr->name[i]=='=')  /* I created earlier? */
  1157. X      { split=curr->name;*last=curr->next;free(curr);
  1158. X    for(preenv=environ;*preenv!=split;preenv++);
  1159. X    goto wipenv;
  1160. X      }
  1161. X  for(preenv=environ;*preenv;preenv++)            /* is it in the standard */
  1162. X     if(!strncmp(a,*preenv,i)&&(*preenv)[i]=='=')         /* environment? */
  1163. Xwipenv:
  1164. X      { while(*preenv=preenv[1])   /* wipe this entry out of the environment */
  1165. X       preenv++;
  1166. X    break;
  1167. X      }
  1168. X  i=(preenv-environ+2)*sizeof*environ;
  1169. X  if(alloced)           /* have we ever alloced the environ array before? */
  1170. X     environ=realloc(environ,i);
  1171. X  else
  1172. X     alloced=1,environ=tmemmove(malloc(i),environ,i-sizeof*environ);
  1173. X  if(!remove)          /* if not remove, then add it to both environments */
  1174. X   { for(preenv=environ;*preenv;preenv++);
  1175. X     curr=malloc(ioffsetof(struct lienv,name[0])+(i=strlen(a)+1));
  1176. X     tmemmove(*preenv=curr->name,a,i);preenv[1]=0;curr->next=myenv;
  1177. X     myenv=curr;
  1178. X   }
  1179. X}
  1180. X                /* strtol replacement which lacks range checking */
  1181. X#ifdef NOstrtol
  1182. Xlong strtol(start,ptr,base)const char*start,**const ptr;
  1183. X{ long result;const char*str=start;unsigned i;int sign,found;
  1184. X  if(base>=36||base<(sign=found=result=0))
  1185. X     goto fault;
  1186. X  for(;;str++)                      /* skip leading whitespace */
  1187. X   { switch(*str)
  1188. X      { case '\t':case '\n':case '\v':case '\f':case '\r':case ' ':continue;
  1189. X      }
  1190. X     break;
  1191. X   }
  1192. X  switch(*str)                               /* any signs? */
  1193. X   { case '-':sign=1;
  1194. X     case '+':str++;
  1195. X   }
  1196. X  if(*str=='0')                         /* leading zero(s)? */
  1197. X   { start++;
  1198. X     if((i= *++str)=='x'||i=='X')            /* leading 0x or 0X? */
  1199. X    if(!base||base==16)
  1200. X       base=16,str++;                /* hexadecimal all right */
  1201. X    else
  1202. X       goto fault;
  1203. X     else if(!base)
  1204. X    base=8;                         /* then it is octal */
  1205. X   }
  1206. X  else if(!base)
  1207. X     base=10;                          /* or else decimal */
  1208. X  goto jumpin;
  1209. X  do
  1210. X   { found=1;result=result*base+i;++str;         /* start converting */
  1211. Xjumpin:
  1212. X     if((i= *str-'0')<10);
  1213. X     else if(i-'A'+'0'<26)
  1214. X    i-='A'-10-'0';
  1215. X     else if(i-'a'+'0'<26)
  1216. X    i-='a'-10-'0';
  1217. X     else
  1218. X    break;                        /* not of this world */
  1219. X   }
  1220. X  while(i<base);                      /* still of this world */
  1221. Xfault:
  1222. X  if(ptr)
  1223. X    *ptr=found?str:start;                   /* how far did we get */
  1224. X  return sign?-result:result;
  1225. X}
  1226. X#endif
  1227. END_OF_FILE
  1228. if test 9223 -ne `wc -c <'procmail/goodies.c'`; then
  1229.     echo shar: \"'procmail/goodies.c'\" unpacked with wrong size!
  1230. fi
  1231. # end of 'procmail/goodies.c'
  1232. fi
  1233. if test -f 'procmail/regexp.c' -a "${1}" != "-c" ; then 
  1234.   echo shar: Will not clobber existing file \"'procmail/regexp.c'\"
  1235. else
  1236. echo shar: Extracting \"'procmail/regexp.c'\" \(10571 characters\)
  1237. sed "s/^X//" >'procmail/regexp.c' <<'END_OF_FILE'
  1238. X/************************************************************************
  1239. X *    Custom regular expression library, *fully* egrep compatible    *
  1240. X *                                    *
  1241. X *    Seems to be relatively bug free.                *
  1242. X *                                    *
  1243. X *    Copyright (c) 1991-1992, S.R. van den Berg, The Netherlands    *
  1244. X *    The sources can be freely copied for non-commercial use.    *
  1245. X *    #include "README"                        *
  1246. X *                                    *
  1247. X ************************************************************************/
  1248. X#ifdef RCS
  1249. Xstatic char rcsid[]="$Id: regexp.c,v 2.13 1992/03/06 12:38:31 berg Rel $";
  1250. X#endif
  1251. X#include "config.h"
  1252. X#include "procmail.h"
  1253. X#include "shell.h"
  1254. X
  1255. X#define R_BEG_GROUP    '('
  1256. X#define R_OR        '|'
  1257. X#define R_END_GROUP    ')'
  1258. X#define R_0_OR_MORE    '*'
  1259. X#define R_0_OR_1    '?'
  1260. X#define R_1_OR_MORE    '+'
  1261. X#define R_DOT        '.'
  1262. X#define R_SOL        '^'
  1263. X#define R_EOL        '$'
  1264. X#define R_BEG_CLASS    '['
  1265. X#define R_NOT_CLASS    '^'
  1266. X#define R_RANGE        '-'
  1267. X#define R_END_CLASS    ']'
  1268. X#define R_ESCAPE    '\\'
  1269. X
  1270. X#define BITS_P_CHAR        8
  1271. X#define OPB            (1<<BITS_P_CHAR)
  1272. X#define OPC_EPS            OPB
  1273. X#define OPC_CLASS        (OPB+1)
  1274. X#define OPC_DOT            (OPB+2)
  1275. X#define OPC_FIN            (OPB+3)
  1276. X
  1277. X#define bit_type        unsigned
  1278. X#define bit_bits        (sizeof(bit_type)*8)
  1279. X#define bit_index(which)    ((unsigned)(which)/bit_bits)
  1280. X#define bit_mask(which)        ((unsigned)1<<(unsigned)(which)%bit_bits)
  1281. X#define bit_toggle(name,which)    (name[bit_index(which)]^=bit_mask(which))
  1282. X#define bit_test(name,which)    (!!(name[bit_index(which)]&bit_mask(which)))
  1283. X#define bit_set(name,which,value)    \
  1284. X (value?(name[bit_index(which)]|=bit_mask(which)):\
  1285. X (name[bit_index(which)]&=~bit_mask(which)))
  1286. X#define bit_field(name,size)    bit_type name[((size)+bit_bits-1)/bit_bits]
  1287. X
  1288. X#define SZ(x)        (sizeof(struct x))
  1289. X#define Ceps        (struct eps*)
  1290. X#define epso(to,add)    (Ceps((char*)(to)+(add)))
  1291. X#define ii        (aleps.topc)
  1292. X#define jjp        (aleps.tnext)
  1293. X
  1294. X/* the spawn and stack members are reused in the normal opcodes as pc fields */
  1295. Xstatic struct eps{unsigned opc;struct eps*stack,*spawn,*next;}*r;
  1296. Xstatic struct{unsigned topc;struct eps*tnext;}aleps;
  1297. Xstatic uchar*p;
  1298. Xstatic ignore_case;
  1299. X
  1300. Xstruct chclass {unsigned opc_;struct eps*stack_,*spawn_,*next_;
  1301. X bit_field(c,OPB);};
  1302. X
  1303. Xstatic puteps(spot,to,aswell)struct eps*const spot;    /* epsilon transition */
  1304. X const struct eps*const to,*const aswell;
  1305. X{ spot->opc=OPC_EPS;spot->next=to!=spot?Ceps to:Ceps aswell;
  1306. X  spot->spawn=aswell!=spot?Ceps aswell:Ceps to;spot->stack=0;
  1307. X}
  1308. X
  1309. Xstatic putneps(spot,to)struct eps*const spot;const struct eps*const to;
  1310. X{ puteps(spot,to,spot+1);
  1311. X}
  1312. X
  1313. X#define rAc    (((struct chclass*)r)->c)
  1314. X
  1315. Xstatic bseti(i,j)unsigned i;const int j;
  1316. X{ bit_set(rAc,i,j);               /* mark 'i' as being in the class */
  1317. X  if(ignore_case)                  /* mark the other case too */
  1318. X   { if(i-'A'<26)                        /* uppercase */
  1319. X    i+='a'-'A';
  1320. X     else if(i-'a'<26)                        /* lowercase */
  1321. X    i-='a'-'A';
  1322. X     else return;                          /* no case */
  1323. X     bit_set(rAc,i,j);
  1324. X   }
  1325. X}
  1326. X
  1327. Xstatic por();
  1328. X
  1329. Xstatic psimp(e)const struct eps*const e;
  1330. X{ switch(*p)
  1331. X   { case R_BEG_GROUP:++p;por(e);return;      /* not so simple after all */
  1332. X     case R_BEG_CLASS:                       /* a simple class */
  1333. X      { unsigned i,j=R_NOT_CLASS==*++p;
  1334. X    if(e)
  1335. X     { r->opc=OPC_CLASS;r->next=Ceps e;r->spawn=r->stack=0;
  1336. X       i=maxindex(rAc);
  1337. X       do rAc[i]=j?~0:0;                 /* preset the bit field */
  1338. X       while(i--);
  1339. X     }
  1340. X    if(j)                      /* skip the 'not' modifier */
  1341. X     { ++p;
  1342. X       if(e)
  1343. X          bit_toggle(rAc,'\n');
  1344. X     }
  1345. X    if(*p==R_END_CLASS)      /* right at the start, cannot mean the end */
  1346. X     { ++p;
  1347. X       if(e)
  1348. X          i=R_END_CLASS,bit_toggle(rAc,R_END_CLASS);
  1349. X     }
  1350. X    else if(*p==R_RANGE)                /* take it literally */
  1351. X     { ++p;
  1352. X       if(e)
  1353. X          i=R_RANGE,bit_toggle(rAc,R_RANGE);
  1354. X     }
  1355. X    for(;;++p)
  1356. X     { switch(*p)
  1357. X        { case R_END_CLASS:++p;
  1358. X          case '\0':r=epso(r,SZ(chclass));return;
  1359. X          case R_RANGE:
  1360. X         switch(*++p)
  1361. X          { default:
  1362. X               if(e)
  1363. X              while(++i<*p)            /* mark all in the range */
  1364. X                 bseti(i,!j);
  1365. X               break;
  1366. X            case '\0':case R_END_CLASS:--p;        /* literally */
  1367. X          }
  1368. X        }
  1369. X       if(e)
  1370. X          bseti(i= *p,!j);              /* a normal character, mark it */
  1371. X     }
  1372. X      }
  1373. X     case '\0':return;
  1374. X     case R_DOT:             /* matches everything but a newline */
  1375. X    if(e)
  1376. X     { r->opc=OPC_DOT;goto fine;
  1377. X     }
  1378. X    goto fine2;
  1379. X     case R_EOL:case R_SOL:              /* match a newline (in effect) */
  1380. X    if(e)
  1381. X     { r->opc='\n';goto fine;
  1382. X     }
  1383. X    goto fine2;
  1384. X     case R_ESCAPE:                      /* quote something */
  1385. X    if(!*++p)                     /* nothing to quote */
  1386. X       --p;
  1387. X   }
  1388. X  if(e)                              /* a regular character */
  1389. X   { r->opc=ignore_case&&(unsigned)*p-'A'<26?*p+'a'-'A':*p;
  1390. Xfine:
  1391. X     r->next=Ceps e;r->spawn=r->stack=0;
  1392. X   }
  1393. Xfine2:
  1394. X  ++p;++r;
  1395. X}
  1396. X
  1397. X#define EOS(x)    (jjp?jjp:(x))
  1398. X
  1399. Xstatic pnorm(e)const struct eps*const e;
  1400. X{ void*pold;struct eps*rold;
  1401. X  for(;;)
  1402. X   { pold=p;rold=r;psimp(Ceps 0);ii= *p;            /* skip it first */
  1403. X     jjp=p[1]==R_OR||p[1]==R_END_GROUP||!p[1]?Ceps e:Ceps 0;
  1404. X     if(e)
  1405. X    p=pold,pold=r;
  1406. X     switch(ii)               /* check for any of the postfix operators */
  1407. X      { case R_0_OR_MORE:++r;
  1408. X       if(e)              /* first an epsilon, then the rest */
  1409. X          putneps(rold,EOS(r)),r=rold+1,psimp(rold);
  1410. X       goto incagoon;
  1411. X    case R_1_OR_MORE:                   /* first the rest */
  1412. X       if(e)                      /* and then an epsilon */
  1413. X          puteps(r,rold,EOS(r+1)),r=rold,psimp(Ceps pold);
  1414. X       ++r;goto incagoon;
  1415. X    case R_0_OR_1:++r;
  1416. X       if(e)              /* first an epsilon, then the rest */
  1417. X          putneps(rold,r=EOS(r)),pold=r,r=rold+1,psimp(Ceps pold);
  1418. Xincagoon:  switch(*++p)            /* at the end of this group already? */
  1419. X        { case R_OR:case R_END_GROUP:case '\0':return;
  1420. X        }
  1421. X       continue;                 /* regular end of the group */
  1422. X    case R_OR:case R_END_GROUP:case '\0':
  1423. X       if(e)
  1424. X          r=rold,psimp(e);
  1425. X       return;
  1426. X      }
  1427. X     if(e)            /* no fancy postfix operators, plain vanilla */
  1428. X    r=rold,psimp(Ceps pold);
  1429. X   }
  1430. X}
  1431. X
  1432. Xstatic por(e)const struct eps*const e;
  1433. X{ uchar*pold;struct eps*rold;
  1434. X  for(;;)
  1435. X     for(pold=p;;)
  1436. X      { rold=r;
  1437. X    switch(*p)
  1438. X     { default:pnorm(Ceps 0);r=rold;continue;     /* still in this group */
  1439. X       case '\0':case R_END_GROUP:           /* found the end of the group */
  1440. X          if(p==pold)                 /* empty 'or' group */
  1441. X           { if(e)
  1442. X            puteps(r,e,e);           /* misused epsilon as branch, */
  1443. X         ++r;        /* let the optimiser (fillout()) take it out */
  1444. X           }
  1445. X          else
  1446. X         p=pold,pnorm(e);            /* normal last group */
  1447. X          if(*p)
  1448. X         ++p;
  1449. X          return;
  1450. X       case R_OR:++r;
  1451. X          if(p==pold)                 /* empty 'or' group */
  1452. X           { if(e)
  1453. X            putneps(rold,e);              /* special epsilon */
  1454. X           }
  1455. X          else
  1456. X           { p=pold;pnorm(e);          /* normal 'or' group, first an */
  1457. X         if(e)                   /* epsilon, then the rest */
  1458. X            putneps(rold,r);
  1459. X           }
  1460. X          ++p;
  1461. X     }
  1462. X    break;
  1463. X      }
  1464. X}
  1465. X
  1466. Xstatic findandrep(old,newv)register struct eps**const old;
  1467. X struct eps*const newv;
  1468. X{ register struct eps*i,*t= *old;               /* save the value */
  1469. X  for(i=r;i->opc!=OPC_FIN;)         /* change all pointers from *old to new */
  1470. X   { if(i->next==t)
  1471. X    i->next=newv;
  1472. X     if(i->spawn==t)
  1473. X    i->spawn=newv;
  1474. X     switch(i->opc)
  1475. X      { case OPC_CLASS:i=epso(i,SZ(chclass));break;
  1476. X    default:++i;
  1477. X      }
  1478. X   }
  1479. X  *old=t;
  1480. X}
  1481. X
  1482. X#define drs(m)    (*(struct eps**)((char*)*stack+(ioffsetof(struct eps,m)^ofs)))
  1483. X
  1484. Xstatic cstack(stack,ofs)struct eps**const stack;
  1485. X{ if(drs(next)->stack==Ceps p)
  1486. X   { findandrep(*stack,drs(next));*stack=drs(spawn);return 1;
  1487. X   }
  1488. X  return 0;
  1489. X}
  1490. X    /* break up any closed epsilon circles, otherwise they can't be executed */
  1491. Xstatic fillout(stack)struct eps**const stack;
  1492. X{ if((*stack)->opc!=OPC_EPS||(*stack)->stack)
  1493. X     return 0;
  1494. X  (*stack)->stack=Ceps p;                /* mark this one as used */
  1495. X#define RECURS(nxt)    \
  1496. X  do\
  1497. X     if(cstack(stack,ioffsetof(struct eps,nxt)^ioffsetof(struct eps,next)))\
  1498. X    return 1;\
  1499. X  while(fillout(&(*stack)->nxt))
  1500. X  RECURS(next);RECURS(spawn);return 0;                  /* recurse */
  1501. X}
  1502. X
  1503. Xvoid*bregcomp(a,ign_case)char const*a;
  1504. X{ struct eps*st;size_t i;      /* first a trial run, determine memory needed */
  1505. X  p=(uchar*)a;ignore_case=ign_case;r=Ceps&aleps+1;por(Ceps 0);
  1506. X  st=malloc((i=(char*)r-(char*)&aleps)+ioffsetof(struct eps,stack)+sizeof r);
  1507. X  putneps(st,r=st+1);p=(uchar*)a;por(Ceps((char*)st+i));   /* really compile */
  1508. X  r->opc=OPC_FIN;r->stack=0;                  /* tack on the end */
  1509. X  for(r=st;;)                 /* simplify the compiled code (i.e. */
  1510. X     switch(st->opc)              /* take out cyclic epsilon references) */
  1511. X      { case OPC_FIN:return r;                     /* finished */
  1512. X    case OPC_CLASS:st=epso(st,SZ(chclass));break;             /* skip */
  1513. X    case OPC_EPS:p=(uchar*)st;fillout(&st);               /* check tree */
  1514. X    default:++st;                         /* skip too */
  1515. X      }
  1516. X}
  1517. X
  1518. X#define XOR1        \
  1519. X (ioffsetof(struct eps,spawn)^ioffsetof(struct eps,stack))
  1520. X#define PC(this,t)    (*(struct eps**)((char*)(this)+(t)))
  1521. X
  1522. Xchar*bregexec(code,text,len,ign_case)struct eps*code;const uchar*text;
  1523. X size_t len;
  1524. X{ register struct eps*reg,*t,*stack,*other,*thiss;unsigned i,th1,ot1;
  1525. X  if(code[1].opc==OPC_EPS)
  1526. X     ++code;           /* two epsilons at the start would be superfluous */
  1527. X  (thiss=code)->stack=0;th1=ioffsetof(struct eps,spawn);
  1528. X  ot1=ioffsetof(struct eps,stack);--text;++len;
  1529. X  i='\n';goto setups;          /* make sure any beginning-of-line-hooks catch */
  1530. X  do
  1531. X   { i= *++text;             /* get the next real-text character */
  1532. Xlastrun:                     /* switch this & other pc-stack */
  1533. X     th1^=XOR1;ot1^=XOR1;thiss=other;
  1534. Xsetups:
  1535. X     reg=(other=stack=code)->next;goto nostack;
  1536. X     do                     /* pop next entry off this pc-stack */
  1537. X      { reg=(t=thiss)->next;thiss=PC(t,th1);PC(t,th1)=0;goto nostack;
  1538. X    do                /* pop next entry off the work-stack */
  1539. X     { stack=(t=stack)->stack;t->stack=0;reg=t->spawn;
  1540. Xnostack:   switch(reg->opc-OPB)        /* push spawned branch on the work-stack */
  1541. X        { default:
  1542. X         if(ign_case&&i-'A'<26)
  1543. X            i+='a'-'A';             /* transmogrify it to lowercase */
  1544. X         if(i==reg->opc)          /* regular character match */
  1545. X            goto yep;
  1546. X         break;
  1547. X          case OPC_EPS-OPB:reg->stack=stack;reg=(stack=reg)->next;
  1548. X         goto nostack;
  1549. X          case OPC_FIN-OPB:           /* hurray!  complete regexp match */
  1550. X         return(char*)text;        /* return one past the match */
  1551. X          case OPC_CLASS-OPB:
  1552. X         if(bit_test(((struct chclass*)reg)->c,i))
  1553. X            goto yep;                   /* character in class */
  1554. X         break;
  1555. X          case OPC_DOT-OPB:                     /* dot-wildcard */
  1556. X         if(i!='\n')
  1557. Xyep:            if(!PC(reg,ot1))             /* state not yet pushed */
  1558. X               PC(reg,ot1)=other,other=reg;    /* push location onto */
  1559. X        }                           /* other pc-stack */
  1560. X     }
  1561. X    while(stack);                  /* the work-stack is not empty */
  1562. X      }
  1563. X     while(thiss!=code);               /* this pc-stack is not empty */
  1564. X   }
  1565. X  while(--len);                         /* still text to search */
  1566. X  if(ign_case!=2)                          /* out of text */
  1567. X   { ign_case=2;len=1;++text;goto lastrun;     /* check if we just matched */
  1568. X   }
  1569. X  return 0;                             /* no match */
  1570. X}
  1571. END_OF_FILE
  1572. if test 10571 -ne `wc -c <'procmail/regexp.c'`; then
  1573.     echo shar: \"'procmail/regexp.c'\" unpacked with wrong size!
  1574. fi
  1575. # end of 'procmail/regexp.c'
  1576. fi
  1577. echo shar: End of archive 3 \(of 5\).
  1578. cp /dev/null ark3isdone
  1579. MISSING=""
  1580. for I in 1 2 3 4 5 ; do
  1581.     if test ! -f ark${I}isdone ; then
  1582.     MISSING="${MISSING} ${I}"
  1583.     fi
  1584. done
  1585. if test "${MISSING}" = "" ; then
  1586.     echo You have unpacked all 5 archives.
  1587.     rm -f ark[1-9]isdone
  1588. else
  1589.     echo You still need to unpack the following archives:
  1590.     echo "        " ${MISSING}
  1591. fi
  1592. ##  End of shell archive.
  1593. exit 0
  1594. -- 
  1595. Sincerely,                                  berg@pool.informatik.rwth-aachen.de
  1596.            Stephen R. van den Berg (AKA BuGless).    berg@physik.tu-muenchen.de
  1597.  
  1598. He did a quarter of the work in *half* the time!
  1599.  
  1600. exit 0 # Just in case...
  1601.