home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / misc / volume43 / procmail / part03 < prev    next >
Encoding:
Internet Message Format  |  1994-07-05  |  54.1 KB

  1. From: berg@pool.informatik.rwth-aachen.de (Stephen R. van den Berg)
  2. Newsgroups: comp.sources.misc
  3. Subject: v43i058:  procmail - mail processing package v3.03, Part03/10
  4. Date: 5 Jul 1994 20:49:42 -0500
  5. Organization: Sterling Software
  6. Sender: kent@sparky.sterling.com
  7. Approved: kent@sparky.sterling.com
  8. Message-ID: <2vd2jm$i5u@sparky.sterling.com>
  9. X-Md4-Signature: 10287c58589e11102cb71e36609a3c5c
  10.  
  11. Submitted-by: berg@pool.informatik.rwth-aachen.de (Stephen R. van den Berg)
  12. Posting-number: Volume 43, Issue 58
  13. Archive-name: procmail/part03
  14. Environment: sendmail, ZMailer, smail, MMDF, mailsurr, UNIX, POSIX
  15. Supersedes: procmail: Volume 38, Issue 19-31
  16.  
  17. #! /bin/sh
  18. # This is a shell archive.  Remove anything before this line, then feed it
  19. # into a shell via "sh file" or similar.  To overwrite existing files,
  20. # type "sh file -c".
  21. # Contents:  procmail-3.03/man/procmailrc.man
  22. #   procmail-3.03/src/formail.c procmail-3.03/src/mailfold.h
  23. # Wrapped by kent@sparky on Tue Jul  5 20:42:12 1994
  24. PATH=/bin:/usr/bin:/usr/ucb:/usr/local/bin:/usr/lbin:$PATH ; export PATH
  25. echo If this archive is complete, you will see the following message:
  26. echo '          "shar: End of archive 3 (of 10)."'
  27. if test -f 'procmail-3.03/man/procmailrc.man' -a "${1}" != "-c" ; then 
  28.   echo shar: Will not clobber existing file \"'procmail-3.03/man/procmailrc.man'\"
  29. else
  30.   echo shar: Extracting \"'procmail-3.03/man/procmailrc.man'\" \(21444 characters\)
  31.   sed "s/^X//" >'procmail-3.03/man/procmailrc.man' <<'END_OF_FILE'
  32. XPlease read the README file in this directory first.
  33. X.ex
  34. X.Id $Id: procmailrc.man,v 1.41 1994/05/26 14:12:11 berg Exp $
  35. X.TH PROCMAILRC 5 \*(Dt BuGless
  36. X.na
  37. X.SH NAME
  38. Xprocmailrc \- procmail rcfile
  39. X.SH SYNOPSIS
  40. X.B $HOME/@PROCMAILRC@
  41. X.ad
  42. X.SH DESCRIPTION
  43. XFor a quick start, see
  44. X.B NOTES
  45. Xat the end of the
  46. X.BR procmail (1)
  47. Xman page.
  48. X.PP
  49. XThe rcfile can contain a mixture of environment variable assignments (some
  50. Xof which have special meanings to procmail), and recipes.  In their most
  51. Xsimple appearance, the recipes are simply one line regular expressions
  52. Xthat are searched for in the header of the arriving mail, the first recipe
  53. Xthat matches is used to determine where the mail has to go (usually a file).
  54. X.PP
  55. XIf a matching recipe does not specify any special flags (like `@FILTER@' or
  56. X`@CONTINUE@') and the recipe is successful (i.e. no write failures or other
  57. Xcalamities), then processing of the rcfile will cease at this point, and
  58. Xprocmail will consider the mail to have been delivered.
  59. X.PP
  60. XThis enables you to presort your mail extremely straightforward into several
  61. Xmailfolders.  Bear in mind though that the mail can arrive concurrently in
  62. Xthese mailfolders (if several procmail programs happen to run at the same time,
  63. Xnot unlikely if a lot of mail arrives), to make sure this does not result in a
  64. Xmess, proper use of lockfiles is highly recommended.
  65. X.PP
  66. XThe environment variable
  67. X.B assignments
  68. Xand
  69. X.B recipes
  70. Xcan be freely intermixed in the rcfile. If any environment variable has
  71. Xa special meaning to procmail, it will be used appropriately the moment
  72. Xit is parsed. (i.e. you can change the current directory whenever you
  73. Xwant by specifying a new
  74. X.BR MAILDIR ,
  75. Xswitch lockfiles by specifying a new
  76. X.BR LOCKFILE ,
  77. Xchange the umask at any time, etc., the possibilities are endless :-).
  78. X.PP
  79. XThe assignments and substitutions of these environment variables are handled
  80. Xexactly like in
  81. X.BR sh (1)
  82. X(that includes all possible quotes and escapes),
  83. Xwith the added bonus that blanks around the '=' sign are ignored and that,
  84. Xif an environment variable appears without a trailing '=', it will be
  85. Xremoved from the environment.  Any program in backquotes started by procmail
  86. Xwill have the entire mail at its stdin.
  87. X.PP
  88. X.SS Comments
  89. XA word beginning with # and all the following characters up to a NEWLINE
  90. Xare ignored.
  91. X.SS Recipes
  92. X.PP
  93. XA line starting with ':' marks the beginning of a recipe.  It has the
  94. Xfollowing format:
  95. X.Sx 3
  96. X: [\fInumber\fP] [\fIflags\fP] [ : [\fIlocallockfile\fP] ]
  97. X<zero or more conditions (one per line)>
  98. X<exactly one action line>
  99. X.Ex
  100. XThe
  101. X.I number
  102. Xis optional (defaults to 1) and specifies the number of conditions that
  103. Xfollow the first line of the recipe.  Conditions are complete lines that are
  104. Xpassed on to the internal egrep
  105. X.BR literally ,
  106. Xexcept for leading and trailing whitespace.  If you start every condition
  107. Xline with an `*', you do not need to specify
  108. X.IR number .
  109. XWhitespace after the leading `*' are ignored.  The safest way would be
  110. Xto specify
  111. X.I number
  112. Xto be zero in that case (to avoid problems when you have no conditions, but
  113. Xprocmail expects one).
  114. XThese regular expressions are
  115. X.B completely
  116. Xcompatible to the normal
  117. X.BR egrep (1)
  118. Xregular expressions.
  119. X.PP
  120. XConditions are anded; if
  121. X.I number
  122. Xis zero, then the condition is always true and no conditions are expected
  123. Xnext.
  124. X.PP
  125. X.I Flags
  126. Xcan be any of the following:
  127. X.TP 0.5i
  128. X.B @HEAD_GREP@
  129. XEgrep the header (default).
  130. X.TP
  131. X.B @BODY_GREP@
  132. XEgrep the body.
  133. X.TP
  134. X.B @DISTINGUISH_CASE@
  135. XTell the internal egrep to distinguish between upper and lower case (contrary
  136. Xto the default which is to ignore case).
  137. X.TP
  138. X.B @ALSO_NEXT_RECIPE@
  139. XThis recipe will depend on the last preceding recipe (on the current
  140. Xblock-nesting level) without the `@ALSO_NEXT_RECIPE@' or `@ALSO_N_IF_SUCC@'
  141. Xflag.  This allows you to chain actions that depend on a common condition.
  142. XThe number of conditions that are expected to follow default to none.
  143. X.TP
  144. X.B @ALSO_N_IF_SUCC@
  145. XHas the same meaning as the `@ALSO_NEXT_RECIPE@' flag, but will depend on the
  146. X.I successful
  147. Xcompletion of the immediately preceding recipe as well.
  148. X.Tp
  149. X.B @ELSE_DO@
  150. XThis recipe only executes if the immediately preceding recipe was not
  151. Xexecuted.  Execution of this recipe also disables any immediately
  152. Xfollowing recipes with the '@ELSE_DO@' flag.  This allows you to specify
  153. X`else if' actions.
  154. XThe number of conditions that are expected to follow default to none.
  155. X.Tp
  156. X.B @ERROR_DO@
  157. XThis recipe only executes if the immediately preceding recipe failed.
  158. XThis allows you to specify `error' actions.
  159. XThe number of conditions that are expected to follow default to none.
  160. X.TP
  161. X.B @PASS_HEAD@
  162. XFeed the header to the pipe (default).
  163. X.TP
  164. X.B @PASS_BODY@
  165. XFeed the body to the pipe (default).
  166. X.TP
  167. X.B @FILTER@
  168. XConsider the pipe as a filter.
  169. X.TP
  170. X.B @CONTINUE@
  171. XContinue processing the rcfile even if this recipe matches (not needed
  172. Xwhen `@FILTER@' is specified).  On nesting blocks this will clone the
  173. Xrunning procmail process (lockfiles can not be inherited).
  174. X.TP
  175. X.B @WAIT_EXIT@
  176. XWait for the filter or program to finish and check its exitcode (normally
  177. Xignored); if the filter is unsuccessful, then the text will not have been
  178. Xfiltered.
  179. X.TP
  180. X.B @WAIT_EXIT_QUIET@
  181. XHas the same meaning as the `@WAIT_EXIT@' flag, but will suppress any
  182. X`Program failure' message.
  183. X.TP
  184. X.B @IGNORE_WRITERR@
  185. XIgnore any write errors on this recipe (i.e. usually due to an early closed
  186. Xpipe).
  187. X.PP
  188. XThere are some special conditions you can use that are not straight regular
  189. Xexpressions.  To select them, the first character of the condition must
  190. Xbe a:
  191. X.TP 0.5i
  192. X.B !
  193. XInvert the condition.
  194. X.TP
  195. X.B $
  196. XEvaluate the remainder according to
  197. X.BR sh (1)
  198. Xsubstitution rules inside double quotes, skip leading whitespace,
  199. Xthen reparse it.
  200. X.TP
  201. X.B ?
  202. XUse the exitcode of the specified program.
  203. X.TP
  204. X.B <
  205. XCheck if the total length of the mail is shorter than the specified (in
  206. Xdecimal) number of bytes.
  207. X.TP
  208. X.B >
  209. XAnalogous to '<'.
  210. X.TP
  211. X.B \e
  212. XTo quote any of the above at the start of the line.
  213. X.SS "Local lockfile"
  214. X.PP
  215. XIf you put a second (trailing) ':' on the first recipe line, then procmail
  216. Xwill use a
  217. X.I locallockfile
  218. X(for this recipe only).  You can optionally specify the locallockfile
  219. Xto use; if you don't however, procmail will use the destination filename
  220. X(or the filename following the first '>>') and will append $LOCKEXT to it.
  221. X.SS "Recipe action line"
  222. X.PP
  223. XThe action line can start with the following characters:
  224. X.TP
  225. X.B !
  226. XForwards to all the specified mail addresses.
  227. X.TP
  228. X.B |
  229. XStarts the specified program, possibly in $SHELL if any
  230. Xof the characters $SHELLMETAS are spotted.  You can optionally prepend this
  231. Xpipe symbol with
  232. X.IR variable= ,
  233. Xwhich will cause stdout of the program to be captured in the environment
  234. X.IR variable .
  235. XIf you specify just this pipe symbol, without any program, then procmail will
  236. Xpipe the mail to stdout.
  237. X.TP
  238. X.B {
  239. XFollowed by at least one space, tab or newline will mark the start of a
  240. Xnesting block.  Everything up till the next closing brace will depend on
  241. Xthe conditions specified for this recipe.  Unlimited nesting is permitted.
  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 HOST
  283. XThe current hostname
  284. X.TP
  285. X.B COMSAT
  286. X\&@DEFcomsat@
  287. X.br
  288. X(If an rcfile is specified on the command line)
  289. X.TP
  290. X.B LOCKEXT
  291. X\&@DEFlockext@@PRESTENV@@LD_ENV_FIX@
  292. X.SS Environment
  293. X.PP
  294. XBefore you get lost in the multitude of environment variables, keep in mind
  295. Xthat all of them have reasonable defaults.
  296. X.TP 1.2i
  297. X.B MAILDIR
  298. XCurrent directory while procmail is executing (that means that all paths
  299. Xare relative to $MAILDIR).
  300. X.TP
  301. X.B DEFAULT
  302. XDefault
  303. X.B mailbox
  304. Xfile (if not told otherwise, procmail will dump mail in this mailbox).
  305. XProcmail will automatically use $DEFAULT$LOCKEXT as lockfile prior to writing
  306. Xto this mailbox.
  307. X.TP
  308. X.B LOGFILE
  309. XThis file will also contain any error or diagnostic messages from procmail
  310. X(normally none :-) or any other programs started by procmail.  If this file
  311. Xis not specified, any diagnostics or error messages will
  312. X@pconsole@@console@@aconsole@
  313. XSee also
  314. X.BR LOGABSTRACT .
  315. X.TP
  316. X.B VERBOSE
  317. XYou can turn on
  318. X.I extended diagnostics
  319. Xby setting this variable to `yes' or `on', to turn it off again set it to `no'
  320. Xor `off'.
  321. X.TP
  322. X.B LOGABSTRACT
  323. XJust before procmail exits it logs an abstract of the delivered message in
  324. X$LOGFILE showing the `@FROM@' and `Subject:' fields of the header, what folder
  325. Xit finally went to and how long (in bytes) the message was.  By setting this
  326. Xvariable to `no', generation of this abstract is suppressed.
  327. X.TP
  328. X.B LOG
  329. XAnything assigned to this variable will be appended to $LOGFILE.
  330. X.TP
  331. X.B ORGMAIL
  332. XUsually the system mailbox (\fBOR\fPi\fBG\fPinal \fBMAIL\fPbox).  If, for
  333. Xsome obscure reason (like `\fBfilesystem full\fP') the mail could not be
  334. Xdelivered, then this mailbox will be the last resort.  If procmail
  335. Xfails to save the mail in here (deep, deep trouble :-), then the mail
  336. Xwill bounce back to the sender.
  337. X.TP
  338. X.B LOCKFILE
  339. XGlobal semaphore file.  If this file already exists, procmail
  340. Xwill wait until it has gone before proceeding, and will create it itself
  341. X(cleaning it up when ready, of course).  If more than one
  342. X.I lockfile
  343. Xare specified, then the previous one will be removed before trying to create
  344. Xthe new one.  The use of a global lockfile is discouraged, whenever possible
  345. Xuse locallockfiles (on a per recipe basis) instead.
  346. X.TP
  347. X.B LOCKEXT
  348. XDefault extension that is appended to a destination file to determine
  349. Xwhat local
  350. X.I lockfile
  351. Xto use (only if turned on, on a per-recipe basis).
  352. X.TP
  353. X.B LOCKSLEEP
  354. XNumber of seconds procmail will sleep before retrying on a
  355. X.I lockfile
  356. X(if it already existed); if not specified, it defaults to @DEFlocksleep@
  357. Xseconds.
  358. X.TP
  359. X.B LOCKTIMEOUT
  360. XNumber of seconds that have to have passed since a
  361. X.I lockfile
  362. Xwas last modified/created before procmail decides that this must be an
  363. Xerroneously leftover lockfile that can be removed by force now.  If zero,
  364. Xthen no timeout will be used and procmail will wait forever until the
  365. Xlockfile is removed; if not specified, it defaults to @DEFlocktimeout@ seconds.
  366. XThis variable is useful to prevent indefinite hangups of
  367. X.BR sendmail /procmail.
  368. XProcmail is immune to clock skew across machines.
  369. X.TP
  370. X.B TIMEOUT
  371. XNumber of seconds that have to have passed before procmail decides that
  372. Xsome child it started must be hanging.  The offending program will receive
  373. Xa TERMINATE signal from procmail, and processing of the rcfile will continue.
  374. XIf zero, then no timeout will be used and procmail will wait forever until the
  375. Xchild has terminated; if not specified, it defaults to @DEFtimeout@ seconds.
  376. X.TP
  377. X.B MSGPREFIX
  378. XFilename prefix that is used when delivering to a directory (not used when
  379. Xdelivering to an MH directory).
  380. X.TP
  381. X.B HOST
  382. XIf this is not the
  383. X.I hostname
  384. Xof the machine, processing of the current
  385. X.I rcfile
  386. Xwill immediately cease. If other rcfiles were specified on the
  387. Xcommand line, processing will continue with the next one.  If all rcfiles
  388. Xare exhausted, the program will terminate, but will not generate an error
  389. X(i.e. to the mailer it will seem that the mail has been delivered).
  390. X.TP
  391. X.B UMASK
  392. XThe name says it all (if it doesn't, then forget about this one :-).
  393. XAnything assigned to UMASK is taken as an
  394. X.B octal
  395. Xnumber.  If not specified, the umask defaults to @INIT_UMASK@.  If the umask
  396. Xpermits o+x, all the mailboxes procmail delivers to directly will receive
  397. Xan o+x mode change.  This can be used to check if new mail arrived.
  398. X.TP
  399. X.B SHELLMETAS
  400. XIf any of the characters in SHELLMETAS appears in the line specifying
  401. Xa filter or program, the line will be fed to $SHELL
  402. Xinstead of being executed directly.
  403. X.TP
  404. X.B SHELLFLAGS
  405. XAny invocation of $SHELL will be like:
  406. X.br
  407. X"$SHELL" "$SHELLFLAGS" "$*";
  408. X.TP
  409. X.B SENDMAIL
  410. XIf you're not using the
  411. X.I forwarding
  412. Xfacility don't worry about this one.  It specifies the program being
  413. Xcalled to forward any mail.
  414. X.br
  415. XIt gets invoked as: "$SENDMAIL" "$@";
  416. X.TP
  417. X.B NORESRETRY
  418. XNumber of retries that are to be made if any `\fBprocess table full\fP',
  419. X`\fBfile table full\fP', `\fBout of memory\fP' or
  420. X`\fBout of swap space\fP' error should occur.  If this number is negative,
  421. Xthen procmail will retry indefinitely; if not specified, it defaults to
  422. X@DEFnoresretry@ times.  The retries occur with a $SUSPEND second interval.  The
  423. Xidea behind this is, that if e.g. the
  424. X.I swap
  425. X.I space
  426. Xhas been exhausted or the
  427. X.I process
  428. X.I table
  429. Xis full, usually several other programs will either detect this as well
  430. Xand abort or crash 8-), thereby freeing valuable
  431. X.I resources
  432. Xfor procmail.
  433. X.TP
  434. X.B SUSPEND
  435. XNumber of seconds that procmail will pause if it has to wait for something
  436. Xthat is currently unavailable (memory, fork, etc.); if not specified, it will
  437. Xdefault to @DEFsuspend@ seconds.  See also:
  438. X.BR LOCKSLEEP .
  439. X.TP
  440. X.B LINEBUF
  441. XLength of the internal line buffers, cannot be set smaller than @MINlinebuf@.
  442. XAll lines read from the
  443. X.I rcfile
  444. Xshould not exceed $LINEBUF characters before and after expansion.  If not
  445. Xspecified, it defaults to @DEFlinebuf@.  This limit, of course, does
  446. X.I not
  447. Xapply to the mail itself, which can have arbitrary line lengths, or could
  448. Xbe a binary file for that matter.
  449. X.TP
  450. X.B DELIVERED
  451. XIf set to `yes' procmail will pretend (to the mail agent) the mail
  452. Xhas been delivered.  If mail cannot be delivered after meeting this
  453. Xassignment (to `yes'), the mail will be lost (i.e. it will not bounce).
  454. X.TP
  455. X.B TRAP
  456. XWhen procmail terminates it will execute the contents of this variable.
  457. XA copy of the mail can be read from stdin.  Any output produced by this
  458. Xcommand will be appended to $LOGFILE.  Possible uses for TRAP are: removal
  459. Xof temporary files, logging customised abstracts, etc.  See also
  460. X.B EXITCODE
  461. Xand
  462. X.BR LOGABSTRACT .
  463. X.Tp
  464. X.B EXITCODE
  465. XWhen procmail terminates and this variable has been set to a positive numeric
  466. Xvalue, procmail will use this as the exitcode.  If this variable is set but
  467. Xempty, procmail will set the exitcode to whatever the
  468. X.B TRAP
  469. Xprogram returns.
  470. XIf this variable has not been set, procmail will set it shortly before calling
  471. Xup the
  472. X.B TRAP
  473. Xprogram.
  474. X.TP
  475. X.B LASTFOLDER
  476. XThis variable is assigned to by procmail whenever it is delivering
  477. Xto a folder or program.  It always contains the name of the last folder
  478. X(or program) procmail delivered to.
  479. X.Tp
  480. X.B SHIFT
  481. XAssigning a positive value to this variable has the same effect as
  482. Xthe `shift' command in
  483. X.BR sh (1).
  484. XThis command is most useful to extract extra arguments passed to procmail
  485. Xwhen acting as a generic mailfilter.
  486. X.TP
  487. X.B INCLUDERC
  488. XNames an rcfile (relative to the current directory) which will be included
  489. Xhere as if it were part of the current rcfile.  Unlimited nesting is
  490. Xpermitted.
  491. X.TP
  492. X.B COMSAT
  493. X.BR Comsat (8)/ biff (1)
  494. Xnotification is on by default, it can be turned off by setting this variable
  495. Xto `no'.  Alternatively the biff-service can be customised by setting it to
  496. Xeither `service@SERV_ADDRsep@', `@SERV_ADDRsep@hostname', or
  497. X`service@SERV_ADDRsep@hostname'.  When not specified it defaults
  498. Xto @COMSATservice@@SERV_ADDRsep@@COMSAThost@.@DROPPRIVS@
  499. X.SH EXAMPLES
  500. XLook in the
  501. X.BR procmailex (5)
  502. Xman page.
  503. X.SH CAVEATS
  504. XContinued lines in an action line that specifies a program always have to end
  505. Xin a backslash, even if the underlying shell would not need or want the
  506. Xbackslash to indicate continuation.  This is due to the two pass parsing
  507. Xprocess needed (first procmail, then the shell (or not, depending on
  508. X.BR SHELLMETAS )).
  509. X.PP
  510. XDon't put comments on the regular expression condition lines in a
  511. Xrecipe, these lines are fed to the internal egrep
  512. X.I literally
  513. X(except for continuation backslashes at the end of a line).
  514. X.PP
  515. XLeading whitespace on continued regular expression condition lines
  516. Xis usually ignored (so that they can be indented), but
  517. X.B not
  518. Xon continued condition lines that are evaluated according to the
  519. X.BR sh (1)
  520. Xsubstitution rules inside double quotes.
  521. X.PP
  522. XWatch out for deadlocks when doing unhealthy things like forwarding mail
  523. Xto your own account.  Deadlocks can be broken by proper use of
  524. X.BR LOCKTIMEOUT .
  525. X.PP
  526. XAny default values that procmail has for some environment variables will
  527. X.B always
  528. Xoverride the ones that were already defined.  If you really want to
  529. Xoverride the defaults, you either have to put them in the
  530. X.B rcfile
  531. Xor on the command line as arguments.
  532. X.PP
  533. XEnvironment variables set
  534. X.B inside
  535. Xthe action part of a recipe will
  536. X.B not
  537. Xretain their value after the recipe has finished since they are set in a
  538. Xsubshell of procmail.  To make sure the value of an environment variable is
  539. Xretained you have to put the assignment to the variable before the leading `|'
  540. Xof a recipe, so that it can capture stdout of the program.
  541. X.PP
  542. XIf you specify only a `@PASS_HEAD@' or a `@PASS_BODY@' flag on a recipe,
  543. Xand the recipe matches, then, unless a `@FILTER@' or `@CONTINUE@' flag is
  544. Xpresent as well, the body respectively the header of the mail will be silently
  545. Xlost.
  546. X.PP
  547. XThe `@CONTINUE@' flag defaults to on when capturing stdout of a recipe in an
  548. Xenvironment variable.
  549. X.SH "SEE ALSO"
  550. X.na
  551. X.nh
  552. X.BR procmail (1),
  553. X.BR procmailsc (5),
  554. X.BR procmailex (5),
  555. X.BR sh (1),
  556. X.BR csh (1),
  557. X.BR mail (1),
  558. X.BR mailx (1),
  559. X.BR binmail (1),
  560. X.BR uucp (1),
  561. X.BR aliases (5),
  562. X.BR sendmail (8),
  563. X.BR egrep (1),
  564. X.BR grep (1),
  565. X.BR biff (1),
  566. X.BR comsat (8),
  567. X.BR lockfile (1),
  568. X.BR formail (1)
  569. X.hy
  570. X.ad
  571. X.SH BUGS
  572. XThe only substitutions of environment variables that can be handled by
  573. Xprocmail itself are of the type $name, ${name}, ${name:-text}, ${name:+text},
  574. X${name-text}, ${name+text}, $#, $n, $$, $?, $_, $\- and $=; whereas $_ will be
  575. Xsubstituted by the name of the current rcfile, $\- by $LASTFOLDER and $=
  576. Xwill contain the score of the last recipe.
  577. XWhen the
  578. X.B \-@ARGUMENTOPT@
  579. Xor
  580. X.B \-@MAILFILTOPT@
  581. Xoptions are used, "$@" will expand to respectively the specified argument
  582. Xor the sender and recipient list; but only when passed as in the
  583. Xargument list to a program.@UPPERCASE_USERNAMES@
  584. X.PP
  585. XProcmail does not support the expansion of `~'.
  586. X.PP
  587. XA line buffer of length $LINEBUF is used when processing the
  588. X.IR rcfile ,
  589. Xany expansions
  590. X.B have
  591. Xto fit within this limit; if they don't, behaviour is undefined.
  592. X.PP
  593. XIf the global lockfile has a
  594. X.I relative
  595. Xpath, and the current directory
  596. Xis not the same as when the global lockfile was created, then the global
  597. Xlockfile will not be removed if procmail exits at that point (remedy:
  598. Xuse
  599. X.I absolute
  600. Xpaths to specify global lockfiles).
  601. X.PP
  602. XWhen capturing stdout from a recipe into an environment variable, exactly
  603. Xone trailing newline will be stripped.
  604. X.PP
  605. XBy using the `^' or `$' in other spots than at the start respectively
  606. Xend of a regular expression you can use the internal egrep to do multiline
  607. Xmatches.
  608. X.PP
  609. XWhen the regular expression starts with `^^' it will anchor the match
  610. Xat the very start of the text.
  611. X.PP
  612. XThe start and end of a word can be matched by `\e<' and `\e>'.  They
  613. Xare merely a shorthand for `[^a-zA-Z0-9_]', but can also match newlines.
  614. XSince they match actual characters, they are only suitable to delimit
  615. Xwords, not to delimit inter-word space.
  616. X.SH MISCELLANEOUS
  617. XIf the regular expression contains `\fB@TOkey@\fP' it will be substituted by
  618. X.na
  619. X.nh
  620. X`\fB@TOsubstitute@\fP',
  621. Xwhich should catch all destination specifications.
  622. X.hy
  623. X.ad
  624. X.PP
  625. XIf the regular expression contains `\fB@FROMDkey@\fP' it will be
  626. Xsubstituted by
  627. X.na
  628. X.nh
  629. X`\fB@FROMDsubstitute@\fP',
  630. Xwhich should catch mails coming from most daemons (how's that for a regular
  631. Xexpression :-).
  632. X.hy
  633. X.ad
  634. X.PP
  635. XIf the regular expression contains `\fB@FROMMkey@\fP' it will be
  636. Xsubstituted by
  637. X.na
  638. X.nh
  639. X`\fB@FROMMsubstitute@\fP'
  640. X(a stripped down version of `\fB@FROMDkey@\fP'),
  641. Xwhich should catch mails coming from most mailer-daemons.
  642. X.hy
  643. X.ad
  644. X.PP
  645. XWhen assigning boolean values to variables like VERBOSE, DELIVERED or COMSAT,
  646. Xprocmail accepts as true every string starting with: a non-zero value, `on',
  647. X`y', `t' or `e'.  False is every string starting with: a zero value, `off',
  648. X`n', `f' or 'd'.
  649. X.PP
  650. XIf the action line of a recipe specifies a program, a sole backslash-newline
  651. Xpair in it on an otherwise empty line will be converted into a newline.
  652. X.SH NOTES
  653. XSince unquoted leading whitespace is generally ignored in the rcfile you can
  654. Xindent everything to taste.
  655. X.PP
  656. XThe leading `|' on the action line to specify a program or filter is stripped
  657. Xbefore checking for $SHELLMETAS.
  658. X.PP
  659. XFiles included with the INCLUDERC directive containing only environment
  660. Xvariable assignments can be shared with sh.
  661. X.PP
  662. XFor
  663. X.I really
  664. Xcomplicated processing you can even consider calling
  665. X.B procmail
  666. Xrecursively.
  667. END_OF_FILE
  668.   if test 21444 -ne `wc -c <'procmail-3.03/man/procmailrc.man'`; then
  669.     echo shar: \"'procmail-3.03/man/procmailrc.man'\" unpacked with wrong size!
  670.   fi
  671.   # end of 'procmail-3.03/man/procmailrc.man'
  672. fi
  673. if test -f 'procmail-3.03/src/formail.c' -a "${1}" != "-c" ; then 
  674.   echo shar: Will not clobber existing file \"'procmail-3.03/src/formail.c'\"
  675. else
  676.   echo shar: Extracting \"'procmail-3.03/src/formail.c'\" \(28361 characters\)
  677.   sed "s/^X//" >'procmail-3.03/src/formail.c' <<'END_OF_FILE'
  678. X/************************************************************************
  679. X *    formail - The mail (re)formatter                *
  680. X *                                    *
  681. X *    Seems to be relatively bug free.                *
  682. X *                                    *
  683. X *    Copyright (c) 1990-1994, S.R. van den Berg, The Netherlands    *
  684. X *    #include "../README"                        *
  685. X ************************************************************************/
  686. X#ifdef RCS
  687. Xstatic /*const*/char rcsid[]=
  688. X "$Id: formail.c,v 1.53 1994/06/28 16:56:10 berg Exp $";
  689. X#endif
  690. Xstatic /*const*/char rcsdate[]="$Date: 1994/06/28 16:56:10 $";
  691. X#include "includes.h"
  692. X#include <ctype.h>        /* iscntrl() */
  693. X#include "formail.h"
  694. X#include "acommon.h"
  695. X#include "sublib.h"
  696. X#include "shell.h"
  697. X#include "common.h"
  698. X#include "fields.h"
  699. X#include "ecommon.h"
  700. X#include "formisc.h"
  701. X
  702. X#define ssl(str)        str,STRLEN(str)
  703. X#define bsl(str)        {ssl(str)}
  704. X#define sslbar(str,bar1,bar2)    {ssl(str),STRLEN(bar1)-1,STRLEN(bar2)-1}
  705. X
  706. Xstatic const char
  707. X#define X(name,value)    name[]=value,
  708. X#include "header.h"                  /* pull in the definitions */
  709. X#undef X
  710. X From_[]=        FROM,                /* VNIX 'From ' line */
  711. X Article_[]=        "Article ",           /* USENET 'Article ' line */
  712. X x_[]=            "X-",                /* general extension */
  713. X old_[]=        OLD_PREFIX,                 /* my extension */
  714. X xloop[]=        "X-Loop:",                /* ditto ... */
  715. X unknown[]=UNKNOWN,re[]=" Re:",fmusage[]=FM_USAGE;
  716. X
  717. Xstatic const struct {const char*hedr;int lnr;}cdigest[]=
  718. X{
  719. X#define X(name,value)    bsl(name),
  720. X#include "header.h"             /* pull in the precalculated references */
  721. X#undef X
  722. X};
  723. X
  724. X/*
  725. X *    sender determination fields in order of importance/reliability
  726. X *    reply-address determination fields (wrepl specifies the weight
  727. X *    for regular replies, wtrepl specifies the weight for trusted users)
  728. X *
  729. X *    I bet this is the first time you see a bar graph in C-source-code :-)
  730. X */
  731. Xstatic const struct {const char*head;int len,wrepl,wtrepl;}sest[]=
  732. X{ sslbar(replyto    ,"******"    ,"********"    ),
  733. X  sslbar(Fromm        ,"*"        ,"*******"    ),
  734. X  sslbar(retreceiptto    ,"********"    ,"*****"    ),
  735. X  sslbar(sender        ,"*****"    ,"******"    ),
  736. X  sslbar(res_replyto    ,"***********"    ,"***********"    ),
  737. X  sslbar(res_from    ,"***foo***"    ,"***bar****"    ),
  738. X  sslbar(res_sender    ,"**********"    ,"*********"    ),
  739. X  sslbar(errorsto    ,"*******"    ,"****"        ),
  740. X  sslbar(path        ,"**"        ,"*"        ),
  741. X  sslbar(returnpath    ,"***"        ,"***"        ),
  742. X  sslbar(From_        ,"****"        ,"**"        )
  743. X};
  744. X
  745. Xstatic struct saved rex[]=
  746. X{ bsl(subject),bsl(references),bsl(messageid),bsl(date)
  747. X};
  748. X#define subj    (rex+0)
  749. X#define refr    (rex+1)
  750. X#define msid    (rex+2)
  751. X#define hdate    (rex+3)
  752. X
  753. X#ifdef sMAILBOX_SEPARATOR
  754. X#define emboxsep    smboxsep
  755. X#define MAILBOX_SEPARATOR
  756. Xstatic const char smboxsep[]=sMAILBOX_SEPARATOR;
  757. X#endif /* sMAILBOX_SEPARATOR */
  758. X#ifdef eMAILBOX_SEPARATOR
  759. X#ifdef emboxsep
  760. X#undef emboxsep
  761. X#else
  762. X#define MAILBOX_SEPARATOR
  763. X#endif
  764. Xstatic const char emboxsep[]=eMAILBOX_SEPARATOR;
  765. X#endif /* eMAILBOX_SEPARATOR */
  766. X
  767. Xconst char binsh[]=BinSh,sfolder[]=FOLDER,
  768. X couldntw[]="Couldn't write to stdout";
  769. Xint errout,oldstdout,quiet=1,buflast,lenfileno;
  770. Xlong initfileno;
  771. Xchar ffileno[LEN_FILENO_VAR+8*sizeof(initfileno)*4/10+1+1]=DEFfileno;
  772. Xint lexitcode;                         /* dummy, for waitfor() */
  773. Xpid_t child= -1;
  774. Xunsigned long rhash;
  775. XFILE*mystdout;
  776. Xint nrskip,nrtotal= -1,retval=EX_OK;
  777. Xsize_t buflen,buffilled;
  778. Xlong totallen;
  779. Xchar*buf,*logsummary;
  780. Xstruct field*rdheader,*xheader,*Xheader,*uheader,*Uheader;
  781. Xstatic struct field*iheader,*Iheader,*aheader,*Aheader,*Rheader,*nheader;
  782. X
  783. Xstatic void logfolder P((void))     /* estimate the no. of characters needed to */
  784. X{ size_t i;charNUM(num,totallen);               /* represent totallen */
  785. X  static const char tabchar[]=TABCHAR;
  786. X  if(logsummary)
  787. X   { putssn(sfolder,STRLEN(sfolder));putssn(logsummary,i=strlen(logsummary));
  788. X     i+=STRLEN(sfolder);i-=i%TABWIDTH;
  789. X     do putssn(tabchar,STRLEN(tabchar));
  790. X     while((i+=TABWIDTH)<LENoffset);
  791. X     ultstr(7,totallen,num);putssn(num,strlen(num));putcs('\n');
  792. X   }
  793. X}
  794. X    /* checks if the last field in rdheader looks like a known digest header */
  795. Xstatic int digheadr P((void))
  796. X{ char*chp;int i;size_t j;struct field*fp;
  797. X  for(fp=rdheader;fp->fld_next;fp=fp->fld_next);     /* skip to the last */
  798. X  i=maxindex(cdigest);chp=fp->fld_text;j=fp->id_len;
  799. X  while((cdigest[i].lnr!=j||strnIcmp(cdigest[i].hedr,chp,j))&&i--);
  800. X  return i>=0||j>STRLEN(old_)&&!strnIcmp(old_,chp,STRLEN(old_))||
  801. X   j>STRLEN(x_)&&!strnIcmp(x_,chp,STRLEN(x_));
  802. X}
  803. X
  804. Xstatic int artheadr P((void))         /* could it be the start of an article? */
  805. X{ if(!rdheader&&!strncmp(buf,Article_,STRLEN(Article_)))
  806. X   { addbuf();rdheader->id_len=STRLEN(Article_);
  807. X     return 1;
  808. X   }
  809. X  return 0;
  810. X}
  811. X
  812. Xstatic PROGID;
  813. X
  814. Xmain(lastm,argv)int lastm;const char*const argv[];
  815. X{ int i,split=0,force=0,bogus=1,every=0,areply=0,trust=0,digest=0,nowait=0,
  816. X   keepb=0,minfields=(char*)progid-(char*)progid,conctenate=0,babyl=0,
  817. X   babylstart;
  818. X  off_t maxlen,insoffs,ctlength;FILE*idcache=0;pid_t thepid;
  819. X  size_t j,lnl,escaplen;char*chp,*namep,*escap=ESCAP;
  820. X  struct field*fldp,*fp2,**afldp,*fdate,*fcntlength;
  821. X  if(lastm)                   /* sanity check, any argument at all? */
  822. X#define Qnext_arg()    if(!*chp&&!(chp=(char*)*++argv))goto usg
  823. X     while(chp=(char*)*++argv)
  824. X      { if((lastm= *chp++)==FM_SKIP)
  825. X       goto number;
  826. X    else if(lastm!=FM_TOTAL)
  827. X       goto usg;
  828. X    for(;;)
  829. X     { switch(lastm= *chp++)
  830. X        { case FM_TRUST:trust=1;
  831. X         continue;
  832. X          case FM_REPLY:areply=1;
  833. X         continue;
  834. X          case FM_FORCE:force=1;
  835. X         continue;
  836. X          case FM_EVERY:every=1;
  837. X         continue;
  838. X          case FM_BABYL:babyl=every=1;
  839. X          case FM_DIGEST:digest=1;
  840. X         continue;
  841. X          case FM_NOWAIT:nowait=1;
  842. X         continue;
  843. X          case FM_KEEPB:keepb=1;
  844. X         continue;
  845. X          case FM_CONCATENATE:conctenate=1;
  846. X         continue;
  847. X          case FM_QUIET:quiet=1;
  848. X         if(*chp=='-')
  849. X            chp++,quiet=0;
  850. X         continue;
  851. X          case FM_LOGSUMMARY:Qnext_arg();
  852. X         if(strlen(logsummary=chp)>MAXfoldlen)
  853. X            chp[MAXfoldlen]='\0';
  854. X         detab(chp);
  855. X         break;
  856. X          case FM_SPLIT:split=1;
  857. X         if(!*chp)
  858. X          { ++argv;
  859. X            goto parsedoptions;
  860. X          }
  861. X         goto usg;
  862. X          case HELPOPT1:case HELPOPT2:elog(fmusage);elog(FM_HELP);
  863. X         goto xusg;
  864. X          case FM_DUPLICATE:case FM_MINFIELDS:Qnext_arg();chp++;
  865. X          default:chp--;
  866. Xnumber:         if(*chp-'0'>(unsigned)9)        /* the number is not >=0 */
  867. X            goto usg;
  868. X         i=strtol(chp,&chp,10);
  869. X         switch(lastm)            /* where does the number go? */
  870. X          { case FM_SKIP:nrskip=i;
  871. X               break;
  872. X            case FM_DUPLICATE:maxlen=i;Qnext_arg();
  873. X               if(!(idcache=fopen(chp,"r+b"))&&      /* existing cache? */
  874. X              !(idcache=fopen(chp,"w+b")))        /* create cache? */
  875. X            { nlog("Couldn't open");logqnl(argv[i]);
  876. X              return EX_CANTCREAT;
  877. X            }
  878. X               goto nextarg;
  879. X            case FM_MINFIELDS:minfields=i;
  880. X               break;
  881. X            default:nrtotal=i;
  882. X          }
  883. X         continue;
  884. X          case FM_BOGUS:bogus=0;
  885. X         continue;
  886. X          case FM_QPREFIX:Qnext_arg();escap=chp;
  887. X         break;
  888. X          case FM_ADD_IFNOT:case FM_ADD_ALWAYS:case FM_REN_INSERT:
  889. X          case FM_DEL_INSERT:case FM_EXTRACT:case FM_EXTRC_KEEP:
  890. X          case FM_FIRST_UNIQ:case FM_LAST_UNIQ:case FM_ReNAME:Qnext_arg();
  891. X         i=breakfield(chp,lnl=strlen(chp));
  892. X         switch(lastm)
  893. X          { case FM_DEL_INSERT:case FM_REN_INSERT:case FM_EXTRACT:
  894. X            case FM_FIRST_UNIQ:case FM_LAST_UNIQ:case FM_EXTRC_KEEP:
  895. X               if(-i!=lnl)
  896. X            default:
  897. X              if(i<=0)
  898. X                 goto invfield;
  899. X            case FM_ReNAME:;
  900. X          }
  901. X         chp[lnl]='\n';                   /* terminate the line */
  902. X         afldp=addfield(lastm==FM_REN_INSERT?&iheader:
  903. X          lastm==FM_DEL_INSERT?&Iheader:lastm==FM_ADD_IFNOT?&aheader:
  904. X          lastm==FM_ADD_ALWAYS?&Aheader:lastm==FM_EXTRACT?&xheader:
  905. X          lastm==FM_FIRST_UNIQ?&uheader:lastm==FM_LAST_UNIQ?&Uheader:
  906. X          lastm==FM_EXTRC_KEEP?&Xheader:&Rheader,chp,++lnl);
  907. X         if(lastm==FM_ReNAME)          /* then we need a second field */
  908. X          { int copied=0;
  909. X            for(namep=(chp=(fldp= *afldp)->fld_text)+lnl,
  910. X             chp+=lnl=fldp->id_len;chp<namep;++chp)
  911. X             { switch(*chp)              /* skip whitespace */
  912. X            { case ' ':case '\t':case '\n':
  913. X                 continue;
  914. X            }
  915. X               break;
  916. X             }                   /* second field attached? */
  917. X            lastm=i;
  918. X            if((i=breakfield(chp,(size_t)(namep-chp)))>0)
  919. X               tmemmove((char*)fldp->fld_text+lnl,chp,i),copied=1;
  920. X            else if(namep>chp&&lastm<=0|| /* first field ended early */
  921. X                !(chp=(char*)*++argv)||     /* look at next arg */
  922. X                (i=breakfield(chp,strlen(chp)))<=0) /* no field? */
  923. Xinvfield:         { nlog("Invalid field-name:");logqnl(chp?chp:"");
  924. X               goto usg;
  925. X             }
  926. X            *afldp=fldp=
  927. X             realloc(fldp,FLD_HEADSIZ+(fldp->tot_len=lnl+i));
  928. X            if(!copied)               /* if not squeezed on yet */
  929. X               tmemmove((char*)fldp->fld_text+lnl,chp,i);  /* do now */
  930. X          }
  931. X          case '\0':;
  932. X        }
  933. X       break;
  934. X     }
  935. Xnextarg:;
  936. X      }
  937. Xparsedoptions:
  938. X  escaplen=strlen(escap);mystdout=stdout;signal(SIGPIPE,SIG_IGN);
  939. X  thepid=getpid();
  940. X  if(split)
  941. X   { char**ep;char**vfileno=0;
  942. X     for(ep=environ;*ep;ep++)           /* gobble through the environment */
  943. X    if(!strncmp(*ep,ffileno,LEN_FILENO_VAR))     /* look for FILENO= */
  944. X       vfileno=ep;                        /* yes, found it */
  945. X     if(!vfileno)            /* FILENO= found in the environment? */
  946. X      { size_t envlen;                         /* no, pity */
  947. X    envlen=(ep-environ+1)*sizeof*environ;           /* current length */
  948. X    tmemmove(ep=malloc(envlen+sizeof*environ),environ,envlen);
  949. X    *(vfileno=(char**)((char*)(environ=ep)+envlen))=0;*--vfileno=ffileno;
  950. X      }                              /* copy over the array */
  951. X     if((lenfileno=strlen(chp= *vfileno+LEN_FILENO_VAR))>
  952. X    STRLEN(ffileno)-LEN_FILENO_VAR-1)      /* check the desired width */
  953. X    lenfileno=STRLEN(ffileno)-LEN_FILENO_VAR-1;    /* too big, truncate */
  954. X     if((initfileno=strtol(chp,&chp,10))<0)      /* fetch the initial value */
  955. X    lenfileno--;                 /* correct it for negatives */
  956. X     if(*chp)                         /* no valid number? */
  957. X    lenfileno= -1;                /* disable the FILENO generation */
  958. X     else
  959. X    *vfileno=ffileno;        /* stuff our template in the environment */
  960. X     oldstdout=dup(STDOUT);fclose(stdout);
  961. X     if(!nrtotal)
  962. X    goto onlyhead;
  963. X     startprog((const char*Const*)argv);
  964. X     if(!minfields)                   /* no user specified minimum? */
  965. X    minfields=DEFminfields;                 /* take our default */
  966. X   }
  967. X  else if(nrskip>0||nrtotal>=0||every||digest||minfields||nowait)
  968. X     goto usg;                 /* only valid in combination with split */
  969. X  if((xheader||Xheader)&&logsummary||keepb&&!(areply||xheader||Xheader))
  970. Xusg:                             /* options sanity check */
  971. X   { elog(fmusage);                       /* impossible mix */
  972. Xxusg:
  973. X     return EX_USAGE;
  974. X   }
  975. X  buf=malloc(buflen=Bsize);totallen=0;i=maxindex(rex); /* prime some buffers */
  976. X  do rex[i].rexp=malloc(1);
  977. X  while(i--);
  978. X  fdate=0;addfield(&fdate,date,STRLEN(date)); /* fdate is only for searching */
  979. X  fcntlength=0;addfield(&fcntlength,cntlength,STRLEN(cntlength));   /* ditto */
  980. X  if(areply)                           /* when auto-replying */
  981. X     addfield(&iheader,xloop,STRLEN(xloop));      /* preserve X-Loop: fields */
  982. X  if(babyl)                        /* skip BABYL leader */
  983. X   { while(getchar()!=BABYL_SEP1||getchar()!=BABYL_SEP2||getchar()!='\n')
  984. X    while(getchar()!='\n');
  985. X     while(getchar()!='\n');
  986. X   }
  987. X  while((buflast=getchar())=='\n');             /* skip leading garbage */
  988. X  if(!readhead())                        /* start looking */
  989. X   {
  990. X#ifdef sMAILBOX_SEPARATOR                  /* check for a leading */
  991. X     if(!strncmp(smboxsep,buf,STRLEN(smboxsep)))    /* mailbox separator */
  992. X      { buffilled=0;                          /* skip it */
  993. X    goto startover;
  994. X      }
  995. X#endif
  996. X     if(digest&&artheadr())
  997. X    goto startover;
  998. X   }
  999. X  else
  1000. Xstartover:
  1001. X     while(readhead());                 /* read in the whole header */
  1002. X  ;{ size_t lenparkedbuf;void*parkedbuf;
  1003. X     if(rdheader)
  1004. X      { char*tmp,*tmp2;
  1005. X    if(!strncmp(tmp=(char*)rdheader->fld_text,Article_,STRLEN(Article_)))
  1006. X       tmp[STRLEN(Article_)-1]=HEAD_DELIMITER;
  1007. X    else if(babyl&&
  1008. X        !force&&
  1009. X        !strncmp(tmp,mailfrom,STRLEN(mailfrom))&&
  1010. X        eqFrom_(tmp2=skpspace(tmp+STRLEN(mailfrom))))
  1011. X     { rdheader->id_len=STRLEN(From_);
  1012. X       tmemmove(tmp,tmp2,rdheader->tot_len-=tmp2-tmp);
  1013. X     }
  1014. X      }
  1015. X     namep=0;totallen=0;i=maxindex(rex);
  1016. X     do rex[i].rexl=0;
  1017. X     while(i--);
  1018. X     clear_uhead(uheader);clear_uhead(Uheader);     /* all state has been reset */
  1019. X     for(fldp=rdheader;fldp;fldp=fldp->fld_next)    /* go through the linked */
  1020. X      { int nowm;                    /* list of header-fields */
  1021. X    if(conctenate)
  1022. X       concatenate(fldp);             /* look for `sender' fields */
  1023. X    chp=fldp->fld_text;j=fldp->id_len;i=maxindex(sest);
  1024. X    while((sest[i].len!=j||strnIcmp(sest[i].head,chp,j))&&i--);
  1025. X    if(i>=0&&(i!=maxindex(sest)||fldp==rdheader))      /* found anything? */
  1026. X     { char*saddr;char*tmp;                 /* determine the weight */
  1027. X       nowm=trust?sest[i].wtrepl:areply?sest[i].wrepl:i;chp+=j;
  1028. X       tmp=malloc(j=fldp->tot_len-j);tmemmove(tmp,chp,j);
  1029. X       (chp=tmp)[j-1]='\0';
  1030. X       if(sest[i].head==From_)
  1031. X        { char*pastad;
  1032. X          if(trust||!(saddr=strchr(chp,'\n')))   /* skip the first line? */
  1033. X         saddr=chp;                      /* no need */
  1034. X          if(*saddr=='\n'&&(pastad=strchr(saddr,' ')))
  1035. X         saddr=pastad+1;        /* reposition at the address */
  1036. X          chp=saddr;
  1037. X          while((pastad=strchr(chp,'\n'))&&(pastad=strchr(pastad,' ')))
  1038. X         chp=pastad+1;              /* skip to the last uucp >From */
  1039. X          if(pastad=strchr(chp,' '))        /* found an address? */
  1040. X           { char*savetmp;                      /* lift it out */
  1041. X         savetmp=malloc((j=pastad-chp)+1);tmemmove(savetmp,chp,j);
  1042. X         savetmp[j]='\0';
  1043. X         if(strchr(savetmp,'@'))         /* domain attached? */
  1044. X            chp=savetmp,savetmp=tmp,tmp=chp;        /* ok, ready */
  1045. X         else                /* no domain, bang away! :-) */
  1046. X          { static const char remf[]=" remote from ",
  1047. X             fwdb[]=" forwarded by ";
  1048. X            char*p1,*p2;
  1049. X            chp=tmp;
  1050. X            for(;;)
  1051. X             { int c;
  1052. X               p1=strstr(saddr,remf);
  1053. X               if(!(p2=strstr(saddr,fwdb))&&!p1)
  1054. X              break;                 /* no more info */
  1055. X               if(!p1||p2&&p2<p1)          /* pick the first bang */
  1056. X              p1=p2+STRLEN(fwdb);
  1057. X               else
  1058. X              p1+=STRLEN(remf);
  1059. X               for(;;)                     /* copy it over */
  1060. X            { switch(c= *p1++)
  1061. X               { default:*chp++=c;
  1062. X                continue;
  1063. X                 case '\0':case '\n':*chp++='!'; /* for the buck */
  1064. X               }
  1065. X              break;
  1066. X            }
  1067. X               saddr=p1;            /* continue the hunt */
  1068. X             }
  1069. X            strcpy(chp,savetmp);chp=tmp;     /* attach the user part */
  1070. X          }
  1071. X         free(savetmp);      /* (temporary buffers might have switched) */
  1072. X           }
  1073. X        }
  1074. X       while(*(chp=skpspace(chp))=='\n')
  1075. X          chp++;
  1076. X       for(saddr=0;;chp=skipwords(chp))        /* skip RFC 822 wise */
  1077. X        { switch(*chp)
  1078. X           { default:
  1079. X            if(!saddr)           /* if we haven't got anything yet */
  1080. X               saddr=chp;        /* this might be the address */
  1081. X            continue;
  1082. X         case '<':skipwords(saddr=chp);      /* hurray, machine useable */
  1083. X         case '\0':;
  1084. X           }
  1085. X          break;
  1086. X        }
  1087. X       if(saddr)                /* any useful mailaddress found? */
  1088. X        { if(*saddr)              /* did it have any length? */
  1089. X           { if(!strpbrk(saddr,"@!/"))
  1090. X            nowm-=(maxindex(sest)+2)*4;        /* depreciate "user" */
  1091. X         else if(strstr(saddr,".UUCP"))
  1092. X            nowm-=(maxindex(sest)+2)*3;     /* depreciate .UUCP address */
  1093. X         else if(strchr(saddr,'@')&&!strchr(saddr,'.'))
  1094. X            nowm-=(maxindex(sest)+2)*2;         /* depreciate user@host */
  1095. X         else if(strchr(saddr,'!'))
  1096. X            nowm-=(maxindex(sest)+2)*1;         /* depreciate bangpaths */
  1097. X         if(!namep||nowm>lastm)        /* better than previous ones */
  1098. X          { saddr=strcpy(malloc(strlen(saddr)+1),saddr);lastm=nowm;
  1099. X            goto newnamep;
  1100. X          }
  1101. X           }
  1102. X          else if(sest[i].head==returnpath)        /* nill Return-Path: */
  1103. X           { saddr=0;lastm=maxindex(sest)+2;         /* override */
  1104. Xnewnamep:     if(namep)
  1105. X            free(namep);
  1106. X         namep=saddr;
  1107. X           }
  1108. X        }
  1109. X       free(tmp);
  1110. X     }                   /* save headers for later perusal */
  1111. X    i=maxindex(rex);chp=fldp->fld_text;j=fldp->id_len;    /* e.g. areply */
  1112. X    while((rex[i].lenr!=j||strnIcmp(rex[i].headr,chp,j))&&i--);
  1113. X    chp+=j;
  1114. X    if(i>=0&&(j=fldp->tot_len-j)>1)              /* found anything? */
  1115. X     { tmemmove(rex[i].rexp=realloc(rex[i].rexp,(rex[i].rexl=j)+1),chp,j);
  1116. X       rex[i].rexp[j]='\0';                 /* add a terminating \0 */
  1117. X     }
  1118. X      }
  1119. X     if(idcache)
  1120. X      { int dupid=0;
  1121. X    if(msid->rexl)                    /* any Message-ID: ? */
  1122. X     { insoffs=maxlen;msid->rexp[msid->rexl-1]='\0';
  1123. X       do                    /* wipe out trailing newline */
  1124. X        { int j;char*p;      /* start reading & comparing the next word */
  1125. X          for(p=msid->rexp;(j=fgetc(idcache))==*p;p++)
  1126. X         if(!j)                         /* end of word? */
  1127. X          { if(!quiet)
  1128. X               nlog("Duplicate ID found:"),elog(msid->rexp),elog("\n");
  1129. X            dupid=1;
  1130. X            goto dupfound;             /* YES! duplicate found */
  1131. X          }
  1132. X          if(!j)                         /* end of word? */
  1133. X           { if(p==msid->rexp&&insoffs==maxlen)     /* first character? */
  1134. X          { insoffs=ftell(idcache)-1;             /* found end of */
  1135. X            goto skiprest;              /* circular buffer */
  1136. X          }
  1137. X           }
  1138. X          else
  1139. Xskiprest:     for(;;)            /* skip the rest of the word */
  1140. X          { switch(fgetc(idcache))
  1141. X             { case EOF:
  1142. X              goto noluck;
  1143. X               default:
  1144. X              continue;
  1145. X               case '\0':;
  1146. X             }
  1147. X            break;
  1148. X          }
  1149. X        }
  1150. X       while(ftell(idcache)<maxlen);          /* past our quota? */
  1151. Xnoluck:       if(insoffs>=maxlen)                  /* past our quota? */
  1152. X          insoffs=0;                 /* start up front again */
  1153. X       fseek(idcache,insoffs,SEEK_SET);
  1154. X       fwrite(msid->rexp,1,msid->rexl+1,idcache);
  1155. Xdupfound:  fseek(idcache,(off_t)0,SEEK_SET);     /* rewind, for any next run */
  1156. X       msid->rexp[msid->rexl-1]='\n';          /* restore the newline */
  1157. X     }
  1158. X    if(!split)              /* not splitting?  terminate early */
  1159. X       return dupid?EX_OK:1;
  1160. X    if(dupid)                   /* duplicate? suppress output */
  1161. X       closemine(),opensink();
  1162. X      }
  1163. X     ctlength=0;
  1164. X     if(!digest&&(fldp=findf(fcntlength,&rdheader)))
  1165. X      { *(chp=(char*)fldp->fld_text+fldp->tot_len-1)='\0';   /* terminate it */
  1166. X    ctlength=strtol((char*)fldp->fld_text+STRLEN(cntlength),(char**)0,10);
  1167. X    *chp='\n';                 /* restore the trailing newline */
  1168. X      }
  1169. X     tmemmove(parkedbuf=malloc(buffilled),buf,lenparkedbuf=buffilled);
  1170. X     buffilled=0;    /* moved the contents of buf out of the way temporarily */
  1171. X     if(areply)              /* autoreply requested, we clean up the header */
  1172. X      { for(fldp= *(afldp= &rdheader);fldp;)
  1173. X       if(!(fp2=findf(fldp,&iheader))||fp2->id_len<fp2->tot_len-1)
  1174. X          *afldp=fldp->fld_next,free(fldp),fldp= *afldp;   /* remove all */
  1175. X       else                    /* except the ones mentioned */
  1176. X          fldp= *(afldp= &fldp->fld_next);               /* as -i ...: */
  1177. X    loadbuf(to,STRLEN(to));loadchar(' ');       /* generate the To: field */
  1178. X    if(namep)           /* did we find a valid return address at all? */
  1179. X       loadbuf(namep,strlen(namep));          /* then insert it here */
  1180. X    else
  1181. X       loadbuf(unknown,STRLEN(unknown));        /* or insert our default */
  1182. X    loadchar('\n');addbuf();               /* add it to rdheader */
  1183. X    if(subj->rexl)                      /* any Subject: found? */
  1184. X     { loadbuf(subject,STRLEN(subject));      /* sure, check for leading */
  1185. X       if(strnIcmp(skpspace(chp=subj->rexp),Re,STRLEN(Re)))          /* Re: */
  1186. X          loadbuf(re,STRLEN(re));           /* no Re: , add one ourselves */
  1187. X       loadsaved(subj);addbuf();
  1188. X     }
  1189. X    if(refr->rexl||msid->rexl)       /* any References: or Message-ID: */
  1190. X     { loadbuf(references,STRLEN(references)); /* yes insert References: */
  1191. X       if(refr->rexl)
  1192. X        { if(msid->rexl)        /* if we're going to append a Message-ID */
  1193. X         --refr->rexl;            /* suppress the trailing newline */
  1194. X          loadsaved(refr);
  1195. X        }
  1196. X       if(msid->rexl)
  1197. X          loadsaved(msid);               /* here's our missing newline */
  1198. X       addbuf();
  1199. X     }
  1200. X    if(msid->rexl)             /* do we add an In-Reply-To: field? */
  1201. X       loadbuf(inreplyto,STRLEN(inreplyto)),loadsaved(msid),addbuf();
  1202. X      }                       /* are we allowed to add From_ lines? */
  1203. X     else if(!force&&(!rdheader||!eqFrom_(rdheader->fld_text)))     /* missing? */
  1204. X      { struct field*old;time_t t;         /* insert a From_ line up front */
  1205. X    t=time((time_t*)0);old=rdheader;rdheader=0;
  1206. X    loadbuf(From_,STRLEN(From_));
  1207. X    if(namep)              /* we found a valid return address */
  1208. X       loadbuf(namep,strlen(namep));
  1209. X    else
  1210. X       loadbuf(unknown,STRLEN(unknown));
  1211. X    loadchar(' ');                   /* insert one extra blank */
  1212. X    if(!hdate->rexl||!findf(fdate,&aheader))            /* Date: */
  1213. X       loadchar(' '),chp=ctime(&t),loadbuf(chp,strlen(chp)); /* no Date: */
  1214. X    else                     /* we generate it ourselves */
  1215. X       loadsaved(hdate);          /* yes, found Date:, then copy from it */
  1216. X    addbuf();rdheader->fld_next=old;
  1217. X      }
  1218. X     for(fldp=aheader;fldp;fldp=fldp->fld_next)
  1219. X    if(!findf(fldp,&rdheader))           /* only add what didn't exist */
  1220. X       if(fldp->id_len+1>=fldp->tot_len&&          /* field name only */
  1221. X          (fldp->id_len==STRLEN(messageid)&&
  1222. X           !strnIcmp(fldp->fld_text,messageid,STRLEN(messageid))||
  1223. X           fldp->id_len==STRLEN(res_messageid)&&
  1224. X           !strnIcmp(fldp->fld_text,res_messageid,STRLEN(res_messageid))))
  1225. X        { char*p;const char*name;unsigned long h1,h2,h3;
  1226. X          static unsigned long h4; /* conjure up a `unique' msg-id field */
  1227. X          h1=time((time_t*)0);h2=thepid;h3=rhash;
  1228. X          p=chp=malloc(fldp->id_len+2+1+((sizeof h1*8+5)/6+1)*4+1+
  1229. X           strlen(name=hostname())+2);     /* allocate worst case length */
  1230. X          strncpy(p,fldp->fld_text,fldp->id_len);*(p+=fldp->id_len)=' ';
  1231. X          *++p='<';*++p='"';*(p=ultoan(h3,p+1))='.';
  1232. X          *(p=ultoan(h4,p+1))='.';*(p=ultoan(h2,p+1))='.';
  1233. X          *(p=ultoan(h1,p+1))='"';*++p='@';strcpy(p+1,name);
  1234. X          *(p=strchr(p,'\0'))='>';*++p='\n';addfield(&nheader,chp,p-chp+1);
  1235. X          free(chp);h4++;                    /* put it in */
  1236. X        }
  1237. X       else
  1238. X          addfield(&nheader,fldp->fld_text,fldp->tot_len);
  1239. X     if((fldp= *(afldp= &rdheader))&&logsummary&&eqFrom_(fldp->fld_text))
  1240. X    concatenate(fldp),putssn(fldp->fld_text,fldp->tot_len);
  1241. X     while(fldp)
  1242. X      { lnl=fldp->id_len;chp=fldp->fld_text;
  1243. X    if(logsummary)
  1244. X     { if(lnl==STRLEN(subject)&&!strnIcmp(chp,subject,lnl))
  1245. X        { concatenate(fldp);chp[i=fldp->tot_len-1]='\0';detab(chp);
  1246. X          putcs(' ');putssn(chp,i>=MAXSUBJECTSHOW?MAXSUBJECTSHOW:i);
  1247. X          putcs('\n');
  1248. X        }
  1249. X     }
  1250. X    if(findf(fldp,&Iheader))                /* delete fields */
  1251. X       goto delfld;
  1252. X    ;{ struct field*uf;
  1253. X       if((uf=findf(fldp,&uheader))&&!uf->fld_ref)
  1254. X          uf->fld_ref=afldp;           /* first uheader, keep it */
  1255. X       else if(fp2=findf(fldp,&Uheader))
  1256. X        { if(fp2->fld_ref)
  1257. X           { if(afldp==&(*fp2->fld_ref)->fld_next)
  1258. X            afldp=fp2->fld_ref;
  1259. X         delfield(fp2->fld_ref);           /* delete old Uheader */
  1260. X           }
  1261. X          fp2->fld_ref=afldp;            /* keep last Uheader */
  1262. X        }
  1263. X       else if(uf)                /* delete all following uheaders */
  1264. Xdelfld:        { fldp=delfield(afldp);
  1265. X          continue;
  1266. X        }
  1267. X     }
  1268. X    if(fp2=findf(fldp,&Rheader))          /* explicitly rename field */
  1269. X       renfield(afldp,lnl,(char*)fp2->fld_text+lnl,fp2->tot_len-lnl);
  1270. X    else if((fp2=findf(fldp,&iheader))&&!(areply&&lnl==fp2->tot_len-1))
  1271. X       renfield(afldp,(size_t)0,old_,STRLEN(old_)); /* implicitly rename */
  1272. X    fldp= *(afldp= &(*afldp)->fld_next);
  1273. X      }                    /* restore the saved contents of buf */
  1274. X     tmemmove(buf,parkedbuf,buffilled=lenparkedbuf);free(parkedbuf);
  1275. X   }
  1276. X  flushfield(&rdheader);flushfield(&nheader);dispfield(Aheader);
  1277. X  dispfield(iheader);dispfield(Iheader);
  1278. X  if(namep)
  1279. X     free(namep);
  1280. X  if(keepb||!(xheader||Xheader))     /* we're not just extracting fields */
  1281. X     lputcs('\n');        /* make sure it is followed by an empty line */
  1282. X  if(!keepb&&(areply||xheader||Xheader))            /* decision time */
  1283. X   { logfolder();                   /* we throw away the rest */
  1284. X     if(split)
  1285. X    closemine();
  1286. X     else              /* terminate early, only the header was needed */
  1287. X    goto onlyhead;
  1288. X     opensink();                     /* discard the body */
  1289. X   }
  1290. X  lnl=1;                      /* last line was a newline */
  1291. X  if(buffilled==1)           /* the header really ended with a newline */
  1292. X     buffilled=0;          /* throw it away, since we already inserted it */
  1293. X  if(babyl)
  1294. X   { int c,lc;                    /* ditch pseudo BABYL header */
  1295. X     for(lc=0;c=getchar(),c!=EOF&&(c!='\n'||lc!='\n');lc=c);
  1296. X     babylstart=0;
  1297. X   }
  1298. X  if(ctlength>0)
  1299. X   { if(buffilled)
  1300. X    lputssn(buf,buffilled),ctlength-=buffilled,buffilled=lnl=0;
  1301. X     ;{ int tbl=buflast,lwr='\n';
  1302. X    while(--ctlength>=0&&tbl!=EOF)           /* skip Content-Length: bytes */
  1303. X       lnl=lwr==tbl&&lwr=='\n',putcs(lwr=tbl),tbl=getchar();
  1304. X    if((buflast=tbl)=='\n'&&lwr!=tbl)    /* just before a line break? */
  1305. X       putcs('\n'),buflast=getchar();        /* wrap up loose end */
  1306. X      }
  1307. X     if(!quiet&&ctlength>0)
  1308. X      { charNUM(num,ctlength);
  1309. X    nlog(cntlength);elog(" field exceeds actual length by ");
  1310. X    ultstr(0,(unsigned long)ctlength,num);elog(num);elog(" bytes\n");
  1311. X      }
  1312. X   }
  1313. X  while(buffilled||!lnl||buflast!=EOF)     /* continue the quest, line by line */
  1314. X   { if(!buffilled)                      /* is it really empty? */
  1315. X    readhead();                      /* read the next field */
  1316. X     if(!babyl||babylstart)           /* don't split BABYL files everywhere */
  1317. X      { if(rdheader)            /* anything looking like a header found? */
  1318. X     { if(eqFrom_(chp=rdheader->fld_text))          /* check if it's From_ */
  1319. Xfromanyway: { register size_t k;
  1320. X          if(split&&
  1321. X         (lnl||every)&&           /* more thorough check for a postmark */
  1322. X         (k=strcspn(chp=skpspace(chp+STRLEN(From_))," \t\n"))&&
  1323. X         *skpspace(chp+k)!='\n')
  1324. X         goto accuhdr;             /* ok, postmark found, split it */
  1325. X          if(bogus)                           /* disarm */
  1326. X         lputssn(escap,escaplen);
  1327. X        }
  1328. X       else if(split&&digest&&(lnl||every)&&digheadr())      /* digest? */
  1329. Xaccuhdr:    { for(i=minfields;--i&&readhead()&&digheadr();); /* found enough */
  1330. X          if(!i)                       /* then split it! */
  1331. Xsplitit:       { if(!lnl)   /* did the previous mail end with an empty line? */
  1332. X            lputcs('\n');              /* but now it does :-) */
  1333. X         logfolder();
  1334. X         if(fclose(mystdout)==EOF||errout==EOF)
  1335. X          { split= -1;
  1336. X            if(!quiet)
  1337. X               nlog(couldntw),elog(", continuing...\n");
  1338. X          }
  1339. X         if(!nowait&&*argv)     /* wait till the child has finished */
  1340. X          { int excode;
  1341. X            if((excode=waitfor(child))!=EX_OK&&retval!=EX_OK)
  1342. X               retval=excode;
  1343. X          }
  1344. X         if(!nrtotal)
  1345. X            goto onlyhead;
  1346. X         startprog((const char*Const*)argv);
  1347. X         goto startover;
  1348. X           }                    /* and there we go again */
  1349. X        }
  1350. X     }
  1351. X    else if(eqFrom_(buf))             /* special case, From_ line */
  1352. X     { addbuf();               /* add it manually, readhead() didn't */
  1353. X       goto fromanyway;
  1354. X     }
  1355. X    else if(split&&digest&&(lnl||every)&&artheadr())
  1356. X       goto accuhdr;
  1357. X      }
  1358. X#ifdef MAILBOX_SEPARATOR
  1359. X     if(!strncmp(emboxsep,buf,STRLEN(emboxsep)))         /* end of mail? */
  1360. X      { if(split)               /* gobble up the next start separator */
  1361. X     { buffilled=0;
  1362. X#ifdef sMAILBOX_SEPARATOR
  1363. X       getline();buffilled=0;         /* but only if it's defined */
  1364. X#endif
  1365. X       if(buflast!=EOF)                       /* if any */
  1366. X          goto splitit;
  1367. X       break;
  1368. X     }
  1369. X    else if(bogus)
  1370. X       goto putsp;                   /* escape it with a space */
  1371. X      }
  1372. X     else if(!strncmp(smboxsep,buf,STRLEN(smboxsep)&&bogus))
  1373. Xputsp:    lputcs(' ');
  1374. X#endif /* MAILBOX_SEPARATOR */
  1375. X     lnl=buffilled==1;              /* check if we just read an empty line */
  1376. X     if(babyl&&*buf==BABYL_SEP1)
  1377. X    babylstart=1,closemine(),opensink();         /* discard the rest */
  1378. X     if(areply&&bogus)                      /* escape the body */
  1379. X    if(fldp=rdheader)          /* we already read some "valid" fields */
  1380. X     { register char*p;
  1381. X       rdheader=0;
  1382. X       do                   /* careful, they can contain newlines */
  1383. X        { fp2=fldp->fld_next;chp=fldp->fld_text;
  1384. X          do
  1385. X           { lputssn(escap,escaplen);
  1386. X         lputssn(chp,(p=strchr(chp,'\n')+1)-chp);
  1387. X           }
  1388. X          while((chp=p)<(char*)fldp->fld_text+fldp->tot_len);
  1389. X          free(fldp);                    /* delete it */
  1390. X        }
  1391. X       while(fldp=fp2);               /* escape all fields we found */
  1392. X     }
  1393. X    else
  1394. X     { if(buffilled>1)      /* we don't escape empty lines, looks neat */
  1395. X          lputssn(escap,escaplen);
  1396. X       goto flbuf;
  1397. X     }
  1398. X     else if(rdheader)
  1399. X      { struct field*ox,*oX;
  1400. X    ox=xheader;oX=Xheader;xheader=Xheader=0;flushfield(&rdheader);
  1401. X    xheader=ox;Xheader=oX; /* beware, after this buf can still be filled */
  1402. X      }
  1403. X     else
  1404. Xflbuf:    lputssn(buf,buffilled),buffilled=0;
  1405. X   }                   /* make sure the mail ends with an empty line */
  1406. X  logfolder();
  1407. Xonlyhead:
  1408. X  closemine();
  1409. X  ;{ int excode;                    /* wait for everyone */
  1410. X     while((excode=waitfor((pid_t)0))!=NO_PROCESS)
  1411. X    if(retval==EX_OK&&excode!=EX_OK)
  1412. X       retval=excode;
  1413. X   }
  1414. X  if(retval<0)
  1415. X     retval=EX_UNAVAILABLE;
  1416. X  return retval!=EX_OK?retval:split<0?EX_IOERR:EX_OK;
  1417. X}
  1418. X
  1419. XeqFrom_(a)const char*const a;
  1420. X{ return !strncmp(a,From_,STRLEN(From_));
  1421. X}
  1422. X
  1423. Xint breakfield(line,len)const char*const line;size_t len;  /* look where the */
  1424. X{ const char*p=line;               /* fieldname ends (RFC 822 specs) */
  1425. X  if(eqFrom_(p))                      /* special case, From_ */
  1426. X     return STRLEN(From_);
  1427. X  while(len&&!iscntrl(*p))            /* no control characters allowed */
  1428. X   { switch(*p++)
  1429. X      { default:len--;
  1430. X       continue;
  1431. X    case HEAD_DELIMITER:len=p-line;
  1432. X       return len==1?0:len;                      /* eureka! */
  1433. X    case ' ':p--;                    /* no spaces allowed */
  1434. X      }
  1435. X     break;
  1436. X   }
  1437. X  return -(int)(p-line);    /* sorry, does not seem to be a legitimate field */
  1438. X}
  1439. END_OF_FILE
  1440.   if test 28361 -ne `wc -c <'procmail-3.03/src/formail.c'`; then
  1441.     echo shar: \"'procmail-3.03/src/formail.c'\" unpacked with wrong size!
  1442.   fi
  1443.   # end of 'procmail-3.03/src/formail.c'
  1444. fi
  1445. if test -f 'procmail-3.03/src/mailfold.h' -a "${1}" != "-c" ; then 
  1446.   echo shar: Will not clobber existing file \"'procmail-3.03/src/mailfold.h'\"
  1447. else
  1448.   echo shar: Extracting \"'procmail-3.03/src/mailfold.h'\" \(1005 characters\)
  1449.   sed "s/^X//" >'procmail-3.03/src/mailfold.h' <<'END_OF_FILE'
  1450. X/*$Id: mailfold.h,v 1.11 1994/05/26 14:13:06 berg Exp $*/
  1451. X
  1452. Xlong
  1453. X dump P((const s,const char*source,long len));
  1454. Xint
  1455. X deliver P((char*boxname,char*linkfolder));
  1456. Xvoid
  1457. X logabstract P((const char*const lstfolder)),
  1458. X concon P((const ch)),
  1459. X readmail P((int rhead,const long tobesent));
  1460. Xchar
  1461. X *findtstamp P((const char*start,const char*end));
  1462. X
  1463. Xextern int logopened,tofile;
  1464. Xextern off_t lasttell;
  1465. X
  1466. X#define to_FILE        1          /* when we are writing a real file */
  1467. X#define to_FOLDER    2         /* when we are writing a filefolder */
  1468. X
  1469. X#ifdef sMAILBOX_SEPARATOR
  1470. X#define smboxseparator(fd)    (tofile==to_FOLDER&&\
  1471. X (part=len,rwrite(fd,sMAILBOX_SEPARATOR,STRLEN(sMAILBOX_SEPARATOR))))
  1472. X#define MAILBOX_SEPARATOR
  1473. X#else
  1474. X#define smboxseparator(fd)
  1475. X#endif /* sMAILBOX_SEPARATOR */
  1476. X#ifdef eMAILBOX_SEPARATOR
  1477. X#define emboxseparator(fd)    \
  1478. X (tofile==to_FOLDER&&rwrite(fd,eMAILBOX_SEPARATOR,STRLEN(eMAILBOX_SEPARATOR)))
  1479. X#ifndef MAILBOX_SEPARATOR
  1480. X#define MAILBOX_SEPARATOR
  1481. X#endif
  1482. X#else
  1483. X#define emboxseparator(fd)
  1484. X#endif /* eMAILBOX_SEPARATOR */
  1485. END_OF_FILE
  1486.   if test 1005 -ne `wc -c <'procmail-3.03/src/mailfold.h'`; then
  1487.     echo shar: \"'procmail-3.03/src/mailfold.h'\" unpacked with wrong size!
  1488.   fi
  1489.   # end of 'procmail-3.03/src/mailfold.h'
  1490. fi
  1491. echo shar: End of archive 3 \(of 10\).
  1492. cp /dev/null ark3isdone
  1493. MISSING=""
  1494. for I in 1 2 3 4 5 6 7 8 9 10 ; do
  1495.     if test ! -f ark${I}isdone ; then
  1496.     MISSING="${MISSING} ${I}"
  1497.     fi
  1498. done
  1499. if test "${MISSING}" = "" ; then
  1500.     echo You have unpacked all 10 archives.
  1501.     rm -f ark[1-9]isdone ark[1-9][0-9]isdone
  1502. else
  1503.     echo You still must unpack the following archives:
  1504.     echo "        " ${MISSING}
  1505. fi
  1506. exit 0
  1507. exit 0 # Just in case...
  1508.