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