home *** CD-ROM | disk | FTP | other *** search
- From: berg@pool.informatik.rwth-aachen.de (Stephen R. van den Berg)
- Newsgroups: comp.sources.misc
- Subject: v43i058: procmail - mail processing package v3.03, Part03/10
- Date: 5 Jul 1994 20:49:42 -0500
- Organization: Sterling Software
- Sender: kent@sparky.sterling.com
- Approved: kent@sparky.sterling.com
- Message-ID: <2vd2jm$i5u@sparky.sterling.com>
- X-Md4-Signature: 10287c58589e11102cb71e36609a3c5c
-
- Submitted-by: berg@pool.informatik.rwth-aachen.de (Stephen R. van den Berg)
- Posting-number: Volume 43, Issue 58
- Archive-name: procmail/part03
- Environment: sendmail, ZMailer, smail, MMDF, mailsurr, UNIX, POSIX
- Supersedes: procmail: Volume 38, Issue 19-31
-
- #! /bin/sh
- # This is a shell archive. Remove anything before this line, then feed it
- # into a shell via "sh file" or similar. To overwrite existing files,
- # type "sh file -c".
- # Contents: procmail-3.03/man/procmailrc.man
- # procmail-3.03/src/formail.c procmail-3.03/src/mailfold.h
- # Wrapped by kent@sparky on Tue Jul 5 20:42:12 1994
- PATH=/bin:/usr/bin:/usr/ucb:/usr/local/bin:/usr/lbin:$PATH ; export PATH
- echo If this archive is complete, you will see the following message:
- echo ' "shar: End of archive 3 (of 10)."'
- if test -f 'procmail-3.03/man/procmailrc.man' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'procmail-3.03/man/procmailrc.man'\"
- else
- echo shar: Extracting \"'procmail-3.03/man/procmailrc.man'\" \(21444 characters\)
- sed "s/^X//" >'procmail-3.03/man/procmailrc.man' <<'END_OF_FILE'
- XPlease read the README file in this directory first.
- X.ex
- X.Id $Id: procmailrc.man,v 1.41 1994/05/26 14:12:11 berg Exp $
- X.TH PROCMAILRC 5 \*(Dt BuGless
- X.na
- X.SH NAME
- Xprocmailrc \- procmail rcfile
- X.SH SYNOPSIS
- X.B $HOME/@PROCMAILRC@
- X.ad
- X.SH DESCRIPTION
- XFor a quick start, see
- X.B NOTES
- Xat the end of the
- X.BR procmail (1)
- Xman page.
- X.PP
- XThe rcfile can contain a mixture of environment variable assignments (some
- Xof which have special meanings to procmail), and recipes. In their most
- Xsimple appearance, the recipes are simply one line regular expressions
- Xthat are searched for in the header of the arriving mail, the first recipe
- Xthat matches is used to determine where the mail has to go (usually a file).
- X.PP
- XIf a matching recipe does not specify any special flags (like `@FILTER@' or
- X`@CONTINUE@') and the recipe is successful (i.e. no write failures or other
- Xcalamities), then processing of the rcfile will cease at this point, and
- Xprocmail will consider the mail to have been delivered.
- X.PP
- XThis enables you to presort your mail extremely straightforward into several
- Xmailfolders. Bear in mind though that the mail can arrive concurrently in
- Xthese mailfolders (if several procmail programs happen to run at the same time,
- Xnot unlikely if a lot of mail arrives), to make sure this does not result in a
- Xmess, proper use of lockfiles is highly recommended.
- X.PP
- XThe environment variable
- X.B assignments
- Xand
- X.B recipes
- Xcan be freely intermixed in the rcfile. If any environment variable has
- Xa special meaning to procmail, it will be used appropriately the moment
- Xit is parsed. (i.e. you can change the current directory whenever you
- Xwant by specifying a new
- X.BR MAILDIR ,
- Xswitch lockfiles by specifying a new
- X.BR LOCKFILE ,
- Xchange the umask at any time, etc., the possibilities are endless :-).
- X.PP
- XThe assignments and substitutions of these environment variables are handled
- Xexactly like in
- X.BR sh (1)
- X(that includes all possible quotes and escapes),
- Xwith the added bonus that blanks around the '=' sign are ignored and that,
- Xif an environment variable appears without a trailing '=', it will be
- Xremoved from the environment. Any program in backquotes started by procmail
- Xwill have the entire mail at its stdin.
- X.PP
- X.SS Comments
- XA word beginning with # and all the following characters up to a NEWLINE
- Xare ignored.
- X.SS Recipes
- X.PP
- XA line starting with ':' marks the beginning of a recipe. It has the
- Xfollowing format:
- X.Sx 3
- X: [\fInumber\fP] [\fIflags\fP] [ : [\fIlocallockfile\fP] ]
- X<zero or more conditions (one per line)>
- X<exactly one action line>
- X.Ex
- XThe
- X.I number
- Xis optional (defaults to 1) and specifies the number of conditions that
- Xfollow the first line of the recipe. Conditions are complete lines that are
- Xpassed on to the internal egrep
- X.BR literally ,
- Xexcept for leading and trailing whitespace. If you start every condition
- Xline with an `*', you do not need to specify
- X.IR number .
- XWhitespace after the leading `*' are ignored. The safest way would be
- Xto specify
- X.I number
- Xto be zero in that case (to avoid problems when you have no conditions, but
- Xprocmail expects one).
- XThese regular expressions are
- X.B completely
- Xcompatible to the normal
- X.BR egrep (1)
- Xregular expressions.
- X.PP
- XConditions are anded; if
- X.I number
- Xis zero, then the condition is always true and no conditions are expected
- Xnext.
- X.PP
- X.I Flags
- Xcan be any of the following:
- X.TP 0.5i
- X.B @HEAD_GREP@
- XEgrep the header (default).
- X.TP
- X.B @BODY_GREP@
- XEgrep the body.
- X.TP
- X.B @DISTINGUISH_CASE@
- XTell the internal egrep to distinguish between upper and lower case (contrary
- Xto the default which is to ignore case).
- X.TP
- X.B @ALSO_NEXT_RECIPE@
- XThis recipe will depend on the last preceding recipe (on the current
- Xblock-nesting level) without the `@ALSO_NEXT_RECIPE@' or `@ALSO_N_IF_SUCC@'
- Xflag. This allows you to chain actions that depend on a common condition.
- XThe number of conditions that are expected to follow default to none.
- X.TP
- X.B @ALSO_N_IF_SUCC@
- XHas the same meaning as the `@ALSO_NEXT_RECIPE@' flag, but will depend on the
- X.I successful
- Xcompletion of the immediately preceding recipe as well.
- X.Tp
- X.B @ELSE_DO@
- XThis recipe only executes if the immediately preceding recipe was not
- Xexecuted. Execution of this recipe also disables any immediately
- Xfollowing recipes with the '@ELSE_DO@' flag. This allows you to specify
- X`else if' actions.
- XThe number of conditions that are expected to follow default to none.
- X.Tp
- X.B @ERROR_DO@
- XThis recipe only executes if the immediately preceding recipe failed.
- XThis allows you to specify `error' actions.
- XThe number of conditions that are expected to follow default to none.
- X.TP
- X.B @PASS_HEAD@
- XFeed the header to the pipe (default).
- X.TP
- X.B @PASS_BODY@
- XFeed the body to the pipe (default).
- X.TP
- X.B @FILTER@
- XConsider the pipe as a filter.
- X.TP
- X.B @CONTINUE@
- XContinue processing the rcfile even if this recipe matches (not needed
- Xwhen `@FILTER@' is specified). On nesting blocks this will clone the
- Xrunning procmail process (lockfiles can not be inherited).
- X.TP
- X.B @WAIT_EXIT@
- XWait for the filter or program to finish and check its exitcode (normally
- Xignored); if the filter is unsuccessful, then the text will not have been
- Xfiltered.
- X.TP
- X.B @WAIT_EXIT_QUIET@
- XHas the same meaning as the `@WAIT_EXIT@' flag, but will suppress any
- X`Program failure' message.
- X.TP
- X.B @IGNORE_WRITERR@
- XIgnore any write errors on this recipe (i.e. usually due to an early closed
- Xpipe).
- X.PP
- XThere are some special conditions you can use that are not straight regular
- Xexpressions. To select them, the first character of the condition must
- Xbe a:
- X.TP 0.5i
- X.B !
- XInvert the condition.
- X.TP
- X.B $
- XEvaluate the remainder according to
- X.BR sh (1)
- Xsubstitution rules inside double quotes, skip leading whitespace,
- Xthen reparse it.
- X.TP
- X.B ?
- XUse the exitcode of the specified program.
- X.TP
- X.B <
- XCheck if the total length of the mail is shorter than the specified (in
- Xdecimal) number of bytes.
- X.TP
- X.B >
- XAnalogous to '<'.
- X.TP
- X.B \e
- XTo quote any of the above at the start of the line.
- X.SS "Local lockfile"
- X.PP
- XIf you put a second (trailing) ':' on the first recipe line, then procmail
- Xwill use a
- X.I locallockfile
- X(for this recipe only). You can optionally specify the locallockfile
- Xto use; if you don't however, procmail will use the destination filename
- X(or the filename following the first '>>') and will append $LOCKEXT to it.
- X.SS "Recipe action line"
- X.PP
- XThe action line can start with the following characters:
- X.TP
- X.B !
- XForwards to all the specified mail addresses.
- X.TP
- X.B |
- XStarts the specified program, possibly in $SHELL if any
- Xof the characters $SHELLMETAS are spotted. You can optionally prepend this
- Xpipe symbol with
- X.IR variable= ,
- Xwhich will cause stdout of the program to be captured in the environment
- X.IR variable .
- XIf you specify just this pipe symbol, without any program, then procmail will
- Xpipe the mail to stdout.
- X.TP
- X.B {
- XFollowed by at least one space, tab or newline will mark the start of a
- Xnesting block. Everything up till the next closing brace will depend on
- Xthe conditions specified for this recipe. Unlimited nesting is permitted.
- X.PP
- XAnything else will be taken as a mailbox name (either a filename or a
- Xdirectory, absolute or relative to the current directory (see MAILDIR)).
- XIf it is a filename (or nonexistent), the mail will be appended to it.
- X.PP
- XIf it is a directory, the mail will be delivered to a newly created, guaranteed
- Xto be unique file named $MSGPREFIX* in the specified directory. If the
- Xdirectory name ends in "@MCDIRSEP@@chCURDIR@", then this directory is presumed
- Xto be an MH folder; i.e. procmail will use the next number it finds available.
- XWhen procmail is delivering to directories, you can specify multiple
- Xdirectories to deliver to (using hardlinks).
- X.SS "Environment variable defaults"
- X.TP 2.2i
- X.B "LOGNAME, HOME and SHELL"
- XYour (the recipient's) defaults
- X.TP
- X.B SHELLMETAS
- X\&@DEFshellmetas@
- X.TP
- X.B SHELLFLAGS
- X\&@DEFshellflags@
- X.TP
- X.BR ORGMAIL
- X\&@SYSTEM_MBOX@
- X.TP
- X.B MAILDIR
- X\&@DEFmaildir@
- X.br
- X(Unless the name of the first successfully opened rcfile starts with
- X`@chCURDIR@@MCDIRSEP@', in which case it defaults to `@chCURDIR@')
- X.TP
- X.B DEFAULT
- X\&@DEFdefault@
- X.TP
- X.B MSGPREFIX
- X\&@DEFmsgprefix@
- X.TP
- X.B SENDMAIL
- X\&@DEFsendmail@
- X.TP
- X.B HOST
- XThe current hostname
- X.TP
- X.B COMSAT
- X\&@DEFcomsat@
- X.br
- X(If an rcfile is specified on the command line)
- X.TP
- X.B LOCKEXT
- X\&@DEFlockext@@PRESTENV@@LD_ENV_FIX@
- X.SS Environment
- X.PP
- XBefore you get lost in the multitude of environment variables, keep in mind
- Xthat all of them have reasonable defaults.
- X.TP 1.2i
- X.B MAILDIR
- XCurrent directory while procmail is executing (that means that all paths
- Xare relative to $MAILDIR).
- X.TP
- X.B DEFAULT
- XDefault
- X.B mailbox
- Xfile (if not told otherwise, procmail will dump mail in this mailbox).
- XProcmail will automatically use $DEFAULT$LOCKEXT as lockfile prior to writing
- Xto this mailbox.
- X.TP
- X.B LOGFILE
- XThis file will also contain any error or diagnostic messages from procmail
- X(normally none :-) or any other programs started by procmail. If this file
- Xis not specified, any diagnostics or error messages will
- X@pconsole@@console@@aconsole@
- XSee also
- X.BR LOGABSTRACT .
- X.TP
- X.B VERBOSE
- XYou can turn on
- X.I extended diagnostics
- Xby setting this variable to `yes' or `on', to turn it off again set it to `no'
- Xor `off'.
- X.TP
- X.B LOGABSTRACT
- XJust before procmail exits it logs an abstract of the delivered message in
- X$LOGFILE showing the `@FROM@' and `Subject:' fields of the header, what folder
- Xit finally went to and how long (in bytes) the message was. By setting this
- Xvariable to `no', generation of this abstract is suppressed.
- X.TP
- X.B LOG
- XAnything assigned to this variable will be appended to $LOGFILE.
- X.TP
- X.B ORGMAIL
- XUsually the system mailbox (\fBOR\fPi\fBG\fPinal \fBMAIL\fPbox). If, for
- Xsome obscure reason (like `\fBfilesystem full\fP') the mail could not be
- Xdelivered, then this mailbox will be the last resort. If procmail
- Xfails to save the mail in here (deep, deep trouble :-), then the mail
- Xwill bounce back to the sender.
- X.TP
- X.B LOCKFILE
- XGlobal semaphore file. If this file already exists, procmail
- Xwill wait until it has gone before proceeding, and will create it itself
- X(cleaning it up when ready, of course). If more than one
- X.I lockfile
- Xare specified, then the previous one will be removed before trying to create
- Xthe new one. The use of a global lockfile is discouraged, whenever possible
- Xuse locallockfiles (on a per recipe basis) instead.
- X.TP
- X.B LOCKEXT
- XDefault extension that is appended to a destination file to determine
- Xwhat local
- X.I lockfile
- Xto use (only if turned on, on a per-recipe basis).
- X.TP
- X.B LOCKSLEEP
- XNumber of seconds procmail will sleep before retrying on a
- X.I lockfile
- X(if it already existed); if not specified, it defaults to @DEFlocksleep@
- Xseconds.
- X.TP
- X.B LOCKTIMEOUT
- XNumber of seconds that have to have passed since a
- X.I lockfile
- Xwas last modified/created before procmail decides that this must be an
- Xerroneously leftover lockfile that can be removed by force now. If zero,
- Xthen no timeout will be used and procmail will wait forever until the
- Xlockfile is removed; if not specified, it defaults to @DEFlocktimeout@ seconds.
- XThis variable is useful to prevent indefinite hangups of
- X.BR sendmail /procmail.
- XProcmail is immune to clock skew across machines.
- X.TP
- X.B TIMEOUT
- XNumber of seconds that have to have passed before procmail decides that
- Xsome child it started must be hanging. The offending program will receive
- Xa TERMINATE signal from procmail, and processing of the rcfile will continue.
- XIf zero, then no timeout will be used and procmail will wait forever until the
- Xchild has terminated; if not specified, it defaults to @DEFtimeout@ seconds.
- X.TP
- X.B MSGPREFIX
- XFilename prefix that is used when delivering to a directory (not used when
- Xdelivering to an MH directory).
- X.TP
- X.B HOST
- XIf this is not the
- X.I hostname
- Xof the machine, processing of the current
- X.I rcfile
- Xwill immediately cease. If other rcfiles were specified on the
- Xcommand line, processing will continue with the next one. If all rcfiles
- Xare exhausted, the program will terminate, but will not generate an error
- X(i.e. to the mailer it will seem that the mail has been delivered).
- X.TP
- X.B UMASK
- XThe name says it all (if it doesn't, then forget about this one :-).
- XAnything assigned to UMASK is taken as an
- X.B octal
- Xnumber. If not specified, the umask defaults to @INIT_UMASK@. If the umask
- Xpermits o+x, all the mailboxes procmail delivers to directly will receive
- Xan o+x mode change. This can be used to check if new mail arrived.
- X.TP
- X.B SHELLMETAS
- XIf any of the characters in SHELLMETAS appears in the line specifying
- Xa filter or program, the line will be fed to $SHELL
- Xinstead of being executed directly.
- X.TP
- X.B SHELLFLAGS
- XAny invocation of $SHELL will be like:
- X.br
- X"$SHELL" "$SHELLFLAGS" "$*";
- X.TP
- X.B SENDMAIL
- XIf you're not using the
- X.I forwarding
- Xfacility don't worry about this one. It specifies the program being
- Xcalled to forward any mail.
- X.br
- XIt gets invoked as: "$SENDMAIL" "$@";
- X.TP
- X.B NORESRETRY
- XNumber of retries that are to be made if any `\fBprocess table full\fP',
- X`\fBfile table full\fP', `\fBout of memory\fP' or
- X`\fBout of swap space\fP' error should occur. If this number is negative,
- Xthen procmail will retry indefinitely; if not specified, it defaults to
- X@DEFnoresretry@ times. The retries occur with a $SUSPEND second interval. The
- Xidea behind this is, that if e.g. the
- X.I swap
- X.I space
- Xhas been exhausted or the
- X.I process
- X.I table
- Xis full, usually several other programs will either detect this as well
- Xand abort or crash 8-), thereby freeing valuable
- X.I resources
- Xfor procmail.
- X.TP
- X.B SUSPEND
- XNumber of seconds that procmail will pause if it has to wait for something
- Xthat is currently unavailable (memory, fork, etc.); if not specified, it will
- Xdefault to @DEFsuspend@ seconds. See also:
- X.BR LOCKSLEEP .
- X.TP
- X.B LINEBUF
- XLength of the internal line buffers, cannot be set smaller than @MINlinebuf@.
- XAll lines read from the
- X.I rcfile
- Xshould not exceed $LINEBUF characters before and after expansion. If not
- Xspecified, it defaults to @DEFlinebuf@. This limit, of course, does
- X.I not
- Xapply to the mail itself, which can have arbitrary line lengths, or could
- Xbe a binary file for that matter.
- X.TP
- X.B DELIVERED
- XIf set to `yes' procmail will pretend (to the mail agent) the mail
- Xhas been delivered. If mail cannot be delivered after meeting this
- Xassignment (to `yes'), the mail will be lost (i.e. it will not bounce).
- X.TP
- X.B TRAP
- XWhen procmail terminates it will execute the contents of this variable.
- XA copy of the mail can be read from stdin. Any output produced by this
- Xcommand will be appended to $LOGFILE. Possible uses for TRAP are: removal
- Xof temporary files, logging customised abstracts, etc. See also
- X.B EXITCODE
- Xand
- X.BR LOGABSTRACT .
- X.Tp
- X.B EXITCODE
- XWhen procmail terminates and this variable has been set to a positive numeric
- Xvalue, procmail will use this as the exitcode. If this variable is set but
- Xempty, procmail will set the exitcode to whatever the
- X.B TRAP
- Xprogram returns.
- XIf this variable has not been set, procmail will set it shortly before calling
- Xup the
- X.B TRAP
- Xprogram.
- X.TP
- X.B LASTFOLDER
- XThis variable is assigned to by procmail whenever it is delivering
- Xto a folder or program. It always contains the name of the last folder
- X(or program) procmail delivered to.
- X.Tp
- X.B SHIFT
- XAssigning a positive value to this variable has the same effect as
- Xthe `shift' command in
- X.BR sh (1).
- XThis command is most useful to extract extra arguments passed to procmail
- Xwhen acting as a generic mailfilter.
- X.TP
- X.B INCLUDERC
- XNames an rcfile (relative to the current directory) which will be included
- Xhere as if it were part of the current rcfile. Unlimited nesting is
- Xpermitted.
- X.TP
- X.B COMSAT
- X.BR Comsat (8)/ biff (1)
- Xnotification is on by default, it can be turned off by setting this variable
- Xto `no'. Alternatively the biff-service can be customised by setting it to
- Xeither `service@SERV_ADDRsep@', `@SERV_ADDRsep@hostname', or
- X`service@SERV_ADDRsep@hostname'. When not specified it defaults
- Xto @COMSATservice@@SERV_ADDRsep@@COMSAThost@.@DROPPRIVS@
- X.SH EXAMPLES
- XLook in the
- X.BR procmailex (5)
- Xman page.
- X.SH CAVEATS
- XContinued lines in an action line that specifies a program always have to end
- Xin a backslash, even if the underlying shell would not need or want the
- Xbackslash to indicate continuation. This is due to the two pass parsing
- Xprocess needed (first procmail, then the shell (or not, depending on
- X.BR SHELLMETAS )).
- X.PP
- XDon't put comments on the regular expression condition lines in a
- Xrecipe, these lines are fed to the internal egrep
- X.I literally
- X(except for continuation backslashes at the end of a line).
- X.PP
- XLeading whitespace on continued regular expression condition lines
- Xis usually ignored (so that they can be indented), but
- X.B not
- Xon continued condition lines that are evaluated according to the
- X.BR sh (1)
- Xsubstitution rules inside double quotes.
- X.PP
- XWatch out for deadlocks when doing unhealthy things like forwarding mail
- Xto your own account. Deadlocks can be broken by proper use of
- X.BR LOCKTIMEOUT .
- X.PP
- XAny default values that procmail has for some environment variables will
- X.B always
- Xoverride the ones that were already defined. If you really want to
- Xoverride the defaults, you either have to put them in the
- X.B rcfile
- Xor on the command line as arguments.
- X.PP
- XEnvironment variables set
- X.B inside
- Xthe action part of a recipe will
- X.B not
- Xretain their value after the recipe has finished since they are set in a
- Xsubshell of procmail. To make sure the value of an environment variable is
- Xretained you have to put the assignment to the variable before the leading `|'
- Xof a recipe, so that it can capture stdout of the program.
- X.PP
- XIf you specify only a `@PASS_HEAD@' or a `@PASS_BODY@' flag on a recipe,
- Xand the recipe matches, then, unless a `@FILTER@' or `@CONTINUE@' flag is
- Xpresent as well, the body respectively the header of the mail will be silently
- Xlost.
- X.PP
- XThe `@CONTINUE@' flag defaults to on when capturing stdout of a recipe in an
- Xenvironment variable.
- X.SH "SEE ALSO"
- X.na
- X.nh
- X.BR procmail (1),
- X.BR procmailsc (5),
- X.BR procmailex (5),
- X.BR sh (1),
- X.BR csh (1),
- X.BR mail (1),
- X.BR mailx (1),
- X.BR binmail (1),
- X.BR uucp (1),
- X.BR aliases (5),
- X.BR sendmail (8),
- X.BR egrep (1),
- X.BR grep (1),
- X.BR biff (1),
- X.BR comsat (8),
- X.BR lockfile (1),
- X.BR formail (1)
- X.hy
- X.ad
- X.SH BUGS
- XThe only substitutions of environment variables that can be handled by
- Xprocmail itself are of the type $name, ${name}, ${name:-text}, ${name:+text},
- X${name-text}, ${name+text}, $#, $n, $$, $?, $_, $\- and $=; whereas $_ will be
- Xsubstituted by the name of the current rcfile, $\- by $LASTFOLDER and $=
- Xwill contain the score of the last recipe.
- XWhen the
- X.B \-@ARGUMENTOPT@
- Xor
- X.B \-@MAILFILTOPT@
- Xoptions are used, "$@" will expand to respectively the specified argument
- Xor the sender and recipient list; but only when passed as in the
- Xargument list to a program.@UPPERCASE_USERNAMES@
- X.PP
- XProcmail does not support the expansion of `~'.
- X.PP
- XA line buffer of length $LINEBUF is used when processing the
- X.IR rcfile ,
- Xany expansions
- X.B have
- Xto fit within this limit; if they don't, behaviour is undefined.
- X.PP
- XIf the global lockfile has a
- X.I relative
- Xpath, and the current directory
- Xis not the same as when the global lockfile was created, then the global
- Xlockfile will not be removed if procmail exits at that point (remedy:
- Xuse
- X.I absolute
- Xpaths to specify global lockfiles).
- X.PP
- XWhen capturing stdout from a recipe into an environment variable, exactly
- Xone trailing newline will be stripped.
- X.PP
- XBy using the `^' or `$' in other spots than at the start respectively
- Xend of a regular expression you can use the internal egrep to do multiline
- Xmatches.
- X.PP
- XWhen the regular expression starts with `^^' it will anchor the match
- Xat the very start of the text.
- X.PP
- XThe start and end of a word can be matched by `\e<' and `\e>'. They
- Xare merely a shorthand for `[^a-zA-Z0-9_]', but can also match newlines.
- XSince they match actual characters, they are only suitable to delimit
- Xwords, not to delimit inter-word space.
- X.SH MISCELLANEOUS
- XIf the regular expression contains `\fB@TOkey@\fP' it will be substituted by
- X.na
- X.nh
- X`\fB@TOsubstitute@\fP',
- Xwhich should catch all destination specifications.
- X.hy
- X.ad
- X.PP
- XIf the regular expression contains `\fB@FROMDkey@\fP' it will be
- Xsubstituted by
- X.na
- X.nh
- X`\fB@FROMDsubstitute@\fP',
- Xwhich should catch mails coming from most daemons (how's that for a regular
- Xexpression :-).
- X.hy
- X.ad
- X.PP
- XIf the regular expression contains `\fB@FROMMkey@\fP' it will be
- Xsubstituted by
- X.na
- X.nh
- X`\fB@FROMMsubstitute@\fP'
- X(a stripped down version of `\fB@FROMDkey@\fP'),
- Xwhich should catch mails coming from most mailer-daemons.
- X.hy
- X.ad
- X.PP
- XWhen assigning boolean values to variables like VERBOSE, DELIVERED or COMSAT,
- Xprocmail accepts as true every string starting with: a non-zero value, `on',
- X`y', `t' or `e'. False is every string starting with: a zero value, `off',
- X`n', `f' or 'd'.
- X.PP
- XIf the action line of a recipe specifies a program, a sole backslash-newline
- Xpair in it on an otherwise empty line will be converted into a newline.
- X.SH NOTES
- XSince unquoted leading whitespace is generally ignored in the rcfile you can
- Xindent everything to taste.
- X.PP
- XThe leading `|' on the action line to specify a program or filter is stripped
- Xbefore checking for $SHELLMETAS.
- X.PP
- XFiles included with the INCLUDERC directive containing only environment
- Xvariable assignments can be shared with sh.
- X.PP
- XFor
- X.I really
- Xcomplicated processing you can even consider calling
- X.B procmail
- Xrecursively.
- END_OF_FILE
- if test 21444 -ne `wc -c <'procmail-3.03/man/procmailrc.man'`; then
- echo shar: \"'procmail-3.03/man/procmailrc.man'\" unpacked with wrong size!
- fi
- # end of 'procmail-3.03/man/procmailrc.man'
- fi
- if test -f 'procmail-3.03/src/formail.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'procmail-3.03/src/formail.c'\"
- else
- echo shar: Extracting \"'procmail-3.03/src/formail.c'\" \(28361 characters\)
- sed "s/^X//" >'procmail-3.03/src/formail.c' <<'END_OF_FILE'
- X/************************************************************************
- X * formail - The mail (re)formatter *
- X * *
- X * Seems to be relatively bug free. *
- X * *
- X * Copyright (c) 1990-1994, S.R. van den Berg, The Netherlands *
- X * #include "../README" *
- X ************************************************************************/
- X#ifdef RCS
- Xstatic /*const*/char rcsid[]=
- X "$Id: formail.c,v 1.53 1994/06/28 16:56:10 berg Exp $";
- X#endif
- Xstatic /*const*/char rcsdate[]="$Date: 1994/06/28 16:56:10 $";
- X#include "includes.h"
- X#include <ctype.h> /* iscntrl() */
- X#include "formail.h"
- X#include "acommon.h"
- X#include "sublib.h"
- X#include "shell.h"
- X#include "common.h"
- X#include "fields.h"
- X#include "ecommon.h"
- X#include "formisc.h"
- X
- X#define ssl(str) str,STRLEN(str)
- X#define bsl(str) {ssl(str)}
- X#define sslbar(str,bar1,bar2) {ssl(str),STRLEN(bar1)-1,STRLEN(bar2)-1}
- X
- Xstatic const char
- X#define X(name,value) name[]=value,
- X#include "header.h" /* pull in the definitions */
- X#undef X
- X From_[]= FROM, /* VNIX 'From ' line */
- X Article_[]= "Article ", /* USENET 'Article ' line */
- X x_[]= "X-", /* general extension */
- X old_[]= OLD_PREFIX, /* my extension */
- X xloop[]= "X-Loop:", /* ditto ... */
- X unknown[]=UNKNOWN,re[]=" Re:",fmusage[]=FM_USAGE;
- X
- Xstatic const struct {const char*hedr;int lnr;}cdigest[]=
- X{
- X#define X(name,value) bsl(name),
- X#include "header.h" /* pull in the precalculated references */
- X#undef X
- X};
- X
- X/*
- X * sender determination fields in order of importance/reliability
- X * reply-address determination fields (wrepl specifies the weight
- X * for regular replies, wtrepl specifies the weight for trusted users)
- X *
- X * I bet this is the first time you see a bar graph in C-source-code :-)
- X */
- Xstatic const struct {const char*head;int len,wrepl,wtrepl;}sest[]=
- X{ sslbar(replyto ,"******" ,"********" ),
- X sslbar(Fromm ,"*" ,"*******" ),
- X sslbar(retreceiptto ,"********" ,"*****" ),
- X sslbar(sender ,"*****" ,"******" ),
- X sslbar(res_replyto ,"***********" ,"***********" ),
- X sslbar(res_from ,"***foo***" ,"***bar****" ),
- X sslbar(res_sender ,"**********" ,"*********" ),
- X sslbar(errorsto ,"*******" ,"****" ),
- X sslbar(path ,"**" ,"*" ),
- X sslbar(returnpath ,"***" ,"***" ),
- X sslbar(From_ ,"****" ,"**" )
- X};
- X
- Xstatic struct saved rex[]=
- X{ bsl(subject),bsl(references),bsl(messageid),bsl(date)
- X};
- X#define subj (rex+0)
- X#define refr (rex+1)
- X#define msid (rex+2)
- X#define hdate (rex+3)
- X
- X#ifdef sMAILBOX_SEPARATOR
- X#define emboxsep smboxsep
- X#define MAILBOX_SEPARATOR
- Xstatic const char smboxsep[]=sMAILBOX_SEPARATOR;
- X#endif /* sMAILBOX_SEPARATOR */
- X#ifdef eMAILBOX_SEPARATOR
- X#ifdef emboxsep
- X#undef emboxsep
- X#else
- X#define MAILBOX_SEPARATOR
- X#endif
- Xstatic const char emboxsep[]=eMAILBOX_SEPARATOR;
- X#endif /* eMAILBOX_SEPARATOR */
- X
- Xconst char binsh[]=BinSh,sfolder[]=FOLDER,
- X couldntw[]="Couldn't write to stdout";
- Xint errout,oldstdout,quiet=1,buflast,lenfileno;
- Xlong initfileno;
- Xchar ffileno[LEN_FILENO_VAR+8*sizeof(initfileno)*4/10+1+1]=DEFfileno;
- Xint lexitcode; /* dummy, for waitfor() */
- Xpid_t child= -1;
- Xunsigned long rhash;
- XFILE*mystdout;
- Xint nrskip,nrtotal= -1,retval=EX_OK;
- Xsize_t buflen,buffilled;
- Xlong totallen;
- Xchar*buf,*logsummary;
- Xstruct field*rdheader,*xheader,*Xheader,*uheader,*Uheader;
- Xstatic struct field*iheader,*Iheader,*aheader,*Aheader,*Rheader,*nheader;
- X
- Xstatic void logfolder P((void)) /* estimate the no. of characters needed to */
- X{ size_t i;charNUM(num,totallen); /* represent totallen */
- X static const char tabchar[]=TABCHAR;
- X if(logsummary)
- X { putssn(sfolder,STRLEN(sfolder));putssn(logsummary,i=strlen(logsummary));
- X i+=STRLEN(sfolder);i-=i%TABWIDTH;
- X do putssn(tabchar,STRLEN(tabchar));
- X while((i+=TABWIDTH)<LENoffset);
- X ultstr(7,totallen,num);putssn(num,strlen(num));putcs('\n');
- X }
- X}
- X /* checks if the last field in rdheader looks like a known digest header */
- Xstatic int digheadr P((void))
- X{ char*chp;int i;size_t j;struct field*fp;
- X for(fp=rdheader;fp->fld_next;fp=fp->fld_next); /* skip to the last */
- X i=maxindex(cdigest);chp=fp->fld_text;j=fp->id_len;
- X while((cdigest[i].lnr!=j||strnIcmp(cdigest[i].hedr,chp,j))&&i--);
- X return i>=0||j>STRLEN(old_)&&!strnIcmp(old_,chp,STRLEN(old_))||
- X j>STRLEN(x_)&&!strnIcmp(x_,chp,STRLEN(x_));
- X}
- X
- Xstatic int artheadr P((void)) /* could it be the start of an article? */
- X{ if(!rdheader&&!strncmp(buf,Article_,STRLEN(Article_)))
- X { addbuf();rdheader->id_len=STRLEN(Article_);
- X return 1;
- X }
- X return 0;
- X}
- X
- Xstatic PROGID;
- X
- Xmain(lastm,argv)int lastm;const char*const argv[];
- X{ int i,split=0,force=0,bogus=1,every=0,areply=0,trust=0,digest=0,nowait=0,
- X keepb=0,minfields=(char*)progid-(char*)progid,conctenate=0,babyl=0,
- X babylstart;
- X off_t maxlen,insoffs,ctlength;FILE*idcache=0;pid_t thepid;
- X size_t j,lnl,escaplen;char*chp,*namep,*escap=ESCAP;
- X struct field*fldp,*fp2,**afldp,*fdate,*fcntlength;
- X if(lastm) /* sanity check, any argument at all? */
- X#define Qnext_arg() if(!*chp&&!(chp=(char*)*++argv))goto usg
- X while(chp=(char*)*++argv)
- X { if((lastm= *chp++)==FM_SKIP)
- X goto number;
- X else if(lastm!=FM_TOTAL)
- X goto usg;
- X for(;;)
- X { switch(lastm= *chp++)
- X { case FM_TRUST:trust=1;
- X continue;
- X case FM_REPLY:areply=1;
- X continue;
- X case FM_FORCE:force=1;
- X continue;
- X case FM_EVERY:every=1;
- X continue;
- X case FM_BABYL:babyl=every=1;
- X case FM_DIGEST:digest=1;
- X continue;
- X case FM_NOWAIT:nowait=1;
- X continue;
- X case FM_KEEPB:keepb=1;
- X continue;
- X case FM_CONCATENATE:conctenate=1;
- X continue;
- X case FM_QUIET:quiet=1;
- X if(*chp=='-')
- X chp++,quiet=0;
- X continue;
- X case FM_LOGSUMMARY:Qnext_arg();
- X if(strlen(logsummary=chp)>MAXfoldlen)
- X chp[MAXfoldlen]='\0';
- X detab(chp);
- X break;
- X case FM_SPLIT:split=1;
- X if(!*chp)
- X { ++argv;
- X goto parsedoptions;
- X }
- X goto usg;
- X case HELPOPT1:case HELPOPT2:elog(fmusage);elog(FM_HELP);
- X goto xusg;
- X case FM_DUPLICATE:case FM_MINFIELDS:Qnext_arg();chp++;
- X default:chp--;
- Xnumber: if(*chp-'0'>(unsigned)9) /* the number is not >=0 */
- X goto usg;
- X i=strtol(chp,&chp,10);
- X switch(lastm) /* where does the number go? */
- X { case FM_SKIP:nrskip=i;
- X break;
- X case FM_DUPLICATE:maxlen=i;Qnext_arg();
- X if(!(idcache=fopen(chp,"r+b"))&& /* existing cache? */
- X !(idcache=fopen(chp,"w+b"))) /* create cache? */
- X { nlog("Couldn't open");logqnl(argv[i]);
- X return EX_CANTCREAT;
- X }
- X goto nextarg;
- X case FM_MINFIELDS:minfields=i;
- X break;
- X default:nrtotal=i;
- X }
- X continue;
- X case FM_BOGUS:bogus=0;
- X continue;
- X case FM_QPREFIX:Qnext_arg();escap=chp;
- X break;
- X case FM_ADD_IFNOT:case FM_ADD_ALWAYS:case FM_REN_INSERT:
- X case FM_DEL_INSERT:case FM_EXTRACT:case FM_EXTRC_KEEP:
- X case FM_FIRST_UNIQ:case FM_LAST_UNIQ:case FM_ReNAME:Qnext_arg();
- X i=breakfield(chp,lnl=strlen(chp));
- X switch(lastm)
- X { case FM_DEL_INSERT:case FM_REN_INSERT:case FM_EXTRACT:
- X case FM_FIRST_UNIQ:case FM_LAST_UNIQ:case FM_EXTRC_KEEP:
- X if(-i!=lnl)
- X default:
- X if(i<=0)
- X goto invfield;
- X case FM_ReNAME:;
- X }
- X chp[lnl]='\n'; /* terminate the line */
- X afldp=addfield(lastm==FM_REN_INSERT?&iheader:
- X lastm==FM_DEL_INSERT?&Iheader:lastm==FM_ADD_IFNOT?&aheader:
- X lastm==FM_ADD_ALWAYS?&Aheader:lastm==FM_EXTRACT?&xheader:
- X lastm==FM_FIRST_UNIQ?&uheader:lastm==FM_LAST_UNIQ?&Uheader:
- X lastm==FM_EXTRC_KEEP?&Xheader:&Rheader,chp,++lnl);
- X if(lastm==FM_ReNAME) /* then we need a second field */
- X { int copied=0;
- X for(namep=(chp=(fldp= *afldp)->fld_text)+lnl,
- X chp+=lnl=fldp->id_len;chp<namep;++chp)
- X { switch(*chp) /* skip whitespace */
- X { case ' ':case '\t':case '\n':
- X continue;
- X }
- X break;
- X } /* second field attached? */
- X lastm=i;
- X if((i=breakfield(chp,(size_t)(namep-chp)))>0)
- X tmemmove((char*)fldp->fld_text+lnl,chp,i),copied=1;
- X else if(namep>chp&&lastm<=0|| /* first field ended early */
- X !(chp=(char*)*++argv)|| /* look at next arg */
- X (i=breakfield(chp,strlen(chp)))<=0) /* no field? */
- Xinvfield: { nlog("Invalid field-name:");logqnl(chp?chp:"");
- X goto usg;
- X }
- X *afldp=fldp=
- X realloc(fldp,FLD_HEADSIZ+(fldp->tot_len=lnl+i));
- X if(!copied) /* if not squeezed on yet */
- X tmemmove((char*)fldp->fld_text+lnl,chp,i); /* do now */
- X }
- X case '\0':;
- X }
- X break;
- X }
- Xnextarg:;
- X }
- Xparsedoptions:
- X escaplen=strlen(escap);mystdout=stdout;signal(SIGPIPE,SIG_IGN);
- X thepid=getpid();
- X if(split)
- X { char**ep;char**vfileno=0;
- X for(ep=environ;*ep;ep++) /* gobble through the environment */
- X if(!strncmp(*ep,ffileno,LEN_FILENO_VAR)) /* look for FILENO= */
- X vfileno=ep; /* yes, found it */
- X if(!vfileno) /* FILENO= found in the environment? */
- X { size_t envlen; /* no, pity */
- X envlen=(ep-environ+1)*sizeof*environ; /* current length */
- X tmemmove(ep=malloc(envlen+sizeof*environ),environ,envlen);
- X *(vfileno=(char**)((char*)(environ=ep)+envlen))=0;*--vfileno=ffileno;
- X } /* copy over the array */
- X if((lenfileno=strlen(chp= *vfileno+LEN_FILENO_VAR))>
- X STRLEN(ffileno)-LEN_FILENO_VAR-1) /* check the desired width */
- X lenfileno=STRLEN(ffileno)-LEN_FILENO_VAR-1; /* too big, truncate */
- X if((initfileno=strtol(chp,&chp,10))<0) /* fetch the initial value */
- X lenfileno--; /* correct it for negatives */
- X if(*chp) /* no valid number? */
- X lenfileno= -1; /* disable the FILENO generation */
- X else
- X *vfileno=ffileno; /* stuff our template in the environment */
- X oldstdout=dup(STDOUT);fclose(stdout);
- X if(!nrtotal)
- X goto onlyhead;
- X startprog((const char*Const*)argv);
- X if(!minfields) /* no user specified minimum? */
- X minfields=DEFminfields; /* take our default */
- X }
- X else if(nrskip>0||nrtotal>=0||every||digest||minfields||nowait)
- X goto usg; /* only valid in combination with split */
- X if((xheader||Xheader)&&logsummary||keepb&&!(areply||xheader||Xheader))
- Xusg: /* options sanity check */
- X { elog(fmusage); /* impossible mix */
- Xxusg:
- X return EX_USAGE;
- X }
- X buf=malloc(buflen=Bsize);totallen=0;i=maxindex(rex); /* prime some buffers */
- X do rex[i].rexp=malloc(1);
- X while(i--);
- X fdate=0;addfield(&fdate,date,STRLEN(date)); /* fdate is only for searching */
- X fcntlength=0;addfield(&fcntlength,cntlength,STRLEN(cntlength)); /* ditto */
- X if(areply) /* when auto-replying */
- X addfield(&iheader,xloop,STRLEN(xloop)); /* preserve X-Loop: fields */
- X if(babyl) /* skip BABYL leader */
- X { while(getchar()!=BABYL_SEP1||getchar()!=BABYL_SEP2||getchar()!='\n')
- X while(getchar()!='\n');
- X while(getchar()!='\n');
- X }
- X while((buflast=getchar())=='\n'); /* skip leading garbage */
- X if(!readhead()) /* start looking */
- X {
- X#ifdef sMAILBOX_SEPARATOR /* check for a leading */
- X if(!strncmp(smboxsep,buf,STRLEN(smboxsep))) /* mailbox separator */
- X { buffilled=0; /* skip it */
- X goto startover;
- X }
- X#endif
- X if(digest&&artheadr())
- X goto startover;
- X }
- X else
- Xstartover:
- X while(readhead()); /* read in the whole header */
- X ;{ size_t lenparkedbuf;void*parkedbuf;
- X if(rdheader)
- X { char*tmp,*tmp2;
- X if(!strncmp(tmp=(char*)rdheader->fld_text,Article_,STRLEN(Article_)))
- X tmp[STRLEN(Article_)-1]=HEAD_DELIMITER;
- X else if(babyl&&
- X !force&&
- X !strncmp(tmp,mailfrom,STRLEN(mailfrom))&&
- X eqFrom_(tmp2=skpspace(tmp+STRLEN(mailfrom))))
- X { rdheader->id_len=STRLEN(From_);
- X tmemmove(tmp,tmp2,rdheader->tot_len-=tmp2-tmp);
- X }
- X }
- X namep=0;totallen=0;i=maxindex(rex);
- X do rex[i].rexl=0;
- X while(i--);
- X clear_uhead(uheader);clear_uhead(Uheader); /* all state has been reset */
- X for(fldp=rdheader;fldp;fldp=fldp->fld_next) /* go through the linked */
- X { int nowm; /* list of header-fields */
- X if(conctenate)
- X concatenate(fldp); /* look for `sender' fields */
- X chp=fldp->fld_text;j=fldp->id_len;i=maxindex(sest);
- X while((sest[i].len!=j||strnIcmp(sest[i].head,chp,j))&&i--);
- X if(i>=0&&(i!=maxindex(sest)||fldp==rdheader)) /* found anything? */
- X { char*saddr;char*tmp; /* determine the weight */
- X nowm=trust?sest[i].wtrepl:areply?sest[i].wrepl:i;chp+=j;
- X tmp=malloc(j=fldp->tot_len-j);tmemmove(tmp,chp,j);
- X (chp=tmp)[j-1]='\0';
- X if(sest[i].head==From_)
- X { char*pastad;
- X if(trust||!(saddr=strchr(chp,'\n'))) /* skip the first line? */
- X saddr=chp; /* no need */
- X if(*saddr=='\n'&&(pastad=strchr(saddr,' ')))
- X saddr=pastad+1; /* reposition at the address */
- X chp=saddr;
- X while((pastad=strchr(chp,'\n'))&&(pastad=strchr(pastad,' ')))
- X chp=pastad+1; /* skip to the last uucp >From */
- X if(pastad=strchr(chp,' ')) /* found an address? */
- X { char*savetmp; /* lift it out */
- X savetmp=malloc((j=pastad-chp)+1);tmemmove(savetmp,chp,j);
- X savetmp[j]='\0';
- X if(strchr(savetmp,'@')) /* domain attached? */
- X chp=savetmp,savetmp=tmp,tmp=chp; /* ok, ready */
- X else /* no domain, bang away! :-) */
- X { static const char remf[]=" remote from ",
- X fwdb[]=" forwarded by ";
- X char*p1,*p2;
- X chp=tmp;
- X for(;;)
- X { int c;
- X p1=strstr(saddr,remf);
- X if(!(p2=strstr(saddr,fwdb))&&!p1)
- X break; /* no more info */
- X if(!p1||p2&&p2<p1) /* pick the first bang */
- X p1=p2+STRLEN(fwdb);
- X else
- X p1+=STRLEN(remf);
- X for(;;) /* copy it over */
- X { switch(c= *p1++)
- X { default:*chp++=c;
- X continue;
- X case '\0':case '\n':*chp++='!'; /* for the buck */
- X }
- X break;
- X }
- X saddr=p1; /* continue the hunt */
- X }
- X strcpy(chp,savetmp);chp=tmp; /* attach the user part */
- X }
- X free(savetmp); /* (temporary buffers might have switched) */
- X }
- X }
- X while(*(chp=skpspace(chp))=='\n')
- X chp++;
- X for(saddr=0;;chp=skipwords(chp)) /* skip RFC 822 wise */
- X { switch(*chp)
- X { default:
- X if(!saddr) /* if we haven't got anything yet */
- X saddr=chp; /* this might be the address */
- X continue;
- X case '<':skipwords(saddr=chp); /* hurray, machine useable */
- X case '\0':;
- X }
- X break;
- X }
- X if(saddr) /* any useful mailaddress found? */
- X { if(*saddr) /* did it have any length? */
- X { if(!strpbrk(saddr,"@!/"))
- X nowm-=(maxindex(sest)+2)*4; /* depreciate "user" */
- X else if(strstr(saddr,".UUCP"))
- X nowm-=(maxindex(sest)+2)*3; /* depreciate .UUCP address */
- X else if(strchr(saddr,'@')&&!strchr(saddr,'.'))
- X nowm-=(maxindex(sest)+2)*2; /* depreciate user@host */
- X else if(strchr(saddr,'!'))
- X nowm-=(maxindex(sest)+2)*1; /* depreciate bangpaths */
- X if(!namep||nowm>lastm) /* better than previous ones */
- X { saddr=strcpy(malloc(strlen(saddr)+1),saddr);lastm=nowm;
- X goto newnamep;
- X }
- X }
- X else if(sest[i].head==returnpath) /* nill Return-Path: */
- X { saddr=0;lastm=maxindex(sest)+2; /* override */
- Xnewnamep: if(namep)
- X free(namep);
- X namep=saddr;
- X }
- X }
- X free(tmp);
- X } /* save headers for later perusal */
- X i=maxindex(rex);chp=fldp->fld_text;j=fldp->id_len; /* e.g. areply */
- X while((rex[i].lenr!=j||strnIcmp(rex[i].headr,chp,j))&&i--);
- X chp+=j;
- X if(i>=0&&(j=fldp->tot_len-j)>1) /* found anything? */
- X { tmemmove(rex[i].rexp=realloc(rex[i].rexp,(rex[i].rexl=j)+1),chp,j);
- X rex[i].rexp[j]='\0'; /* add a terminating \0 */
- X }
- X }
- X if(idcache)
- X { int dupid=0;
- X if(msid->rexl) /* any Message-ID: ? */
- X { insoffs=maxlen;msid->rexp[msid->rexl-1]='\0';
- X do /* wipe out trailing newline */
- X { int j;char*p; /* start reading & comparing the next word */
- X for(p=msid->rexp;(j=fgetc(idcache))==*p;p++)
- X if(!j) /* end of word? */
- X { if(!quiet)
- X nlog("Duplicate ID found:"),elog(msid->rexp),elog("\n");
- X dupid=1;
- X goto dupfound; /* YES! duplicate found */
- X }
- X if(!j) /* end of word? */
- X { if(p==msid->rexp&&insoffs==maxlen) /* first character? */
- X { insoffs=ftell(idcache)-1; /* found end of */
- X goto skiprest; /* circular buffer */
- X }
- X }
- X else
- Xskiprest: for(;;) /* skip the rest of the word */
- X { switch(fgetc(idcache))
- X { case EOF:
- X goto noluck;
- X default:
- X continue;
- X case '\0':;
- X }
- X break;
- X }
- X }
- X while(ftell(idcache)<maxlen); /* past our quota? */
- Xnoluck: if(insoffs>=maxlen) /* past our quota? */
- X insoffs=0; /* start up front again */
- X fseek(idcache,insoffs,SEEK_SET);
- X fwrite(msid->rexp,1,msid->rexl+1,idcache);
- Xdupfound: fseek(idcache,(off_t)0,SEEK_SET); /* rewind, for any next run */
- X msid->rexp[msid->rexl-1]='\n'; /* restore the newline */
- X }
- X if(!split) /* not splitting? terminate early */
- X return dupid?EX_OK:1;
- X if(dupid) /* duplicate? suppress output */
- X closemine(),opensink();
- X }
- X ctlength=0;
- X if(!digest&&(fldp=findf(fcntlength,&rdheader)))
- X { *(chp=(char*)fldp->fld_text+fldp->tot_len-1)='\0'; /* terminate it */
- X ctlength=strtol((char*)fldp->fld_text+STRLEN(cntlength),(char**)0,10);
- X *chp='\n'; /* restore the trailing newline */
- X }
- X tmemmove(parkedbuf=malloc(buffilled),buf,lenparkedbuf=buffilled);
- X buffilled=0; /* moved the contents of buf out of the way temporarily */
- X if(areply) /* autoreply requested, we clean up the header */
- X { for(fldp= *(afldp= &rdheader);fldp;)
- X if(!(fp2=findf(fldp,&iheader))||fp2->id_len<fp2->tot_len-1)
- X *afldp=fldp->fld_next,free(fldp),fldp= *afldp; /* remove all */
- X else /* except the ones mentioned */
- X fldp= *(afldp= &fldp->fld_next); /* as -i ...: */
- X loadbuf(to,STRLEN(to));loadchar(' '); /* generate the To: field */
- X if(namep) /* did we find a valid return address at all? */
- X loadbuf(namep,strlen(namep)); /* then insert it here */
- X else
- X loadbuf(unknown,STRLEN(unknown)); /* or insert our default */
- X loadchar('\n');addbuf(); /* add it to rdheader */
- X if(subj->rexl) /* any Subject: found? */
- X { loadbuf(subject,STRLEN(subject)); /* sure, check for leading */
- X if(strnIcmp(skpspace(chp=subj->rexp),Re,STRLEN(Re))) /* Re: */
- X loadbuf(re,STRLEN(re)); /* no Re: , add one ourselves */
- X loadsaved(subj);addbuf();
- X }
- X if(refr->rexl||msid->rexl) /* any References: or Message-ID: */
- X { loadbuf(references,STRLEN(references)); /* yes insert References: */
- X if(refr->rexl)
- X { if(msid->rexl) /* if we're going to append a Message-ID */
- X --refr->rexl; /* suppress the trailing newline */
- X loadsaved(refr);
- X }
- X if(msid->rexl)
- X loadsaved(msid); /* here's our missing newline */
- X addbuf();
- X }
- X if(msid->rexl) /* do we add an In-Reply-To: field? */
- X loadbuf(inreplyto,STRLEN(inreplyto)),loadsaved(msid),addbuf();
- X } /* are we allowed to add From_ lines? */
- X else if(!force&&(!rdheader||!eqFrom_(rdheader->fld_text))) /* missing? */
- X { struct field*old;time_t t; /* insert a From_ line up front */
- X t=time((time_t*)0);old=rdheader;rdheader=0;
- X loadbuf(From_,STRLEN(From_));
- X if(namep) /* we found a valid return address */
- X loadbuf(namep,strlen(namep));
- X else
- X loadbuf(unknown,STRLEN(unknown));
- X loadchar(' '); /* insert one extra blank */
- X if(!hdate->rexl||!findf(fdate,&aheader)) /* Date: */
- X loadchar(' '),chp=ctime(&t),loadbuf(chp,strlen(chp)); /* no Date: */
- X else /* we generate it ourselves */
- X loadsaved(hdate); /* yes, found Date:, then copy from it */
- X addbuf();rdheader->fld_next=old;
- X }
- X for(fldp=aheader;fldp;fldp=fldp->fld_next)
- X if(!findf(fldp,&rdheader)) /* only add what didn't exist */
- X if(fldp->id_len+1>=fldp->tot_len&& /* field name only */
- X (fldp->id_len==STRLEN(messageid)&&
- X !strnIcmp(fldp->fld_text,messageid,STRLEN(messageid))||
- X fldp->id_len==STRLEN(res_messageid)&&
- X !strnIcmp(fldp->fld_text,res_messageid,STRLEN(res_messageid))))
- X { char*p;const char*name;unsigned long h1,h2,h3;
- X static unsigned long h4; /* conjure up a `unique' msg-id field */
- X h1=time((time_t*)0);h2=thepid;h3=rhash;
- X p=chp=malloc(fldp->id_len+2+1+((sizeof h1*8+5)/6+1)*4+1+
- X strlen(name=hostname())+2); /* allocate worst case length */
- X strncpy(p,fldp->fld_text,fldp->id_len);*(p+=fldp->id_len)=' ';
- X *++p='<';*++p='"';*(p=ultoan(h3,p+1))='.';
- X *(p=ultoan(h4,p+1))='.';*(p=ultoan(h2,p+1))='.';
- X *(p=ultoan(h1,p+1))='"';*++p='@';strcpy(p+1,name);
- X *(p=strchr(p,'\0'))='>';*++p='\n';addfield(&nheader,chp,p-chp+1);
- X free(chp);h4++; /* put it in */
- X }
- X else
- X addfield(&nheader,fldp->fld_text,fldp->tot_len);
- X if((fldp= *(afldp= &rdheader))&&logsummary&&eqFrom_(fldp->fld_text))
- X concatenate(fldp),putssn(fldp->fld_text,fldp->tot_len);
- X while(fldp)
- X { lnl=fldp->id_len;chp=fldp->fld_text;
- X if(logsummary)
- X { if(lnl==STRLEN(subject)&&!strnIcmp(chp,subject,lnl))
- X { concatenate(fldp);chp[i=fldp->tot_len-1]='\0';detab(chp);
- X putcs(' ');putssn(chp,i>=MAXSUBJECTSHOW?MAXSUBJECTSHOW:i);
- X putcs('\n');
- X }
- X }
- X if(findf(fldp,&Iheader)) /* delete fields */
- X goto delfld;
- X ;{ struct field*uf;
- X if((uf=findf(fldp,&uheader))&&!uf->fld_ref)
- X uf->fld_ref=afldp; /* first uheader, keep it */
- X else if(fp2=findf(fldp,&Uheader))
- X { if(fp2->fld_ref)
- X { if(afldp==&(*fp2->fld_ref)->fld_next)
- X afldp=fp2->fld_ref;
- X delfield(fp2->fld_ref); /* delete old Uheader */
- X }
- X fp2->fld_ref=afldp; /* keep last Uheader */
- X }
- X else if(uf) /* delete all following uheaders */
- Xdelfld: { fldp=delfield(afldp);
- X continue;
- X }
- X }
- X if(fp2=findf(fldp,&Rheader)) /* explicitly rename field */
- X renfield(afldp,lnl,(char*)fp2->fld_text+lnl,fp2->tot_len-lnl);
- X else if((fp2=findf(fldp,&iheader))&&!(areply&&lnl==fp2->tot_len-1))
- X renfield(afldp,(size_t)0,old_,STRLEN(old_)); /* implicitly rename */
- X fldp= *(afldp= &(*afldp)->fld_next);
- X } /* restore the saved contents of buf */
- X tmemmove(buf,parkedbuf,buffilled=lenparkedbuf);free(parkedbuf);
- X }
- X flushfield(&rdheader);flushfield(&nheader);dispfield(Aheader);
- X dispfield(iheader);dispfield(Iheader);
- X if(namep)
- X free(namep);
- X if(keepb||!(xheader||Xheader)) /* we're not just extracting fields */
- X lputcs('\n'); /* make sure it is followed by an empty line */
- X if(!keepb&&(areply||xheader||Xheader)) /* decision time */
- X { logfolder(); /* we throw away the rest */
- X if(split)
- X closemine();
- X else /* terminate early, only the header was needed */
- X goto onlyhead;
- X opensink(); /* discard the body */
- X }
- X lnl=1; /* last line was a newline */
- X if(buffilled==1) /* the header really ended with a newline */
- X buffilled=0; /* throw it away, since we already inserted it */
- X if(babyl)
- X { int c,lc; /* ditch pseudo BABYL header */
- X for(lc=0;c=getchar(),c!=EOF&&(c!='\n'||lc!='\n');lc=c);
- X babylstart=0;
- X }
- X if(ctlength>0)
- X { if(buffilled)
- X lputssn(buf,buffilled),ctlength-=buffilled,buffilled=lnl=0;
- X ;{ int tbl=buflast,lwr='\n';
- X while(--ctlength>=0&&tbl!=EOF) /* skip Content-Length: bytes */
- X lnl=lwr==tbl&&lwr=='\n',putcs(lwr=tbl),tbl=getchar();
- X if((buflast=tbl)=='\n'&&lwr!=tbl) /* just before a line break? */
- X putcs('\n'),buflast=getchar(); /* wrap up loose end */
- X }
- X if(!quiet&&ctlength>0)
- X { charNUM(num,ctlength);
- X nlog(cntlength);elog(" field exceeds actual length by ");
- X ultstr(0,(unsigned long)ctlength,num);elog(num);elog(" bytes\n");
- X }
- X }
- X while(buffilled||!lnl||buflast!=EOF) /* continue the quest, line by line */
- X { if(!buffilled) /* is it really empty? */
- X readhead(); /* read the next field */
- X if(!babyl||babylstart) /* don't split BABYL files everywhere */
- X { if(rdheader) /* anything looking like a header found? */
- X { if(eqFrom_(chp=rdheader->fld_text)) /* check if it's From_ */
- Xfromanyway: { register size_t k;
- X if(split&&
- X (lnl||every)&& /* more thorough check for a postmark */
- X (k=strcspn(chp=skpspace(chp+STRLEN(From_))," \t\n"))&&
- X *skpspace(chp+k)!='\n')
- X goto accuhdr; /* ok, postmark found, split it */
- X if(bogus) /* disarm */
- X lputssn(escap,escaplen);
- X }
- X else if(split&&digest&&(lnl||every)&&digheadr()) /* digest? */
- Xaccuhdr: { for(i=minfields;--i&&readhead()&&digheadr();); /* found enough */
- X if(!i) /* then split it! */
- Xsplitit: { if(!lnl) /* did the previous mail end with an empty line? */
- X lputcs('\n'); /* but now it does :-) */
- X logfolder();
- X if(fclose(mystdout)==EOF||errout==EOF)
- X { split= -1;
- X if(!quiet)
- X nlog(couldntw),elog(", continuing...\n");
- X }
- X if(!nowait&&*argv) /* wait till the child has finished */
- X { int excode;
- X if((excode=waitfor(child))!=EX_OK&&retval!=EX_OK)
- X retval=excode;
- X }
- X if(!nrtotal)
- X goto onlyhead;
- X startprog((const char*Const*)argv);
- X goto startover;
- X } /* and there we go again */
- X }
- X }
- X else if(eqFrom_(buf)) /* special case, From_ line */
- X { addbuf(); /* add it manually, readhead() didn't */
- X goto fromanyway;
- X }
- X else if(split&&digest&&(lnl||every)&&artheadr())
- X goto accuhdr;
- X }
- X#ifdef MAILBOX_SEPARATOR
- X if(!strncmp(emboxsep,buf,STRLEN(emboxsep))) /* end of mail? */
- X { if(split) /* gobble up the next start separator */
- X { buffilled=0;
- X#ifdef sMAILBOX_SEPARATOR
- X getline();buffilled=0; /* but only if it's defined */
- X#endif
- X if(buflast!=EOF) /* if any */
- X goto splitit;
- X break;
- X }
- X else if(bogus)
- X goto putsp; /* escape it with a space */
- X }
- X else if(!strncmp(smboxsep,buf,STRLEN(smboxsep)&&bogus))
- Xputsp: lputcs(' ');
- X#endif /* MAILBOX_SEPARATOR */
- X lnl=buffilled==1; /* check if we just read an empty line */
- X if(babyl&&*buf==BABYL_SEP1)
- X babylstart=1,closemine(),opensink(); /* discard the rest */
- X if(areply&&bogus) /* escape the body */
- X if(fldp=rdheader) /* we already read some "valid" fields */
- X { register char*p;
- X rdheader=0;
- X do /* careful, they can contain newlines */
- X { fp2=fldp->fld_next;chp=fldp->fld_text;
- X do
- X { lputssn(escap,escaplen);
- X lputssn(chp,(p=strchr(chp,'\n')+1)-chp);
- X }
- X while((chp=p)<(char*)fldp->fld_text+fldp->tot_len);
- X free(fldp); /* delete it */
- X }
- X while(fldp=fp2); /* escape all fields we found */
- X }
- X else
- X { if(buffilled>1) /* we don't escape empty lines, looks neat */
- X lputssn(escap,escaplen);
- X goto flbuf;
- X }
- X else if(rdheader)
- X { struct field*ox,*oX;
- X ox=xheader;oX=Xheader;xheader=Xheader=0;flushfield(&rdheader);
- X xheader=ox;Xheader=oX; /* beware, after this buf can still be filled */
- X }
- X else
- Xflbuf: lputssn(buf,buffilled),buffilled=0;
- X } /* make sure the mail ends with an empty line */
- X logfolder();
- Xonlyhead:
- X closemine();
- X ;{ int excode; /* wait for everyone */
- X while((excode=waitfor((pid_t)0))!=NO_PROCESS)
- X if(retval==EX_OK&&excode!=EX_OK)
- X retval=excode;
- X }
- X if(retval<0)
- X retval=EX_UNAVAILABLE;
- X return retval!=EX_OK?retval:split<0?EX_IOERR:EX_OK;
- X}
- X
- XeqFrom_(a)const char*const a;
- X{ return !strncmp(a,From_,STRLEN(From_));
- X}
- X
- Xint breakfield(line,len)const char*const line;size_t len; /* look where the */
- X{ const char*p=line; /* fieldname ends (RFC 822 specs) */
- X if(eqFrom_(p)) /* special case, From_ */
- X return STRLEN(From_);
- X while(len&&!iscntrl(*p)) /* no control characters allowed */
- X { switch(*p++)
- X { default:len--;
- X continue;
- X case HEAD_DELIMITER:len=p-line;
- X return len==1?0:len; /* eureka! */
- X case ' ':p--; /* no spaces allowed */
- X }
- X break;
- X }
- X return -(int)(p-line); /* sorry, does not seem to be a legitimate field */
- X}
- END_OF_FILE
- if test 28361 -ne `wc -c <'procmail-3.03/src/formail.c'`; then
- echo shar: \"'procmail-3.03/src/formail.c'\" unpacked with wrong size!
- fi
- # end of 'procmail-3.03/src/formail.c'
- fi
- if test -f 'procmail-3.03/src/mailfold.h' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'procmail-3.03/src/mailfold.h'\"
- else
- echo shar: Extracting \"'procmail-3.03/src/mailfold.h'\" \(1005 characters\)
- sed "s/^X//" >'procmail-3.03/src/mailfold.h' <<'END_OF_FILE'
- X/*$Id: mailfold.h,v 1.11 1994/05/26 14:13:06 berg Exp $*/
- X
- Xlong
- X dump P((const s,const char*source,long len));
- Xint
- X deliver P((char*boxname,char*linkfolder));
- Xvoid
- X logabstract P((const char*const lstfolder)),
- X concon P((const ch)),
- X readmail P((int rhead,const long tobesent));
- Xchar
- X *findtstamp P((const char*start,const char*end));
- X
- Xextern int logopened,tofile;
- Xextern off_t lasttell;
- X
- X#define to_FILE 1 /* when we are writing a real file */
- X#define to_FOLDER 2 /* when we are writing a filefolder */
- X
- X#ifdef sMAILBOX_SEPARATOR
- X#define smboxseparator(fd) (tofile==to_FOLDER&&\
- X (part=len,rwrite(fd,sMAILBOX_SEPARATOR,STRLEN(sMAILBOX_SEPARATOR))))
- X#define MAILBOX_SEPARATOR
- X#else
- X#define smboxseparator(fd)
- X#endif /* sMAILBOX_SEPARATOR */
- X#ifdef eMAILBOX_SEPARATOR
- X#define emboxseparator(fd) \
- X (tofile==to_FOLDER&&rwrite(fd,eMAILBOX_SEPARATOR,STRLEN(eMAILBOX_SEPARATOR)))
- X#ifndef MAILBOX_SEPARATOR
- X#define MAILBOX_SEPARATOR
- X#endif
- X#else
- X#define emboxseparator(fd)
- X#endif /* eMAILBOX_SEPARATOR */
- END_OF_FILE
- if test 1005 -ne `wc -c <'procmail-3.03/src/mailfold.h'`; then
- echo shar: \"'procmail-3.03/src/mailfold.h'\" unpacked with wrong size!
- fi
- # end of 'procmail-3.03/src/mailfold.h'
- fi
- echo shar: End of archive 3 \(of 10\).
- cp /dev/null ark3isdone
- MISSING=""
- for I in 1 2 3 4 5 6 7 8 9 10 ; do
- if test ! -f ark${I}isdone ; then
- MISSING="${MISSING} ${I}"
- fi
- done
- if test "${MISSING}" = "" ; then
- echo You have unpacked all 10 archives.
- rm -f ark[1-9]isdone ark[1-9][0-9]isdone
- else
- echo You still must unpack the following archives:
- echo " " ${MISSING}
- fi
- exit 0
- exit 0 # Just in case...
-