home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / misc / volume38 / procmail / part10 < prev    next >
Text File  |  1993-07-05  |  49KB  |  1,370 lines

  1. Newsgroups: comp.sources.misc
  2. From: berg@pool.informatik.rwth-aachen.de (Stephen R. van den Berg)
  3. Subject: v38i029:  procmail - mail processing package v2.90, Part10/11
  4. Message-ID: <1993Jul1.151501.21955@sparky.imd.sterling.com>
  5. X-Md4-Signature: 45f09892c8d94176ba27558b1538883a
  6. Sender: kent@sparky.imd.sterling.com (Kent Landfield)
  7. Organization: Sterling Software
  8. Date: Thu, 1 Jul 1993 15:15:01 GMT
  9. Approved: kent@sparky.imd.sterling.com
  10.  
  11. Submitted-by: berg@pool.informatik.rwth-aachen.de (Stephen R. van den Berg)
  12. Posting-number: Volume 38, Issue 29
  13. Archive-name: procmail/part10
  14. Environment: sendmail, smail, MMDF, mailsurr, UNIX, POSIX
  15. Supersedes: procmail: Volume 35, Issue 21-32,124,125
  16.  
  17. #! /bin/sh
  18. # This is a shell archive.  Remove anything before this line, then unpack
  19. # it by saving it into a file and typing "sh file".  To overwrite existing
  20. # files, type "sh file -c".  You can also feed this as standard input via
  21. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  22. # will see the following message at the end:
  23. #        "End of archive 10 (of 11)."
  24. # Contents:  procmail/mailinglist/etc/rc.main
  25. #   procmail/man/procmailrc.man procmail/src/procmail.c
  26. # Wrapped by berg@tubastos on Thu Jul  1 14:06:18 1993
  27. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  28. if test -f 'procmail/mailinglist/etc/rc.main' -a "${1}" != "-c" ; then 
  29.   echo shar: Will not clobber existing file \"'procmail/mailinglist/etc/rc.main'\"
  30. else
  31. echo shar: Extracting \"'procmail/mailinglist/etc/rc.main'\" \(216 characters\)
  32. sed "s/^X//" >'procmail/mailinglist/etc/rc.main' <<'END_OF_FILE'
  33. X#$Id: rc.main,v 1.4 1993/06/21 14:23:50 berg Exp $
  34. X
  35. XMAILDIR=.etc                # chdir to the defaults directory
  36. X
  37. XINCLUDERC=rc.init
  38. X
  39. X:0 wfh
  40. X| formail -A"X-Diagnostic: Non-existing mailinglist $X_ENVELOPE_TO"
  41. X
  42. XINCLUDERC=rc.post
  43. END_OF_FILE
  44. if test 216 -ne `wc -c <'procmail/mailinglist/etc/rc.main'`; then
  45.     echo shar: \"'procmail/mailinglist/etc/rc.main'\" unpacked with wrong size!
  46. fi
  47. # end of 'procmail/mailinglist/etc/rc.main'
  48. fi
  49. if test -f 'procmail/man/procmailrc.man' -a "${1}" != "-c" ; then 
  50.   echo shar: Will not clobber existing file \"'procmail/man/procmailrc.man'\"
  51. else
  52. echo shar: Extracting \"'procmail/man/procmailrc.man'\" \(19070 characters\)
  53. sed "s/^X//" >'procmail/man/procmailrc.man' <<'END_OF_FILE'
  54. X.Id $Id: procmailrc.man,v 1.23 1993/06/21 14:24:10 berg Exp $
  55. X.TH PROCMAILRC 5 \*(Dt BuGless
  56. X.na
  57. X.SH NAME
  58. Xprocmailrc \- procmail rcfile
  59. X.SH SYNOPSIS
  60. X.B $HOME/@PROCMAILRC@
  61. X.ad
  62. X.Sh DESCRIPTION
  63. XFor a quick start, see
  64. X.B NOTES
  65. Xat the end of the
  66. X.BR procmail (1)
  67. Xman page.
  68. X.PP
  69. XThe rcfile can contain a mixture of environment variable assignments (some
  70. Xof which have special meanings to procmail), and recipes.  In their most
  71. Xsimple appearance, the recipes are simply one line regular expressions
  72. Xthat are searched for in the header of the arriving mail, the first recipe
  73. Xthat matches is used to determine where the mail has to go (usually a file).
  74. X.PP
  75. XIf a matching recipe does not specify any special flags (like `@FILTER@' or
  76. X`@CONTINUE@') and the recipe is successful (i.e. no write failures or other
  77. Xcalamities), then processing of the rcfile will cease at this point, and
  78. Xprocmail will consider the mail to have been delivered.
  79. X.PP
  80. XThis enables you to presort your mail extremely straightforward into several
  81. Xmailfolders.  Bear in mind though that the mail can arrive concurrently in
  82. Xthese mailfolders (if several procmail programs happen to run at the same time,
  83. Xnot unlikely if a lot of mail arrives), to make sure this does not result in a
  84. Xmess, proper use of lockfiles is highly recommended.
  85. X.PP
  86. XThe environment variable
  87. X.B assignments
  88. Xand
  89. X.B recipes
  90. Xcan be freely intermixed in the rcfile. If any environment variable has
  91. Xa special meaning to procmail, it will be used appropriately the moment
  92. Xit is parsed. (i.e. you can change the current directory whenever you
  93. Xwant by specifying a new
  94. X.BR MAILDIR ,
  95. Xswitch lockfiles by specifying a new
  96. X.BR LOCKFILE ,
  97. Xchange the umask at any time, etc., the possibilities are endless :-).
  98. X.PP
  99. XThe assignments and substitutions of these environment variables are handled
  100. Xexactly like in
  101. X.BR sh (1)
  102. X(that includes all possible quotes and escapes),
  103. Xwith the added bonus that blanks around the '=' sign are ignored and that,
  104. Xif an environment variable appears without a trailing '=', it will be
  105. Xremoved from the environment.  Any program in backquotes started by procmail
  106. Xwill have the entire mail at its stdin.
  107. X.PP
  108. X.Ss Comments
  109. XA word beginning with # and all the following characters up to a NEWLINE
  110. Xare ignored.
  111. X.Ss Recipes
  112. X.PP
  113. XA line starting with ':' marks the beginning of a recipe.  It has the
  114. Xfollowing format:
  115. X.PP
  116. X.Rs
  117. X: [\fInumber\fP] [\fIflags\fP] [ : [\fIlocallockfile\fP] ]
  118. X<zero or more conditions (one per line)>
  119. X<exactly one action line>
  120. X.Re
  121. X.PP
  122. XThe
  123. X.I number
  124. Xis optional (defaults to 1) and specifies the number of conditions that
  125. Xfollow the first line of the recipe.  Conditions are complete lines that are
  126. Xpassed on to the internal egrep
  127. X.BR literally ,
  128. Xexcept for leading and trailing whitespace.  If you start every condition
  129. Xline with an `*', you do not need to specify
  130. X.IR number .
  131. XWhitespace after the leading `*' are ignored.  The safest way would be
  132. Xto specify
  133. X.I number
  134. Xto be zero in that case (to avoid problems when you have no conditions, but
  135. Xprocmail expects one).
  136. XThese regular expressions are
  137. X.B completely
  138. Xcompatible to the normal
  139. X.BR egrep (1)
  140. Xregular expressions.
  141. X.PP
  142. XConditions are anded; if
  143. X.I number
  144. Xis zero, then the condition is always true and no conditions are expected
  145. Xnext.
  146. X.PP
  147. X.I Flags
  148. Xcan be any of the following:
  149. X.Tp 0.5i
  150. X.B @HEAD_GREP@
  151. XEgrep the header (default).
  152. X.Tp
  153. X.B @BODY_GREP@
  154. XEgrep the body.
  155. X.Tp
  156. X.B @DISTINGUISH_CASE@
  157. XTell the internal egrep to distinguish between upper and lower case (defaults
  158. Xto ignoring case).
  159. X.Tp
  160. X.B @ALSO_NEXT_RECIPE@
  161. XThis recipe will depend on the last preceding recipe without the
  162. X`@ALSO_NEXT_RECIPE@' or `@ALSO_N_IF_SUCC@' flag.  This allows you to chain
  163. Xactions that depend on a common condition.  The number of conditions that
  164. Xare expected to follow default to none.
  165. X.Tp
  166. X.B @ALSO_N_IF_SUCC@
  167. XHas the same meaning as the `@ALSO_NEXT_RECIPE@' flag, but will depend on the
  168. X.I successful
  169. Xcompletion of the immediately preceding recipe as well.
  170. X.Tp
  171. X.B @PASS_HEAD@
  172. XFeed the header to the pipe (default).
  173. X.Tp
  174. X.B @PASS_BODY@
  175. XFeed the body to the pipe (default).
  176. X.Tp
  177. X.B @FILTER@
  178. XConsider the pipe as a filter.
  179. X.Tp
  180. X.B @CONTINUE@
  181. XContinue processing rcfile even if this recipe matches (not needed when 'f'
  182. Xspecified).
  183. X.Tp
  184. X.B @WAIT_EXIT@
  185. XWait for the filter or program to finish and check its exitcode (normally
  186. Xignored); if the filter is unsuccessful, then the text will not have been
  187. Xfiltered.
  188. X.Tp
  189. X.B @WAIT_EXIT_QUIET@
  190. XHas the same meaning as the `@WAIT_EXIT@' flag, but will suppress any
  191. X`Program failure' message.
  192. X.Tp
  193. X.B @IGNORE_WRITERR@
  194. XIgnore any write errors on this recipe (i.e. usually due to an early closed
  195. Xpipe).
  196. X.PP
  197. XThere are some special conditions you can use that are not straight regular
  198. Xexpressions.  To select them, the first character of the condition must
  199. Xbe a:
  200. X.Tp 0.5i
  201. X.B !
  202. XInvert the condition.
  203. X.Tp
  204. X.B $
  205. XEvaluate the remainder according to
  206. X.BR sh (1)
  207. Xsubstitution rules inside double quotes.
  208. X.Tp
  209. X.B ?
  210. XUse the exitcode of the specified program.
  211. X.Tp
  212. X.B <
  213. XCheck if the total length of the mail is shorter than the specified (in
  214. Xdecimal) number of bytes.
  215. X.Tp
  216. X.B >
  217. XAnalogous to '<'.
  218. X.Tp
  219. X.B \e
  220. XTo quote any of the above at the start of the line.
  221. X.Ss "Local lockfile"
  222. X.PP
  223. XIf you put a second ':' on the first recipe line, then procmail will use a
  224. X.I locallockfile
  225. X(for this recipe only).  You can optionally specify the locallockfile
  226. Xto use; if you don't however, procmail will use the destination filename
  227. X(or the filename following the first '>>') and will append $LOCKEXT to it.
  228. X.Ss "Recipe action line"
  229. X.PP
  230. XThe action line can start with the following characters:
  231. X.Tp
  232. X.B !
  233. XForwards to all the specified mail addresses.
  234. X.Tp
  235. X.B |
  236. XStarts the specified program, possibly in $SHELL if any
  237. Xof the characters $SHELLMETAS are spotted.  You can optionally prepend this
  238. Xpipe symbol with
  239. X.IR variable= ,
  240. Xwhich will cause stdout of the program to be captured in the environment
  241. X.IR variable .
  242. X.PP
  243. XAnything else will be taken as a mailbox name (either a filename or a
  244. Xdirectory, absolute or relative to the current directory (see MAILDIR)).
  245. XIf it is a filename (or nonexistent), the mail will be appended to it.
  246. X.PP
  247. XIf it is a directory, the mail will be delivered to a newly created, guaranteed
  248. Xto be unique file named $MSGPREFIX* in the specified directory.  If the
  249. Xdirectory name ends in "@MCDIRSEP@@chCURDIR@", then this directory is presumed
  250. Xto be an MH folder; i.e. procmail will use the next number it finds available.
  251. XWhen procmail is delivering to directories, you can specify multiple
  252. Xdirectories to deliver to (using hardlinks).
  253. X.Ss "Environment variable defaults"
  254. X.Tp 2.2i
  255. X.B "LOGNAME, HOME and SHELL"
  256. XYour (the recipient's) defaults
  257. X.Tp
  258. X.B SHELLMETAS
  259. X\&@DEFshellmetas@
  260. X.Tp
  261. X.B SHELLFLAGS
  262. X\&@DEFshellflags@
  263. X.Tp
  264. X.BR ORGMAIL
  265. X\&@SYSTEM_MBOX@
  266. X.Tp
  267. X.B MAILDIR
  268. X\&@DEFmaildir@
  269. X.br
  270. X(Unless the name of the first successfully opened rcfile starts with
  271. X`@chCURDIR@@MCDIRSEP@', in which case it defaults to `@chCURDIR@')
  272. X.Tp
  273. X.B DEFAULT
  274. X\&@DEFdefault@
  275. X.Tp
  276. X.B MSGPREFIX
  277. X\&@DEFmsgprefix@
  278. X.Tp
  279. X.B SENDMAIL
  280. X\&@DEFsendmail@
  281. X.Tp
  282. X.B COMSAT
  283. X\&@DEFcomsat@
  284. X.br
  285. X(If an rcfile is specified on the command line)
  286. X.Tp
  287. X.B LOCKEXT
  288. X\&@DEFlockext@
  289. X.Tp
  290. X.B LOCKFILE
  291. X\&@DEFdefaultlock@
  292. X.br
  293. X(After procmail closed the last rcfile)@PRESTENV@@LD_ENV_FIX@
  294. X.Ss Environment
  295. X.PP
  296. XBefore you get lost in the multitude of environment variables, keep in mind
  297. Xthat all of them have reasonable defaults.
  298. X.Tp 1.2i
  299. X.B MAILDIR
  300. XCurrent directory while procmail is executing (that means that all paths
  301. Xare relative to $MAILDIR).
  302. X.Tp
  303. X.B DEFAULT
  304. XDefault
  305. X.B mailbox
  306. Xfile (if not told otherwise, procmail will dump mail in this mailbox).
  307. XProcmail will automatically use LOCKFILE=$DEFAULT$LOCKEXT prior to writing
  308. Xto this mailbox.
  309. X.Tp
  310. X.B MSGPREFIX
  311. XFilename prefix that is used when delivering to a directory (not used when
  312. Xdelivering to an MH directory).
  313. X.Tp
  314. X.B LOGFILE
  315. XThis file will also contain any error or diagnostic messages from procmail
  316. X(normally none :-) or any other programs started by procmail.  If this file
  317. Xis not specified, any diagnostics or error messages will
  318. X@pconsole@@console@@aconsole@
  319. XSee also
  320. X.BR LOGABSTRACT .
  321. X.Tp
  322. X.B VERBOSE
  323. XYou can turn on
  324. X.I extended diagnostics
  325. Xby setting this variable to `yes' or `on', to turn it off again set it to `no'
  326. Xor `off'.
  327. X.Tp
  328. X.B LOGABSTRACT
  329. XJust before procmail exits it logs an abstract of the delivered message in
  330. X$LOGFILE showing the `@FROM@' and `Subject:' fields of the header, what folder
  331. Xit finally went to and how long (in bytes) the message was.  By setting this
  332. Xvariable to `no', generation of this abstract is suppressed.
  333. X.Tp
  334. X.B LOG
  335. XAnything assigned to this variable will be appended to $LOGFILE.
  336. X.Tp
  337. X.B ORGMAIL
  338. XUsually the system mailbox (\fBOR\fPi\fBG\fPinal \fBMAIL\fPbox).  If, for
  339. Xsome obscure reason (like `\fBfilesystem full\fP') the mail could not be
  340. Xdelivered, then this mailbox will be the last resort.  If procmail
  341. Xfails to save the mail in here (deep, deep trouble :-), then the mail
  342. Xwill bounce back to the sender.
  343. X.Tp
  344. X.B LOCKFILE
  345. XGlobal semaphore file.  If this file already exists, procmail
  346. Xwill wait until it has gone before proceeding, and will create it itself
  347. X(cleaning it up when ready, of course).  If more than one
  348. X.I lockfile
  349. Xare specified, then the previous one will be removed before trying to create
  350. Xthe new one.  The use of a global lockfile is discouraged, whenever possible
  351. Xuse locallockfiles (on a per recipe basis) instead.
  352. X.Tp
  353. X.B LOCKEXT
  354. XDefault extension that is appended to a destination file to determine
  355. Xwhat local
  356. X.I lockfile
  357. Xto use (only if turned on, on a per-recipe basis).
  358. X.Tp
  359. X.B LOCKSLEEP
  360. XNumber of seconds procmail will sleep before retrying on a
  361. X.I lockfile
  362. X(if it already existed); if not specified, it defaults to @DEFlocksleep@
  363. Xseconds.
  364. X.Tp
  365. X.B LOCKTIMEOUT
  366. XNumber of seconds that have to have passed since a
  367. X.I lockfile
  368. Xwas last modified/created before procmail decides that this must be an
  369. Xerroneously leftover lockfile that can be removed by force now.  If zero,
  370. Xthen no timeout will be used and procmail will wait forever until the
  371. Xlockfile is removed; if not specified, it defaults to @DEFlocktimeout@ seconds.
  372. XThis variable is useful to prevent indefinite hangups of
  373. X.BR sendmail /procmail.
  374. XProcmail is immune to clock skew.
  375. X.Tp
  376. X.B TIMEOUT
  377. XNumber of seconds that have to have passed before procmail decides that
  378. Xsome child it started must be hanging.  The offending program will receive
  379. Xa TERMINATE signal from procmail, and processing of the rcfile will continue.
  380. XIf zero, then no timeout will be used and procmail will wait forever until the
  381. Xchild has terminated; if not specified, it defaults to @DEFtimeout@ seconds.
  382. X.Tp
  383. X.B HOST
  384. XIf this is not the
  385. X.I hostname
  386. Xof the machine, processing of the current
  387. X.I rcfile
  388. Xwill immediately cease. If other rcfiles were specified on the
  389. Xcommand line, processing will continue with the next one.  If all rcfiles
  390. Xare exhausted, the program will terminate, but will not generate an error
  391. X(i.e. to the mailer it will seem that the mail has been delivered).  Only the
  392. Xfirst @HOSTNAMElen@ characters of the HOST are significant.
  393. X.Tp
  394. X.B UMASK
  395. XThe name says it all (if it doesn't, then forget about this one :-).
  396. XAnything assigned to UMASK is taken as an
  397. X.B octal
  398. Xnumber.  If not specified, the umask defaults to @INIT_UMASK@.  If the umask
  399. Xpermits o+x, all the mailboxes procmail delivers to directly will receive
  400. Xa o+x mode change.  This can be used to check if new mail arrived.
  401. X.Tp
  402. X.B SHELLMETAS
  403. XIf any of the characters in SHELLMETAS appears in the line specifying
  404. Xa filter or program, the line will be fed to $SHELL
  405. Xinstead of being executed directly.
  406. X.Tp
  407. X.B SHELLFLAGS
  408. XAny invocation of $SHELL will be like:
  409. X.br
  410. X"$SHELL" "$SHELLFLAGS" "$*";
  411. X.Tp
  412. X.B SENDMAIL
  413. XIf you're not using the
  414. X.I forwarding
  415. Xfacility don't worry about this one.  It specifies the program being
  416. Xcalled to forward any mail.
  417. X.br
  418. XIt gets invoked as: "$SENDMAIL" "$@";
  419. X.Tp
  420. X.B NORESRETRY
  421. XNumber of retries that are to be made if any `\fBprocess table full\fP',
  422. X`\fBfile table full\fP', `\fBout of memory\fP' or
  423. X`\fBout of swap space\fP' error should occur.  If this number is negative,
  424. Xthen procmail will retry indefinitely; if not specified, it defaults to
  425. X@DEFnoresretry@ times.  The retries occur with a $SUSPEND second interval.  The
  426. Xidea behind this is, that if e.g. the
  427. X.I swap
  428. X.I space
  429. Xhas been exhausted or the
  430. X.I process
  431. X.I table
  432. Xis full, usually several other programs will either detect this as well
  433. Xand abort or crash 8-), thereby freeing valuable
  434. X.I resources
  435. Xfor procmail.
  436. X.Tp
  437. X.B SUSPEND
  438. XNumber of seconds that procmail will pause if it has to wait for something
  439. Xthat is currently unavailable (memory, fork, etc.); if not specified, it will
  440. Xdefault to @DEFsuspend@ seconds.  See also:
  441. X.BR LOCKSLEEP .
  442. X.Tp
  443. X.B LINEBUF
  444. XLength of the internal line buffers, cannot be set smaller than @MINlinebuf@.
  445. XAll lines read from the
  446. X.I rcfile
  447. Xshould not exceed $LINEBUF characters before and after expansion.  If not
  448. Xspecified, it defaults to @DEFlinebuf@.  This limit, of course, does
  449. X.I not
  450. Xapply to the mail itself, which can have arbitrary line lengths, or could
  451. Xbe a binary file for that matter.
  452. X.Tp
  453. X.B DELIVERED
  454. XIf set to `yes' procmail will pretend (to the mail agent) the mail
  455. Xhas been delivered.  If mail cannot be delivered after meeting this
  456. Xassignment (to `yes'), the mail will be lost (i.e. it will not bounce).
  457. X.Tp
  458. X.B TRAP
  459. XWhen procmail terminates it will execute the contents of this variable.
  460. XA copy of the mail can be read from stdin.  Any output produced by this
  461. Xcommand will be appended to $LOGFILE.  Possible uses for TRAP are: removal
  462. Xof temporary files, logging customised abstracts, change the exitcode of
  463. Xprocmail, etc.
  464. X.Tp
  465. X.B LASTFOLDER
  466. XThis variable is assigned to by procmail whenever it is delivering
  467. Xto a folder or program.  It always contains the name of the last folder
  468. X(or program) procmail delivered to.
  469. X.Tp
  470. X.B INCLUDERC
  471. XNames an rcfile (relative to the current directory) which will be included
  472. Xhere as if it were part of the current rcfile.  Unlimited nesting is
  473. Xpermitted.
  474. X.Tp
  475. X.B COMSAT
  476. X.BR Comsat (8)/ biff (1)
  477. Xnotification is on by default, it can be turned off by setting this variable
  478. Xto `no'.  Alternatively the biff-service can be customised by setting it to
  479. Xeither `service@SERV_ADDRsep@', `@SERV_ADDRsep@hostname', or
  480. X`service@SERV_ADDRsep@hostname'.  When not specified it defaults
  481. Xto @COMSATservice@@SERV_ADDRsep@@COMSAThost@.
  482. X.Sh EXAMPLES
  483. XLook in the
  484. X.BR procmailex (5)
  485. Xman page.
  486. X.Sh CAVEATS
  487. XContinued lines in an action line that specifies a program always have to end
  488. Xin a backslash, even if the underlying shell would not need or want the
  489. Xbackslash to indicate continuation.  This is due to the two pass parsing
  490. Xprocess needed (first procmail, then the shell (or not, depending on
  491. X.BR SHELLMETAS )).
  492. X.PP
  493. XDon't put comments on the regular expression condition lines in a
  494. Xrecipe, these lines are fed to the internal egrep
  495. X.I literally
  496. X(except for continuation backslashes at the end of a line).
  497. X.PP
  498. XWatch out for deadlocks when doing unhealthy things like forwarding mail
  499. Xto your own account.  Deadlocks can be broken by proper use of
  500. X.BR LOCKTIMEOUT .
  501. X.PP
  502. XAny default values that procmail has for some environment variables will
  503. X.B always
  504. Xoverride the ones that were already defined.  If you really want to
  505. Xoverride the defaults, you either have to put them in the
  506. X.B rcfile
  507. Xor on the command line as arguments.
  508. X.PP
  509. XEnvironment variables set
  510. X.B inside
  511. Xthe action part of a recipe will
  512. X.B not
  513. Xretain their value after the recipe has finished since they are set in a
  514. Xsubshell of procmail.  To make sure the value of an environment variable is
  515. Xretained you have to put the assignment to the variable before the leading `|'
  516. Xof a recipe, so that it can capture stdout of the program.
  517. X.PP
  518. XIf you specify only a `@PASS_HEAD@' or a `@PASS_BODY@' flag on a recipe,
  519. Xand the recipe matches, then, unless a `@FILTER@' or `@CONTINUE@' flag is
  520. Xpresent as well, the body respectively the header of the mail will be silently
  521. Xlost.
  522. X.PP
  523. XThe `@CONTINUE@' flag defaults to on when capturing stdout of a recipe in an
  524. Xenvironment variable.
  525. X.Sh "SEE ALSO"
  526. X.na
  527. X.nh
  528. X.BR procmail (1),
  529. X.BR procmailex (5),
  530. X.BR sh (1),
  531. X.BR csh (1),
  532. X.BR mail (1),
  533. X.BR mailx (1),
  534. X.BR binmail (1),
  535. X.BR uucp (1),
  536. X.BR aliases (5),
  537. X.BR sendmail (8),
  538. X.BR egrep (1),
  539. X.BR grep (1),
  540. X.BR biff (1),
  541. X.BR comsat (8),
  542. X.BR lockfile (1),
  543. X.BR formail (1)
  544. X.hy
  545. X.ad
  546. X.Sh BUGS
  547. XThe only substitutions of environment variables that can be handled by
  548. Xprocmail itself are of the type $name, ${name}, $#, $n, $$, $? and $\-;
  549. Xwhereas $\- will be substituted by $LASTFOLDER.  When the
  550. X.B \-$ARGUMENTOPT@
  551. Xor
  552. X.B \-$MAILFILTOPT@
  553. Xoptions are used, "$@" will expand to respectively the specified argument
  554. Xor the sender and recipient list; but only when passed as in the
  555. Xargument list to a program.@UPPERCASE_USERNAMES@
  556. X.PP
  557. XA line buffer of length $LINEBUF is used when processing the
  558. X.IR rcfile ,
  559. Xany expansions
  560. X.B have
  561. Xto fit within this limit; if they don't, behaviour is undefined.
  562. X.PP
  563. XIf the global lockfile has a
  564. X.I relative
  565. Xpath, and the current directory
  566. Xis not the same as when the global lockfile was created, then the global
  567. Xlockfile will not be removed if procmail exits at that point (remedy:
  568. Xuse
  569. X.I absolute
  570. Xpaths to specify global lockfiles).
  571. X.PP
  572. XWhen capturing stdout from a recipe into an environment variable, exactly
  573. Xone trailing newline will be stripped.
  574. X.PP
  575. XBy using the `^' or `$' in other spots than at the start respectively
  576. Xend of a regular expression you can use the internal egrep to do multiline
  577. Xmatches.
  578. X.PP
  579. XWhen the regular expression starts with `^^' it will anchor the match
  580. Xat the very start of the text.
  581. X.Sh MISCELLANEOUS
  582. XIf the regular expression contains `\fB@TOkey@\fP' it will be substituted by
  583. X.na
  584. X.nh
  585. X`\fB@TOsubstitute@\fP',
  586. Xwhich should catch all destination specifications.
  587. X.hy
  588. X.ad
  589. X.PP
  590. XIf the regular expression contains `\fB@FROMDkey@\fP' it will be
  591. Xsubstituted by
  592. X.na
  593. X.nh
  594. X`\fB@FROMDsubstitute@\fP',
  595. Xwhich should catch mails coming from most daemons (how's that for a regular
  596. Xexpression :-).
  597. X.hy
  598. X.ad
  599. X.PP
  600. XIf the regular expression contains `\fB@FROMMkey@\fP' it will be
  601. Xsubstituted by
  602. X.na
  603. X.nh
  604. X`\fB@FROMMsubstitute@\fP'
  605. X(a stripped down version of `\fB@FROMDkey@\fP'),
  606. Xwhich should catch mails coming from most mailer-daemons.
  607. X.hy
  608. X.ad
  609. X.PP
  610. XWhen assigning boolean values to variables like VERBOSE, DELIVERED or COMSAT,
  611. Xprocmail accepts as true every string starting with: a non-zero value, `on',
  612. X`y', `t' or `e'.  False is every string starting with: a zero value, `off',
  613. X`n', `f' or 'd'.
  614. X.PP
  615. XIf the action line of a recipe specifies a program, a sole backslash-newline
  616. Xpair in it on an otherwise empty line will be converted into a newline.
  617. X.Sh NOTES
  618. XSince whitespace is generally ignored in the rcfile you can indent everything
  619. Xto taste.
  620. X.PP
  621. XThe leading `|' on the action line to specify a program or filter is stripped
  622. Xbefore checking for $SHELLMETAS.
  623. X.PP
  624. XFiles included with the INCLUDERC directive containing only environment
  625. Xvariable assignments can be shared with sh.
  626. X.PP
  627. XFor
  628. X.I really
  629. Xcomplicated processing you can even consider calling
  630. X.B procmail
  631. Xrecursively.
  632. END_OF_FILE
  633. if test 19070 -ne `wc -c <'procmail/man/procmailrc.man'`; then
  634.     echo shar: \"'procmail/man/procmailrc.man'\" unpacked with wrong size!
  635. fi
  636. # end of 'procmail/man/procmailrc.man'
  637. fi
  638. if test -f 'procmail/src/procmail.c' -a "${1}" != "-c" ; then 
  639.   echo shar: Will not clobber existing file \"'procmail/src/procmail.c'\"
  640. else
  641. echo shar: Extracting \"'procmail/src/procmail.c'\" \(25195 characters\)
  642. sed "s/^X//" >'procmail/src/procmail.c' <<'END_OF_FILE'
  643. X/************************************************************************
  644. X *    procmail - The autonomous mail processor            *
  645. X *                                    *
  646. X *    It has been designed to be able to be run suid root and (in    *
  647. X *    case your mail spool area is *not* world writeable) sgid    *
  648. X *    mail (or daemon), without creating security holes.        *
  649. X *                                    *
  650. X *    Seems to be perfect.                        *
  651. X *                                    *
  652. X *    Copyright (c) 1990-1992, S.R. van den Berg, The Netherlands    *
  653. X *    #include "README"                        *
  654. X ************************************************************************/
  655. X#ifdef RCS
  656. Xstatic /*const*/char rcsid[]=
  657. X "$Id: procmail.c,v 1.37 1993/07/01 11:58:36 berg Exp $";
  658. X#endif
  659. X#include "../patchlevel.h"
  660. X#include "procmail.h"
  661. X#include "sublib.h"
  662. X#include "robust.h"
  663. X#include "shell.h"
  664. X#include "misc.h"
  665. X#include "pipes.h"
  666. X#include "common.h"
  667. X#include "cstdio.h"
  668. X#include "exopen.h"
  669. X#include "goodies.h"
  670. X#include "locking.h"
  671. X#include "mailfold.h"
  672. X
  673. Xstatic const char fdefault[]="DEFAULT",orgmail[]="ORGMAIL",*const nullp,
  674. X sendmail[]="SENDMAIL",From_[]=FROM,exflags[]=RECFLAGS,
  675. X systm_mbox[]=SYSTEM_MBOX,pmusage[]=PM_USAGE,DEFdeflock[]=DEFdefaultlock;
  676. Xchar*buf,*buf2,*globlock,*loclock,*tolock;
  677. Xconst char shellflags[]="SHELLFLAGS",shell[]="SHELL",lockfile[]="LOCKFILE",
  678. X shellmetas[]="SHELLMETAS",lockext[]="LOCKEXT",newline[]="\n",binsh[]=BinSh,
  679. X unexpeof[]="Unexpected EOL\n",*const*gargv,*const*restargv= &nullp,*sgetcp,
  680. X *rcfile=PROCMAILRC,dirsep[]=DIRSEP,msgprefix[]="MSGPREFIX",devnull[]=DevNull,
  681. X lgname[]="LOGNAME",executing[]="Executing",oquote[]=" \"",cquote[]="\"\n",
  682. X procmailn[]="procmail",whilstwfor[]=" whilst waiting for ",home[]="HOME",
  683. X maildir[]="MAILDIR",*defdeflock,*argv0="";
  684. Xchar*Stdout;
  685. Xint retval=EX_CANTCREAT,retvl2=EX_OK,sh,pwait,lcking,rc=rc_INIT,
  686. X ignwerr,lexitcode=EX_OK,asgnlastf,accspooldir,crestarg;
  687. Xsize_t linebuf=mx(DEFlinebuf+XTRAlinebuf,STRLEN(systm_mbox)<<1);
  688. Xvolatile int nextexit;                   /* if termination is imminent */
  689. Xpid_t thepid;
  690. Xlong filled;                       /* the length of the mail */
  691. Xchar*themail,*thebody;                /* the head and body of the mail */
  692. Xuid_t uid;
  693. Xgid_t gid,sgid;
  694. X
  695. Xmain(argc,argv)const char*const argv[];
  696. X{ register char*chp,*chp2;register i;int suppmunreadable;
  697. X  ;{ int Deliverymode,mailfilter;char*fromwhom=0;
  698. X#define Presenviron    i
  699. X     Deliverymode=mailfilter=0;
  700. X     if(argc)                   /* sanity check, any argument at all? */
  701. X      { Deliverymode=strcmp(lastdirsep(argv0=argv[0]),procmailn);
  702. X    for(Presenviron=argc=0;(chp2=(char*)argv[++argc])&&*chp2=='-';)
  703. X       for(;;)                       /* processing options */
  704. X        { switch(*++chp2)
  705. X           { case VERSIONOPT:elog(VERSION);return EX_OK;
  706. X         case HELPOPT1:case HELPOPT2:elog(pmusage);elog(PM_HELP);
  707. X            elog(PM_QREFERENCE);return EX_USAGE;
  708. X         case PRESERVOPT:Presenviron=1;continue;
  709. X         case MAILFILTOPT:mailfilter=1;continue;
  710. X         case TEMPFAILOPT:retval=EX_TEMPFAIL;continue;
  711. X         case FROMWHOPT:case ALTFROMWHOPT:
  712. X            if(*++chp2)
  713. X               fromwhom=chp2;
  714. X            else if(chp2=(char*)argv[argc+1])
  715. X               argc++,fromwhom=chp2;
  716. X            else
  717. X               nlog("Missing name\n");
  718. X            break;
  719. X         case ARGUMENTOPT:
  720. X          { static const char*argv1[]={"",0};
  721. X            if(*++chp2)
  722. X               goto setarg;
  723. X            else if(chp2=(char*)argv[argc+1])
  724. X             { argc++;
  725. Xsetarg:               *argv1=chp2;restargv=argv1;crestarg=1;
  726. X             }
  727. X            else
  728. X               nlog("Missing argument\n");
  729. X            break;
  730. X          }
  731. X         case DELIVEROPT:
  732. X            if(!*(chp= ++chp2)&&!(chp=(char*)argv[++argc]))
  733. X             { nlog("Missing recipient\n");break;
  734. X             }
  735. X            else
  736. X             { Deliverymode=1;goto last_option;
  737. X             }
  738. X         case '-':
  739. X            if(!*chp2)
  740. X             { argc++;goto last_option;
  741. X             }
  742. X         default:nlog("Unrecognised options:");logqnl(chp2);
  743. X            elog(pmusage);elog("Processing continued\n");
  744. X         case '\0':;
  745. X           }
  746. X          break;
  747. X        }
  748. X      }
  749. Xlast_option:
  750. X     if(mailfilter)
  751. X      { if(Deliverymode)                 /* -d supersedes -m */
  752. X     { mailfilter=0;goto conflopt;
  753. X     }
  754. X    if(crestarg)                     /* -m will supersede -a */
  755. Xconflopt:  nlog("Conflicting options\n"),elog(pmusage);
  756. X      }
  757. X     if(!Presenviron)                     /* drop the environment */
  758. X      { const char**emax=(const char**)environ,*const*ep,*const*kp;
  759. X    static const char*const keepenv[]=KEEPENV;
  760. X    for(kp=keepenv;*kp;kp++)             /* preserve a happy few */
  761. X       for(i=strlen(*kp),ep=emax;chp2=(char*)*ep;ep++)
  762. X          if(!strncmp(*kp,chp2,i)&&(chp2[i]=='='||chp2[i-1]=='_'))
  763. X           { *emax++=chp2;break;
  764. X           }
  765. X    *emax=0;                        /* drop the rest */
  766. X      }
  767. X#ifdef LD_ENV_FIX
  768. X     ;{ const char**emax=(const char**)environ,**ep;
  769. X    static const char ld_[]="LD_";
  770. X    for(ep=emax;*emax;emax++);      /* find the end of the environment */
  771. X    while(*ep)
  772. X       if(!strncmp(ld_,*ep++,STRLEN(ld_)))           /* it starts with LD_ */
  773. X          *--ep= *--emax,*emax=0;            /* copy from the end */
  774. X      }
  775. X#endif /* LD_ENV_FIX */
  776. X     ;{ struct passwd*pass,*passinvk,spassinvk;int privs;
  777. X    uid_t euid=geteuid();
  778. X    if(passinvk=getpwuid(uid=getuid()))        /* save it by copying it */
  779. X       tmemmove(&spassinvk,passinvk,sizeof spassinvk),passinvk= &spassinvk;
  780. X    privs=1;gid=getgid();
  781. X    ;{ static const char*const trusted_ids[]=TRUSTED_IDS;
  782. X       if(*trusted_ids&&uid!=euid)
  783. X        { struct group*grp;const char*const*kp;
  784. X          if(passinvk)              /* check out the invoker's uid */
  785. X         for(chp2=passinvk->pw_name,kp=trusted_ids;*kp;)
  786. X            if(!strcmp(chp2,*kp++)) /* is it amongst the privileged? */
  787. X              goto privileged;
  788. X          if(grp=getgrgid(gid))          /* check out the invoker's gid */
  789. X        for(chp2=grp->gr_name,kp=trusted_ids;*kp;)
  790. X           if(!strcmp(chp2,*kp++))    /* is it among the privileged? */
  791. X              goto privileged;
  792. X          privs=0;
  793. X          if(Deliverymode)
  794. X        fromwhom=0;
  795. X        }
  796. X     }
  797. Xprivileged:
  798. X    endgrent();endpwent();umask(INIT_UMASK);fclose(stdout);rclose(STDOUT);
  799. X    if(0>opena(devnull))
  800. X     { writeerr(devnull);return EX_OSFILE;         /* couldn't open stdout */
  801. X     }
  802. X#ifdef console
  803. X    opnlog(console);
  804. X#endif
  805. X    setbuf(stdin,(char*)0);buf=malloc(linebuf);buf2=malloc(linebuf);
  806. X    thepid=getpid();
  807. X#ifdef SIGXCPU
  808. X    signal(SIGXCPU,SIG_IGN);signal(SIGXFSZ,SIG_IGN);
  809. X#endif
  810. X#ifdef SIGLOST
  811. X    signal(SIGLOST,SIG_IGN);
  812. X#endif
  813. X    signal(SIGPIPE,SIG_IGN);signal(SIGTERM,(void(*)())srequeue);
  814. X    signal(SIGINT,(void(*)())sbounce);signal(SIGHUP,(void(*)())sbounce);
  815. X    signal(SIGQUIT,(void(*)())slose);signal(SIGALRM,(void(*)())ftimeout);
  816. X    ultstr(0,(unsigned long)uid,buf);
  817. X    chp2=fromwhom?
  818. X     fromwhom:!passinvk||!*passinvk->pw_name?buf:passinvk->pw_name;
  819. X    ;{ time_t t;char*chp3;
  820. X       t=time((time_t*)0);chp3=ctime(&t);         /* the current time */
  821. X       strncpy(buf2,chp2,i=linebuf-strlen(chp3)-2);buf2[i]='\0';
  822. X       strcat(strcat(buf2," "),chp3);
  823. X     }
  824. X    ;{ size_t already;
  825. X       thebody=themail=
  826. X        malloc((already=STRLEN(From_)+strlen(buf2))+linebuf);
  827. X       filled=0;
  828. X       if(Deliverymode||fromwhom)  /* need to peek for a leading From_ ? */
  829. X        { char*rstart;int r;                 /* skip garbage */
  830. X          while(1==(r=rread(STDIN,themail,1))&&*themail=='\n');
  831. X          i=0;
  832. X          if(r>0&&STRLEN(From_)<=(i=rread(          /* is it a From_ line? */
  833. X           STDIN,(rstart=themail)+1,linebuf-2)+1)&&eqFrom_(themail))
  834. X         if(fromwhom||!privs)
  835. X            do                       /* discard From_ line */
  836. X               if(!i--&&(i=rread(STDIN,rstart=themail,linebuf-1)-1)<0)
  837. X            { i=0;break;
  838. X            }
  839. X            while(*rstart++!='\n');
  840. X         else                   /* leave the From_ line alone */
  841. X          { already=0;goto leaveFrom;
  842. X          }       /* move the read-ahead text beyond our From_ line */
  843. X          tmemmove(themail+already,rstart,i);strcpy(themail,From_);
  844. X          tmemmove(themail+STRLEN(From_),buf2,already-STRLEN(From_));
  845. XleaveFrom:    filled=already+i;
  846. X        }
  847. X     }
  848. X    readmail(0,0L);                  /* read in the mail completely */
  849. X    if(Deliverymode)
  850. X       do
  851. X        { chp2=chp;
  852. X#ifndef NO_USER_TO_LOWERCASE_HACK
  853. X          for(;*chp;chp++)          /* kludge recipient into lowercase */
  854. X         if((unsigned)*chp-'A'<='Z'-'A')
  855. X            *chp+='a'-'A';     /* getpwnam might be case sensitive */
  856. X#endif
  857. X          if(argv[++argc])              /* more than one recipient */
  858. X         if(pidchild=sfork())
  859. X          { if(forkerr(pidchild,procmailn)||waitfor(pidchild)!=EX_OK)
  860. X               retvl2=retval;
  861. X            pidchild=0;              /* loop for the next recipient */
  862. X          }
  863. X         else
  864. X          { thepid=getpid();
  865. X            while(argv[++argc]);    /* skip till end of command line */
  866. X          }
  867. X        }
  868. X       while(chp=(char*)argv[argc]);
  869. X    gargv=argv+argc;             /* save it for nextrcfile() */
  870. X    if(Deliverymode)
  871. X     { if(!(pass=getpwnam(chp2)))
  872. X        { nlog("Unknown user");logqnl(chp2);return EX_NOUSER;
  873. X        }
  874. X       if(passinvk&&passinvk->pw_uid==pass->pw_uid||euid==ROOT_uid)
  875. X          goto Setuser;
  876. X     }
  877. X    if(pass=passinvk)
  878. X      /*
  879. X       *    set preferred uid to the intended recipient
  880. X       */
  881. XSetuser: { gid=pass->pw_gid;uid=pass->pw_uid;
  882. X       setdef(lgname,chp= *pass->pw_name?pass->pw_name:buf);
  883. X       setdef(home,pass->pw_dir);
  884. X       if(euid==ROOT_uid)
  885. X          initgroups(chp,gid);
  886. X       endgrent();setdef(shell,*pass->pw_shell?pass->pw_shell:binsh);
  887. X     }
  888. X    else         /* user could not be found, set reasonable defaults */
  889. X      /*
  890. X       *    to prevent security holes, drop any privileges now
  891. X       */
  892. X     { setdef(lgname,buf);setdef(home,RootDir);setdef(shell,binsh);
  893. X       setids(uid,gid);
  894. X     }
  895. X    endpwent();
  896. X      }
  897. X     setdef(orgmail,systm_mbox);setdef(shellmetas,DEFshellmetas);
  898. X     setdef(shellflags,DEFshellflags);setdef(maildir,DEFmaildir);
  899. X     setdef(fdefault,DEFdefault);setdef(sendmail,DEFsendmail);
  900. X     setdef(lockext,DEFlockext);setdef(msgprefix,DEFmsgprefix);
  901. X     ;{ const char*const*kp;static const char*const prestenv[]=PRESTENV;
  902. X    for(kp=prestenv;*kp;)    /* preset or wipe some environment variables */
  903. X     { strcpy((char*)(sgetcp=buf2),*kp++);readparse(buf,sgetc,2);
  904. X       sputenv(buf);
  905. X     }
  906. X      }                 /* find out the name of our system lockfile */
  907. X     sgetcp=DEFdeflock+STRLEN(lockfile)+1;readparse(buf,sgetc,2);
  908. X     defdeflock=tstrdup(buf);strcpy(buf,chp=(char*)getenv(orgmail));
  909. X     buf[i=lastdirsep(chp)-chp]='\0';
  910. X     ;{ struct stat stbuf;               /* strip off the basename */
  911. X    sgid=gid;                    /* presumed innocent */
  912. X       /*
  913. X    *    do we need sgidness to access the mail-spool directory/files?
  914. X    */
  915. X    if(!stat(buf,&stbuf))
  916. X     { accspooldir=stbuf.st_mode&(S_IWGRP|S_IWOTH);
  917. X       if((uid!=stbuf.st_uid&&stbuf.st_gid==getegid()||(rc=rc_NOSGID,0))&&
  918. X        (stbuf.st_mode&(S_IWGRP|S_IXGRP|S_IWOTH))==(S_IWGRP|S_IXGRP))
  919. X        { umask(INIT_UMASK&~S_IRWXG);goto keepgid;      /* group-writeable */
  920. X        }
  921. X       else if(stbuf.st_mode&S_ISGID)
  922. Xkeepgid:      sgid=stbuf.st_gid;   /* keep the gid from the parent directory */
  923. X     }
  924. X       /*
  925. X    *    check if the default-mailbox-lockfile is owned by the
  926. X    *    recipient, if not, mark it for further investigation, it
  927. X    *    might need to be removed
  928. X    */
  929. X    for(;;)
  930. X     { ;{ int mboxstat;
  931. X          ;{ int goodlock;
  932. X         if(!(goodlock=lstat(defdeflock,&stbuf)||stbuf.st_uid==uid))
  933. X            ultoan((unsigned long)stbuf.st_ino,      /* i-node numbered */
  934. X             strchr(strcpy(buf+i,BOGUSprefix),'\0'));
  935. X        /*
  936. X         *    check if the original/default mailbox of the recipient
  937. X         *    exists, if it does, perform some security checks on it
  938. X         *    (check if it's a regular file, check if it's owned by
  939. X         *    the recipient), if something is wrong try and move the
  940. X         *    bogus mailbox out of the way, create the
  941. X         *    original/default mailbox file, and chown it to
  942. X         *    the recipient
  943. X         */
  944. X         if(lstat(chp,&stbuf))             /* stat the mailbox */
  945. X          { mboxstat= -(errno==EACCES);goto boglock;
  946. X          }                /* lockfile unrightful owner */
  947. X         mboxstat=1;
  948. X         if(!goodlock&&!(stbuf.st_mode&S_IWGRP))
  949. Xboglock:        if(!goodlock)          /* try & rename bogus lockfile */
  950. X               rename(defdeflock,buf);           /* out of the way */
  951. X           }
  952. X          if(mboxstat>0||mboxstat<0&&(setids(uid,gid),!lstat(chp,&stbuf)))
  953. X         if(!(stbuf.st_mode&S_IWUSR)||S_ISLNK(stbuf.st_mode)||
  954. X          (S_ISDIR(stbuf.st_mode)?
  955. X          !(stbuf.st_mode&S_IXUSR):stbuf.st_nlink!=1))
  956. X            goto bogusbox;        /* we only deliver to real files */
  957. X         else if(stbuf.st_uid!=uid)          /* recipient not owner */
  958. Xbogusbox:      { ultoan((unsigned long)stbuf.st_ino,      /* i-node numbered */
  959. X             strchr(strcpy(buf+i,BOGUSprefix),'\0'));        /* bogus */
  960. X            if(rename(chp,buf))       /* try and move it out of the way */
  961. X               goto fishy;  /* rename failed, something's fishy here */
  962. X          }                /* SysV type autoforwarding? */
  963. X         else if(Deliverymode&&stbuf.st_mode&(S_ISGID|S_ISUID))
  964. X          { nlog("Autoforwarding mailbox found\n");return EX_NOUSER;
  965. X          }
  966. X         else
  967. X            break;              /* everything is just fine */
  968. X        }
  969. X       if(!xcreat(chp,NORMperm,(time_t*)0,1)) /* can create the mailbox? */
  970. X          break;                  /* yes we could, fine, proceed */
  971. X       if(!lstat(chp,&stbuf))             /* anything in the way? */
  972. X          continue;                   /* check if it could be valid */
  973. X       setids(uid,gid);                   /* try some magic */
  974. X       if(!xcreat(chp,NORMperm,(time_t*)0,0))        /* try again */
  975. X          break;
  976. X       if(lstat(chp,&stbuf))              /* nothing in the way? */
  977. Xfishy:        { nlog("Couldn't create");logqnl(chp);sputenv(orgmail);
  978. X          sputenv(fdefault);break;                 /* so panic */
  979. X        }
  980. X     }                    /* bad news, be conservative */
  981. X    umask(INIT_UMASK);
  982. X      }
  983. X     suppmunreadable=verbose;
  984. X     if(!Deliverymode)                   /* not explicit delivery mode */
  985. X       /*
  986. X    *    really change the uid now, since we are not in explicit
  987. X    *    delivery mode
  988. X    */
  989. X      { setids(uid,gid);rc=rc_NOFILE;
  990. X    if(suppmunreadable=nextrcfile())  /* any rcfile on the command-line? */
  991. X#ifndef NO_COMSAT
  992. X       if(!getenv(scomsat))
  993. X          setdef(scomsat,DEFcomsat)           /* turn off comsat by default */
  994. X#endif
  995. X        ;
  996. X    else if(mailfilter)
  997. X     { nlog("Missing rcfile\n");return EX_NOINPUT;
  998. X     }
  999. X    while(chp=(char*)argv[argc])   /* interpret command line specs first */
  1000. X     { argc++;
  1001. X       if(!asenvcpy(chp)&&mailfilter)
  1002. X        { gargv= &nullp;
  1003. X          for(restargv=argv+argc;restargv[crestarg];crestarg++);
  1004. X          break;
  1005. X        }
  1006. X     }
  1007. X      }
  1008. X   }
  1009. X  ;{ int succeed,lastcond;
  1010. X     do                         /* main rcfile interpreter loop */
  1011. X      { alarm((unsigned)(alrmtime=0));                /* reset timeout */
  1012. X    if(rc<0)                     /* open new rc file */
  1013. X     { struct stat stbuf;
  1014. X      /*
  1015. X       *    if we happen to be still running as root, and the rcfile
  1016. X       *    is mounted on a secure NFS-partition, we might not be able
  1017. X       *    to access it, so check if we can stat it or don't need any
  1018. X       *    sgid privileges, if yes, drop all privs and set uid to
  1019. X       *    the recipient beforehand
  1020. X       */
  1021. X       goto findrc;
  1022. X       do
  1023. X        { if(suppmunreadable)      /* should we supress this message? */
  1024. Xfake_rc:     readerr(buf);
  1025. X          if(!nextrcfile())              /* not available? try the next */
  1026. X         goto nomore_rc;
  1027. X          suppmunreadable=0;
  1028. Xfindrc:          i=0;            /* should we keep the current directory? */
  1029. X          if(strchr(dirsep,*rcfile)||           /* absolute path? */
  1030. X           *rcfile==chCURDIR&&strchr(dirsep,rcfile[1])&&(i=1)) /* ./ pfx */
  1031. X         *buf='\0';        /* do not put anything in front then */
  1032. X          else
  1033. X         cat(tgetenv(home),MCDIRSEP);      /* prepend $HOME directory */
  1034. X          if(stat(strcat(buf,rcfile),&stbuf)?          /* accessible? */
  1035. X           rc==rc_NOSGID:stbuf.st_mode&S_IRUSR)   /* and owner-readable? */
  1036. X         setids(uid,gid);            /* then transmogrify */
  1037. X        }
  1038. X       while(0>bopen(buf));               /* try opening the rcfile */
  1039. X       if(i&&!didchd)      /* opened rcfile in the current directory? */
  1040. X        { didchd=1;*(chp=strcpy(buf2,maildir)+STRLEN(maildir))='=';
  1041. X          *++chp=chCURDIR;*++chp='\0';sputenv(buf2);
  1042. X        }
  1043. X      /*
  1044. X       *    OK, so now we have opened an rcfile, but for security reasons
  1045. X       *    we only accept it if it is owned by the recipient or if the
  1046. X       *    the directory it is in, is not world writeable
  1047. X       */
  1048. X       i= *(chp=lastdirsep(buf));
  1049. X       if(lstat(buf,&stbuf)||
  1050. X        (stbuf.st_uid!=uid&&(*chp='\0',stat(buf,&stbuf)||
  1051. X        (stbuf.st_mode&(S_IWOTH|S_IXOTH))==(S_IWOTH|S_IXOTH))))
  1052. X        { *chp=i;rclose(rc);nlog("Suspicious rcfile\n");goto fake_rc;
  1053. X        }
  1054. X      /*
  1055. X       *    set uid back to recipient in any case, since we might just
  1056. X       *    have opened his/her .procmailrc (don't remove these, since
  1057. X       *    the rcfile might have been created after the first stat)
  1058. X       */
  1059. X       *chp=i;yell("Rcfile:",buf);succeed=lastcond=0;setids(uid,gid);
  1060. X       firstchd();
  1061. X     }
  1062. X    unlock(&loclock);            /* unlock any local lockfile */
  1063. X    do skipspace();                      /* skip whitespace */
  1064. X    while(testb('\n'));
  1065. X    if(testb(':'))                       /* check for a recipe */
  1066. X     { int locknext;long tobesent;char*startchar;
  1067. X       static char flags[maxindex(exflags)];
  1068. X       ;{ int nrcond;
  1069. X          readparse(buf,getb,0);
  1070. X          ;{ char*chp3=chp;
  1071. X         nrcond=strtol(buf,&chp3,10);chp=chp3;
  1072. X           }
  1073. X          if(chp==buf)                 /* no number parsed */
  1074. X         nrcond= -1;
  1075. X          if(tolock)     /* clear temporary buffer for lockfile name */
  1076. X         free(tolock);
  1077. X          for(i=maxindex(flags);flags[i]=0,i--;);      /* clear the flags */
  1078. X          for(tolock=0,locknext=0;;)
  1079. X           { chp=skpspace(chp);
  1080. X         switch(i= *chp++)
  1081. X          { default:
  1082. X               if(!(chp2=strchr(exflags,i)))        /* a valid flag? */
  1083. X            { chp--;break;
  1084. X            }
  1085. X               flags[chp2-exflags]=1;             /* set the flag */
  1086. X            case '\0':
  1087. X               if(chp!=Tmnate)        /* if not the real end, skip */
  1088. X              continue;
  1089. X               break;
  1090. X            case ':':locknext=1;    /* yep, local lockfile specified */
  1091. X               if(*chp||++chp!=Tmnate)
  1092. X              tolock=tstrdup(chp),chp=strchr(chp,'\0')+1;
  1093. X          }
  1094. X         concatenate(chp);skipped(chp);break;    /* display leftovers */
  1095. X           }
  1096. X          if(nrcond<0)    /* assume appropriate default nr of conditions */
  1097. X         nrcond=!flags[ALSO_NEXT_RECIPE]&&!flags[ALSO_N_IF_SUCC];
  1098. X          startchar=themail;tobesent=thebody-themail;
  1099. X          if(flags[BODY_GREP])           /* what needs to be egrepped? */
  1100. X         if(flags[HEAD_GREP])
  1101. X            tobesent=filled;
  1102. X         else
  1103. X          { startchar=thebody;tobesent=filled-tobesent;goto noconcat;
  1104. X          }
  1105. X          concon(' ');
  1106. Xnoconcat:     i=flags[ALSO_NEXT_RECIPE]?lastcond:1;      /* init test value */
  1107. X          if(flags[ALSO_N_IF_SUCC])
  1108. X         i=lastcond&&succeed;    /* only if the last recipe succeeded */
  1109. X          while(skipspace(),nrcond--,testb('*')||nrcond>=0)
  1110. X           { skipspace();getlline(buf2);        /* any conditions (left) */
  1111. X         for(chp=strchr(buf2,'\0');--chp>=buf2;)
  1112. X          { switch(*chp)      /* strip off whitespace at the end */
  1113. X             { case ' ':case '\t':*chp='\0';continue;
  1114. X             }
  1115. X            break;
  1116. X          }
  1117. X         if(i)                 /* check out all conditions */
  1118. X          { int negate=0;
  1119. X            for(chp=buf2+1;;strcpy(buf2,buf))
  1120. X             { switch(*(sgetcp=buf2))
  1121. X            { default:chp--;     /* no special character, backup */
  1122. X              case '\\':
  1123. X               { int or_nocase;    /* case-distinction override */
  1124. X                 static const struct {const char*regkey,*regsubst;}
  1125. X                  *regsp,regs[]=
  1126. X                   { {FROMDkey,FROMDsubstitute},
  1127. X                 {TOkey,TOsubstitute},
  1128. X                 {FROMMkey,FROMMsubstitute},
  1129. X                 {0,0}
  1130. X                   };
  1131. X                 ;{ char*tg;
  1132. X                for(or_nocase=0,tg=chp2=chp;;tg++,chp2++)
  1133. X                 { switch(*tg= *chp2)
  1134. X                    { case '\n':
  1135. X                     if(or_nocase==1)
  1136. X                        tg-=2;   /* throw out \ \n pairs */
  1137. X                     or_nocase=2;continue;
  1138. X                      case '\\':or_nocase=1;continue;
  1139. X                      case ' ':case '\t':
  1140. X                     if(or_nocase==2)    /* skip leading */
  1141. X                      { tg--;continue;     /* whitespace */
  1142. X                      }
  1143. X                      default:or_nocase=0;continue;
  1144. X                      case '\0':;
  1145. X                    }
  1146. X                   break;
  1147. X                 }
  1148. X                  }
  1149. X                 or_nocase=0;goto jinregs;
  1150. X                 do           /* find special keyword in regexp */
  1151. X                if((chp2=strstr(chp,regsp->regkey))&&
  1152. X                 (chp2==buf2||chp2[-1]!='\\'))     /* escaped? */
  1153. X                 { size_t lregs,lregk;           /* no, so */
  1154. X                   lregk=strlen(regsp->regkey); /* insert it */
  1155. X                   tmemmove(
  1156. X                    chp2+(lregs=strlen(regsp->regsubst)),
  1157. X                    chp2+lregk,strlen(chp2)-lregk+1);
  1158. X                   tmemmove(chp2,regsp->regsubst,lregs);
  1159. X                   if(regsp==regs)       /* daemon regexp? */
  1160. X                      or_nocase=1;   /* no case sensitivity! */
  1161. Xjinregs:               regsp=regs;    /* start over and look again */
  1162. X                 }
  1163. X                else
  1164. X                   regsp++;             /* next keyword */
  1165. X                 while(regsp->regkey);
  1166. X                 i=!!egrepin(chp,startchar,tobesent, /* egrep it */
  1167. X                  or_nocase?0:flags[DISTINGUISH_CASE]);
  1168. X                 break;
  1169. X               }
  1170. X              case '$':*buf2='"';readparse(buf,sgetc,2);continue;
  1171. X              case '!':negate^=1;strcpy(buf,chp);continue;
  1172. X              case '?':pwait=2;metaparse(chp);inittmout(buf);
  1173. X                  ignwerr=1;i=!pipin(buf,startchar,tobesent);
  1174. X                  strcpy(buf2,buf);break;
  1175. X              case '>':case '<':readparse(buf,sgetc,2);
  1176. X                 ;{ char*chp3=chp;
  1177. X                i=strtol(buf+1,&chp3,10);chp=chp3;
  1178. X                  }
  1179. X                 i='<'==*buf?filled<i:filled>i;
  1180. X                 skipped(skpspace(chp));strcpy(buf2,buf);
  1181. X            }                    /* leftovers */
  1182. X               break;
  1183. X             }
  1184. X            i^=negate;
  1185. X            if(verbose)         /* not entirely correct, but it will do */
  1186. X             { nlog(i?"M":"No m");elog("atch on");
  1187. X               if(negate)
  1188. X              elog(" !");
  1189. X               logqnl(buf2);
  1190. X             }
  1191. X          }
  1192. X           }
  1193. X        }
  1194. X       if(!flags[ALSO_NEXT_RECIPE]&&!flags[ALSO_N_IF_SUCC])
  1195. X          lastcond=i;           /* save the outcome for posterity */
  1196. X       startchar=themail;tobesent=filled;        /* body, header or both? */
  1197. X       if(flags[PASS_HEAD])
  1198. X        { if(!flags[PASS_BODY])
  1199. X         tobesent=thebody-themail;
  1200. X        }
  1201. X       else if(flags[PASS_BODY])
  1202. X          tobesent-=(startchar=thebody)-themail;
  1203. X       chp=strchr(strcpy(buf,tgetenv(sendmail)),'\0');succeed=sh=0;
  1204. X       pwait=flags[WAIT_EXIT]|flags[WAIT_EXIT_QUIET]<<1;
  1205. X       ignwerr=flags[IGNORE_WRITERR];Stdout=0;skipspace();
  1206. X       if(i)
  1207. X          concon('\n');
  1208. Xprogrm:       if(testb('!'))                 /* forward the mail */
  1209. X        { readparse(chp+1,getb,0);
  1210. X          if(i)
  1211. X         goto forward;
  1212. X        }
  1213. X       else if(testb('|'))                    /* pipe the mail */
  1214. X        { getlline(buf2);             /* get the command to start */
  1215. X          if(i)
  1216. X           { metaparse(buf2);
  1217. Xforward:     if(locknext)
  1218. X          { if(!tolock)       /* an explicit lockfile specified already */
  1219. X             { *buf2='\0';  /* find the implicit lockfile ('>>name') */
  1220. X               for(chp=buf;i= *chp++;)
  1221. X              if(i=='>'&&*chp=='>')
  1222. X               { chp=pstrspn(chp+1," \t");
  1223. X                 tmemmove(buf2,chp,i=strcspn(chp,EOFName));
  1224. X                 buf2[i]='\0';
  1225. X                 if(sh)     /* expand any environment variables */
  1226. X                  { chp=tstrdup(buf);sgetcp=buf2;
  1227. X                readparse(buf,sgetc,0);strcpy(buf2,buf);
  1228. X                strcpy(buf,chp);free(chp);
  1229. X                  }
  1230. X                 break;
  1231. X               }
  1232. X               if(!*buf2)
  1233. X            { nlog("Couldn't determine implicit lockfile from");
  1234. X              logqnl(buf);
  1235. X            }
  1236. X               else if(!strcmp(buf2,devnull))    /* locking /dev/null */
  1237. X              goto noloclock;           /* would be silly */
  1238. X             }
  1239. X            lcllock();
  1240. X            if(!pwait)        /* try and protect the user from his */
  1241. X               pwait=2;               /* blissful ignorance :-) */
  1242. X          }
  1243. Xnoloclock:     inittmout(buf);asgnlastf=1;
  1244. X         if(flags[FILTER])
  1245. X          { if(startchar==themail&&tobesent!=filled)  /* if only 'h' */
  1246. X             { if(!pipthrough(buf,startchar,tobesent))
  1247. X              succeed=1,readmail(1,tobesent);
  1248. X             }
  1249. X            else if(!pipthrough(buf,startchar,tobesent))
  1250. X               succeed=1,filled=startchar-themail,readmail(0,0L);
  1251. X          }
  1252. X         else if(Stdout)          /* capturing stdout again? */
  1253. X          { if(!pipthrough(buf,startchar,tobesent))
  1254. X               succeed=1,postStdout();      /* only parse if no errors */
  1255. X          }
  1256. X         else if(!pipin(buf,startchar,tobesent)&& /* regular program */
  1257. X          (succeed=1,!flags[CONTINUE]))
  1258. X            goto mailed;
  1259. X           }
  1260. X        }
  1261. X       else           /* dump the mail into a mailbox file or directory */
  1262. X        { if(flags[FILTER])
  1263. X         flags[FILTER]=0,nlog("Extraneous filter-flag ignored\n");
  1264. X          if(chp=gobenv(buf))       /* can it be an environment name? */
  1265. X           { if(skipspace())
  1266. X            chp++;           /* keep pace with argument breaks */
  1267. X         if(testb('='))              /* is it really an assignment? */
  1268. X          { int c;
  1269. X            *chp++='=';*chp='\0';
  1270. X            if(skipspace())
  1271. X               chp++;
  1272. X            ungetb(c=getb());
  1273. X            switch(c)
  1274. X             { case '!':case '|':          /* ok, it's a pipe */
  1275. X              if(i)
  1276. X                 primeStdout();
  1277. X              goto progrm;
  1278. X             }
  1279. X          }
  1280. X           }
  1281. X          else
  1282. X         chp=strchr(buf,'\0');                 /* find the end */
  1283. X          readparse(chp,getb,0);
  1284. X          if(i)
  1285. X           { strcpy(buf2,buf);
  1286. X         if(locknext)
  1287. X            lcllock();             /* write to a file or directory */
  1288. X         if(dump(deliver(buf,strchr(buf,'\0')+1),startchar,tobesent)&&
  1289. X          !ignwerr)
  1290. X            writeerr(buf);
  1291. X         else if(succeed=1,!flags[CONTINUE])
  1292. X            goto mailed;
  1293. X           }
  1294. X        }
  1295. X     }
  1296. X    else if(testb('#'))                   /* no comment :-) */
  1297. X       getbl(buf);
  1298. X    else                    /* then it must be an assignment */
  1299. X     { if(!(chp=gobenv(buf)))
  1300. X        { if(!*buf)                    /* skip a word first */
  1301. X         getbl(buf);                      /* then a line */
  1302. X          skipped(buf);continue;            /* display leftovers */
  1303. X        }
  1304. X       skipspace();
  1305. X       if(testb('='))               /* removal or assignment? */
  1306. X          *chp='=',readparse(++chp,getb,1);
  1307. X       else
  1308. X          *++chp='\0';             /* throw in a second terminator */
  1309. X       sputenv(buf);chp[-1]='\0';asenv(chp);
  1310. X     }
  1311. X      }
  1312. X     while(rc<0||!testb(EOF)||poprc());            /* main interpreter loop */
  1313. X   }
  1314. Xnomore_rc:
  1315. X  ;{ int succeed;
  1316. X     concon('\n');succeed=0;
  1317. X     if(*(chp=(char*)tgetenv(fdefault)))             /* DEFAULT set? */
  1318. X      { setuid(uid);firstchd();
  1319. X    if(strcmp(chp,devnull))                 /* don't lock /dev/null */
  1320. X       asenvcpy((char*)DEFdeflock);                /* implicit lock */
  1321. X    if(dump(deliver(chp,(char*)0),themail,filled))          /* default */
  1322. X       writeerr(buf);
  1323. X    else
  1324. X       succeed=1;
  1325. X      }
  1326. X     if(!succeed&&*(chp=(char*)tgetenv(orgmail)))      /* if all else failed */
  1327. X    if(dump(deliver(chp,(char*)0),themail,filled))          /* don't panic */
  1328. X       writeerr(buf);                  /* try the last resort */
  1329. X    else
  1330. X       succeed=1;
  1331. X     if(succeed)                     /* should we panic now? */
  1332. Xmailed: retval=EX_OK;              /* we're home free, mail delivered */
  1333. X   }
  1334. X  unlock(&loclock);terminate();
  1335. X}
  1336. X
  1337. XeqFrom_(a)const char*const a;
  1338. X{ return!strncmp(a,From_,STRLEN(From_));
  1339. X}
  1340. END_OF_FILE
  1341. if test 25195 -ne `wc -c <'procmail/src/procmail.c'`; then
  1342.     echo shar: \"'procmail/src/procmail.c'\" unpacked with wrong size!
  1343. fi
  1344. # end of 'procmail/src/procmail.c'
  1345. fi
  1346. echo shar: End of archive 10 \(of 11\).
  1347. cp /dev/null ark10isdone
  1348. MISSING=""
  1349. for I in 1 2 3 4 5 6 7 8 9 10 11 ; do
  1350.     if test ! -f ark${I}isdone ; then
  1351.     MISSING="${MISSING} ${I}"
  1352.     fi
  1353. done
  1354. if test "${MISSING}" = "" ; then
  1355.     echo You have unpacked all 11 archives.
  1356.     rm -f ark[1-9]isdone ark[1-9][0-9]isdone
  1357. else
  1358.     echo You still need to unpack the following archives:
  1359.     echo "        " ${MISSING}
  1360. fi
  1361. ##  End of shell archive.
  1362. exit 0
  1363. -- 
  1364. Sincerely,                                  berg@pool.informatik.rwth-aachen.de
  1365.            Stephen R. van den Berg (AKA BuGless).    berg@physik.tu-muenchen.de
  1366.  
  1367. "Always look on the bright side of life!"
  1368.  
  1369. exit 0 # Just in case...
  1370.