procmail
[Top] [All Lists]

Re: Scoring problem

2003-02-24 05:42:27
On Sun, Feb 23, 2003 at 10:09:40PM -0500, fleet(_at_)teachout(_dot_)org wrote:

I'm testing a variant of Dallman's "infinity shuffle" recipe.  The
variable LAST is set to $= from the preceeding recipe.

LAST=3

:0
* $   -$LAST^0 ! LAST ?? (^^1^^|^^2^^|^^3^^)

That's okay, but could be written

        ^^(1|2|3)^^

or, more efficiently (because char classes are slightly more
efficient),

        ^^[123]^^

or (equivalent in this case),

        ^^[1-3]^^


* 2147483647^0
*          1^0
*          1^1 ^Received:[      ]*\/from\>.+
* MATCH ?? raq2\.paxp\.com

The log reports:

procmail: Assigning "LAST=3"
...
...
procmail: Score:       0       0 ! "(^^1^^|^^2^^|^^3^^)"
procmail: Score: 2147483647 2147483647 ""
procmail: Match on "raq2\.paxp\.com"

I thought that if ! LAST ?? (^^1^^|^^2^^|^^3^^) were true the recipe
would just be skipped.  It's not getting skipped and every hit on the
preceeding recipe gets hit again on this one, since apparently I'm
seeing the same "Received:" line as in the previous recipe.

I'll prewarn here that I'm on my second cup of coffee and not yet
very awake.  Let's see what I can come up with in my morning grogginess.

First, it's important to know that scored conditions always descend
further into the recipe -- with the one exception of when supremum
or infimum is reached, which is the subtlety that we want to
leverage off of with the "infinity shuffle."  More about that in
a minute.  But let's look at a simple example:

        :0
        *  5^0  foo
        * -3^0  bar
        { TOTAL = $= }

Here, each condition is a scored one.  Each condition will therefore
be tested, regardless of match or non-match of previous conditions.
Absent flags specifying that the recipe do otherwise, conditions
look, by default, only at the message header.  So if there is foo
in this message's header, we descend and also check bar.  *If there
is no foo, we also descend and check bar!*  In a scoring recipe,
the scores are accreted (whether positively or negatively, doesn't
matter) for each condition that matches; but all conditions are
tested.

In the sample recipe, although both foo and bar will be checked,
the recipe will only succeed if there is a "foo".  That's because
only if the score is a positive number when we're all done, will
the action be triggered.  Here are the possible outcomes:

        foo appears in headers, add 5
        bar appears in headers, subtract 3
        TOTAL gets assigned as 2

        foo appears in headers, add 5
        bar does not appear in headers, leave score alone
        TOTAL gets assigned as 5

        foo does not appear in headers, score untouched at 0
        bar appears in headers, subtract 3
        TOTAL is NOT assigned.  Negative score won't initiate action

        foo does not appear in headers, score untouched at 0
        bar does not appear in headers, score untouched at 0
        TOTAL is NOT assigned.  Zero score won't initiate recipe action

Let's change the scores:

        :0
        * -5^0  foo
        * -3^0  bar
        { TOTAL = $= }

This recipe's action line will never be reached.  Both foo and bar
will be tested, and the score will be accreted accordingly.  But
the end score can't be higher than zero in the example, so the
action (assignment statement) won't happen.

One could, of course, still use the score by way of (among other
ways) a follow-up recipe:

        :0 E
        { TOTAL = $= }

Thus, although the first recipe didn't arrive at the action, the
E flag (procmail's "else") will cause the second recipe to give
us our total anyway.  (The total will be either -5 or -3 or -8
or 0, depending on which of foo or bar was found, if any.)

Okay, back to the "infinity shuffle." We were here:


        * $     -$LAST^0  ! LAST ?? ^^[1-3]^^
        *   2147483647^0

So, what's happening?  If $LAST is NOT a string -- we know
it's a number, but procmail doesn't, here -- in the range
of 1-3, decrement the score by the value of -$LAST.
(Be careful, because if $LAST was already a negative number,
then the expression will be garbage to procmail.  Use this
syntax only when you know that $LAST can't have been set
negative anywhere up above.)

Now we add procmail's supremum value.  What's the subtotal?
The subtotal depends on whether $LAST was or wasn't any of
a 1, 2, or 3.  If not, then the subtotal score is the supremum
minus the value of $LAST.  For example, let's suppose $LAST
is five.  Then the subtotal here is 2147483647 - 5 = 2147483642,
and we go happily onward through further scored recipe conditions.

However, you set $LAST to 3.  The first condition fails to match, so
the score is not altered.  We saw in your log excerpts that it stayed
at zero.  What's the subtotal?  Well, it's procmail's "infinity,"
and, as per `man procmailsc',

       As  soon  as  `plus infinity' (2147483647) is reached, any
       subsequent weighted conditions will simply be skipped.

Voom!  We are instantly[1] at the action line.  Based on the
construction of your scored conditions, if $LAST is not any of
1 or 2 or 3, this recipe will always trigger its action line.
(And if $LAST *is* a 1, 2, or 3, we'll run through the rest
of the scored conditions before we decide.)


[1] A further caveat is that only *scored* conditions have yet
been evaluated.  EVEN IF WE ARE AT INFINITY, though, procmail
will still, now, look at any non-scoring conditions in the
recipe and evaluate them.  If any of *those* fail, then the
recipe fails.  You do have a non-scored condition in your
recipe:

        * MATCH ?? raq2\.paxp\.com

That condition, if evaluated as true, will allow the scoring
to work as described above.  If the condition is false, however,
the recipe will fail, i.e., exit without action.

Hth,
Dallman

_______________________________________________
procmail mailing list
procmail(_at_)lists(_dot_)RWTH-Aachen(_dot_)DE
http://MailMan.RWTH-Aachen.DE/mailman/listinfo/procmail

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