procmail
[Top] [All Lists]

Fun with scoring (walking down header chains)

1999-07-13 16:05:39

In a recent note, Walter Dnes described a brute-force method he was using
to list received headers in a message. He was looking for assurances that
it would work in the future, and although he did not ask for it
explicitly, I heard a request for a better way of doing it.

I can't give him assurances about the future of procmail or anything else,
but I can show him a different (very different) way of going about his
task. Below is a procmailrc file which uses self-included recursion to
list all received headers, forward and backward, and provides a
(non-recursive) recipe to select any given header by its index. The method
relies heavily on a scoring method ascribed to Philip Guenther by David
Tamkin. The file is complete--that is, it recurses on itself only. To test
it, cut it out of this message into a file and feed it and a message to
procmail, with an invocation akin to:

 path/to/procmail /path/to/extracted-file < path/to/a/single/message

Optionally, try

 path/to/procmail choice=1 /path/to/extracted-file < path/to/a/single/message

for different values of 1.

There are two tab characters in the file. They appear in the only two
negated character classes, and are the only characters in those classes
(that is, open caret tab close).

The scoring section which is at the heart of each recursion performs two
very different chores in one pass. The first is to determine if the
termination criterion has been reached for the recursion, and the second
is to select the next target match.

This can be adapted for other uses as well, although except as a training
excercise I don't know what. To list all headers, change 'received:' to
'.+', get rid of the non-tab character classes, and fix the comments so
that they don't lie.


For those who are still interested in following my meanderings, there is a
second, equivalent procmailrc file which is the result of the first file
being mangled by my uglyprinter. The uglyprinter is simply the first step
toward a prettyprinter (which is still many stepsaway).


:0             ## select rc section based on (initially undefined) variable rc
* rc ?? ^^^^
{ ## initialize variables and call recursive procedures
  SHELL=/bin/sh
  MAILDIR=.
  DEFAULT=|
  nl="
"
  hdrs = 0                              ## default. silly, but default.
  :0                                    ## count 'em once, use count often
  * 1^1 ^received:
  { hdrs = $= }
  LOG = "${nl}Received headers in forward order:$nl"
  rc = forward index INCLUDERC = $_     ## recursively list received headers
  LOG = "${nl}Received headers in reverse order:$nl"
  rc = reverse index INCLUDERC = $_     ## recursive reverse list headers
  choice = ${choice:-2}                 ## display second unless explicit
  :0                                    ## if choice is nonsensical
  * ! choice ?? ^^[1-9][0-9]*^^
  { LOG = "${nl}please make a better choice than $choice$nl" }
  :0 E                                  ## if choice is beyond header range
  * $ $choice^0
  * $  -$hdrs^0
  { LOG = "$nl$choice is greater than the number of received headers$nl" }
  :0 E                                  ## now, list a specific header
  * $   -$choice^0
  *   2147483647^0
  *            1^1 ^\/received:.*
  { LOG = "${nl}Received header $choice is: $MATCH$nl" }
  :0                                    ## deliver message to bit bucket
  /dev/null
}                                       ## done with main rc
:0 E                                    ## begin forward rc
* rc ?? forward
{ ## recursive routine to display received headers in message order
  :0                                    ## first time through
  * index ?? ^^^^
  { index = 1                           ##  set index to 1, and maxPlus1 to
    :0                                  ##  1 more than # of received hdrs
    *       1^0
    * $ $hdrs^0
    { maxPlus1 = $= }
  }
  :0                                    ## bail if index = maxPlus1, else
  * $   $maxPlus1^0
  * $     -$index^0
  *   -2147483647^0
  *    2147483647^0
  * $  -$maxPlus1^0
  *    2147483647^0
  *             1^1 ^\/received:[^      ]+
  { LOG = "  $index $MATCH$nl"          ##  select header, log it,
    :0                                  ##   increment
    * $ $index^0
    *        1^0
    { index = $= }                      ##   index
    INCLUDERC = $_                      ##   and recurse
  }
}                                       ## done with forward rc
:0 E                                    ## begin reverse rc
* rc ?? reverse
{ ## recursive routine to display received headers in reverse message order
  :0                                    ## first time through
  * index ?? ^^^^
  { :0                                  ##  set index to number of
    * 1^1 ^received+:
    { index = $= }                      ##  received headers
  }
  :0                                    ## bail if index is 0, else
  * $      $index^0
  *   -2147483647^0
  *    2147483647^0
  * $     -$index^0
  * $     -$index^0
  *    2147483647^0
  *             1^1 ^\/received:[^      ]+
  { LOG = "  $index $MATCH$nl"          ##  select header, log it,
    :0                                  ##   decrement
    * $ $index^0
    *       -1^0
    { }
    index = $=                          ##   index
    INCLUDERC = $_                      ##   and recurse
  }
}                                       ## done with reverse rc
------------ end header walk version 1 ---------- cut here 8< ----------

---------- begin header walk version 2 ---------- cut here 8< ----------
:0
*rc??^^^^
{ SHELL=/bin/sh MAILDIR=. DEFAULT=| nl="
"
hdrs=0
:0
*1^1^received:
{ hdrs=$= }LOG="${nl}Received headers in forward order:$nl" rc=forward index 
INCLUDERC=$_ LOG="${nl}Received headers in reverse order:$nl" rc=reverse index 
INCLUDERC=$_ choice=${choice:-2}
:0
*!choice??^^[1-9][0-9]*^^
{ LOG="${nl}please make a better choice than $choice$nl" }:0E
*$$choice^0
*$-$hdrs^0
{ LOG="$nl$choice is greater than the number of received headers$nl" }:0E
*$-$choice^0
*2147483647^0
*1^1^\/received:.*
{ LOG="${nl}Received header $choice is: $MATCH$nl" }:0
/dev/null
}:0E
*rc??forward
{ :0
*index??^^^^
{ index=1
:0
*1^0
*$$hdrs^0
{ maxPlus1=$= } }:0
*$$maxPlus1^0
*$-$index^0
*-2147483647^0
*2147483647^0
*$-$maxPlus1^0
*2147483647^0
*1^1^\/received:[^      ]+
{ LOG="  $index $MATCH$nl"
:0
*$$index^0
*1^0
{ index=$= }INCLUDERC=$_ } }:0E
*rc??reverse
{ :0
*index??^^^^
{ :0
*1^1^received+:
{ index=$= } }:0
*$$index^0
*-2147483647^0
*2147483647^0
*$-$index^0
*$-$index^0
*2147483647^0
*1^1^\/received:[^      ]+
{ LOG="  $index $MATCH$nl"
:0
*$$index^0
*-1^0
{ }index=$= INCLUDERC=$_ } }
------------ end header walk version 2 ---------- cut here 8< ----------

-- 
Rik Kabel          Old enough to be an adult              
rik(_at_)netcom(_dot_)com

<Prev in Thread] Current Thread [Next in Thread>
  • Fun with scoring (walking down header chains), Rik Kabel <=