procmail
[Top] [All Lists]

Re: "wc" in pipe not working!

1997-01-15 23:38:20
First, that action line does not read in text from the message, so
the recipe needs an `i' flag to tell procmail to ignore write
errors.

I'm a bit unclear about this.  What "bad" could happen by not putting
an 'i' flag in there?  I mean what "write error" are we worried about
that we'd want PROCMAIL to ignore?

Procmail makes the current mail buffer available on the STDIN filehandle
(0) of any subprocess it runs, including backticks and pipe-command
action recipes.  

In Unix-speak, it is called a "pipe", the "write-end" of which procmail
writes with the contents of the mail buffer, and the "read-end" of which
the subprocess reads to obtain the current mail.

The error which procmail recieves when writing this pipe, and which the
"i" flag says to ignore, is when the pipe filehandle closes before
procmail has finished writing all of the data from the mail message.

For small messages, the first write to the pipe may send all of the
message data, and no write error will ever be received.  For larger
messages, however, it may require two or more writes to send all of the
data.

For backtick commands, procmail doesn't care if the subprocess STDIN is
read or not.  For pipe-command action recipes, especially filters or
delivering recipes, procmail assumes that an error has occurred if the
entire contents of the message has not been read on STDIN.

If you do not tell procmail that a "write error" (on the pipe connected
to the subprocess STDIN) is okay, by using the "i" flag, it will
"recover" the original message and not consider it to have been filtered
or delivered.

Let's use a concrete example:

I want to make it easy for my correspondants to acquire my PGP key.  If
the current mail has the subject: "send pgp key", I want to generate a
reply message, using the original headers to help form it, but not the
body -- the body will be completely replaced with my PGP public key.

    :0c         # send PGP key command?
    * ^Subject: *send pgp[ -]?key
    * $!X-Loop: $LOGNAME(_at_)$HOST
    {
        :0 fbiw # replace the body with the PGP public key
        | pgp -kxaft $LOGNAME 2>/dev/null

        :0 efbi # if that didn't work, show an error
        | echo "Sorry, my PGP public key isn't available at the moment" ; \
          echo "Please try again later."

        :0 afhw # if that worked, filter the header
        | formail -rt   -I"From: $LOGNAME(_at_)$HOST" \
                        -I"Subject: PGP Public Key for $LOGNAME(_at_)$HOST" \
                        -I"X-Loop: $LOGNAME(_at_)$HOST"

        :0 Bafhw # if there was a problem Cc: myself
        * Sorry
        | formail -I"Cc: $LOGNAME"

        :0 a    # if all of that worked, deliver to sendmail
        ! -t
    }

Of course, there are many ways to write this recipe, but the point of
the exercise, beside showing a neat auto-reply generator, is to show
real-world cases where "i" is necessary -- when you are using a
"filtering" recipe to replace the either the contents of the header,
body, or both, and not actually reading them.

You will not need the "i" flag if all your command recipes consume
STDIN, such as a different version of the above recipe:

    :0 ch       # send PGP key command
    * ^Subject: *send pgp[ -]?key
    * $!X-Loop: $LOGNAME(_at_)$HOST
    | formail -rt -I"From: $LOGNAME(_at_)$HOST" \
                  -I"Subject: PGP Public Key for $LOGNAME(_at_)$HOST" \
                  -I"X-Loop: $LOGNAME(_at_)$HOST" ; \
      { pgp -kxaft $LOGNAME 2>/dev/null || \
        { echo "Sorry, my PGP public key isn't available at the moment" ; \
          echo "Please try again later." ; \
        } \
      } | $SENDMAIL $sendmailOPT -t

Since formail part of the command, and is receiving the pipe command
STDIN in the action command, no "i" ignore flag is needed, because
formail always reads to EOF on its input.

This recipe reads: (same conditions as above), create a reply header
using formail, with three additional headers, followed by the output of
a pgp command, or, if that failed, a short message apologizing for the
lack of expected response.  Send all of the above output straight to
sendmail, using the header fields to determine the addressee list.

The disadvantage of this single-action recipe is that there is no way to
append a "Cc:" if the PGP failed without either storing the data
currently in the pipe into a file, or into the procmail buffer.

Shell script and procmail recipe authors can get "religious" about the
issue of whether to try using a single, possibly long command action, or
using several, discrete, small recipes.  

My opinion is that the second recipe is more complicated, less clear and
less accommodating to future adaptation, even though it performs almost
the same function as the first recipe.  I also believe that the first
style of recipe writing is "cleaner". :^)

Hope this helps.
___________________________________________________________
Alan Stebbens <aks(_at_)sgi(_dot_)com>      http://reality.sgi.com/aks

<Prev in Thread] Current Thread [Next in Thread>