procmail
[Top] [All Lists]

Re: Recipe help needed

1996-09-27 13:05:43
"Greg E. Priest-Dorman" <priestdo(_at_)cs(_dot_)vassar(_dot_)edu> writes:
...
:0 b c
* ^Subject: HTML3.2.dtd
|cat  > $TEMPORARY ; \
sgmls /usr/local/lib/sgml/html.decl $TEMPORARY > $TEMP2 ; rm -f $TEMPORARY

:0 h
* ^Subject: HTML3.2.dtd
| (formail -r -A"Precedence: junk" ; \
  cat  $TEMP2 )| $SENDMAIL -t


needless to say, I am open to other aproces to solving the problem.


Well, since you write to a temporary file, you should lock it using a
local lock file.  Next, since sgmls sends it's output to stdout, you
can change the first recipe to a filter, eliminating the temporary file
$TEMP2.  You should also through in a check to prevent accidental (or
malicious) looping.  That's the X-Loop: header stuff below.  Note that
the actual value that you use for X-Loop: doesn't really matter, just
as long as it's (probably) unique to you.


TEMP = $MAILDIR/somefile.$$

:0 bfw:$TEMP.lock
*   ^Subject: HTML3.2.dtd
* ! ^X-Loop: sgml-check(_at_)vassar(_dot_)edu
| cat >$TEMP; sgmls /usr/local/lib/sgml/html.decl $TEMP; rm -f $TEMP

:0A
| formail -rkb -A"Precedence: junk" -A"X-Loop: 
sgml-check(_at_)vassar(_dot_)edu" | \
        $SENDMAIL -t


Okay, we can refine it from there.  What if someone tries to send a
10Megabyte html document to check?  Would that choke your filesystem?
We can throw on a check on the size of the incoming document.  By
sticking it in a nested block we can use the same final recipe to send
the return message:

:0
*   ^SubjectL HTML3.2.dtd
* ! ^X-Loop: sgml-check(_at_)vassar(_dot_)edu
{
    # Okay, the message isn't looping, and it's destined for the checker.
    # Is it too big?

    # How big is too big?  This is 1Meg.
    MAXSIZE = 1048576

    # Is the message large than allowed?  If so, change the body to
    # an error message.  The 'i' flag is needed to keep procmail from
    # complaining about the fact the the 'filter' (in this case, two
    # echos), doesn't read the message before returning.
    :0 fbwi
    * $ > $MAXSIZE
    | echo 'Unable to check HTML document: exceeded size limit of $MAXSIZE'; \
      echo 'Please break it into smaller pieces and try again'


    # Pick a temp file, any temp file.  The pid ($$) should make this
    # unique.  Beware: hacking a program's temp files is a regular sport
    # of crackers, so consider whether it would be okay to put this
    # temp file in some place that isn't world writable.
    # TEMP = $MAILDIR/sgml-check.$$.temp
    TEMP = /tmp/sgml-check.$$.temp


    # The 'E' flag makes this recipe execute only if the preceeding
    # one didn't.  While the temp file is supposed to be unique (see
    # above), paranoia is a good thing, expecially if you ever change
    # the definination listed above.  Be careful about being your own
    # worst enemy.
    :0 Efbw: $TEMP.lock
    | cat >$TEMP; sgmls /usr/local/lib/shml/html.decl $TEMP; rm -f $TEMP
}

# This sends the message back, whether it's a "too big" message or the
# output of sgmls.  The 'A' flag conditions this on the previous block
# being entered.  We could also just put this in the block proper, and
# remove the 'A' flag, but that would require me to reindent it, and
# I'm feeling lazy.
# Oh yeah, the '-k' and '-b' flags to formail (combined below) tell it
# that the body of the message will be included in stdin, and should
# '-k') be kept; and
# '-b') not be quoted with greater than signs.
:0A
| formail -rkb -A"Precedence: junk" -A"X-Loop: 
sgml-check(_at_)vassar(_dot_)edu" | \
        $SENDMAIL -t


As one final possible tweak, if the sgmls program doesn't need to seek
on the input files, then you may be able to pipe the message body
directly into the program, which eliminates the temporary files
altogether, and eliminates teh need for the lock file.  To do this, it
[sgmls] may interpret a filename of '-' to mean "read standard input at
that point".  Alternatively, on newer OSs which have the fd file system
(look for /dev/fd/0, /dev/fd/1, ...) you can specify /dev/fd/0 as the
file, and that'll be treated by kernel as the programs standard input.
This is to be prefered if possible, as it doesn't require the special
handling by sgmls that the '-' hack does.  To do this, change the
last recipe in the block above to read:


    # The 'E' flag makes this recipe execute only if the preceeding
    # one didn't.  We call sgmls with "/dev/fd/0" as an arg, which
    # newer OSs turn into the program's stdin.  If your OS doesn't
    # support that, then you should check to see if sgmls supports
    # the '-' hack, where a '-' arg is treated as specifying stdin.
    # If it doesn't, and you can't add it, then you're stuck with
    # using a temp file, and this is all for naught.  Get a better
    # OS!
    :0 Efbw
    | sgmls /usr/local/lib/shml/html.decl /dev/fd/0
    #| sgmls /usr/local/lib/shml/html.decl -




There's alot of stuff in the above -- nested blocks, size conditions,
'$' expansion in conditions, filters, 'filters' that just replace,
X-Loop: loop avoidance, a couple new flags to formail -- so you may
have to stare at it closely while reading the manpages to understand
how it's does everything.  If you're confused by anything in the above,
please send a message (to the list, please!) and a clearer explanation
may be obtainable.

Philip Guenther

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