[Dovecot] Sieve "header :value" test does not work

Tom Hendrikx tom at whyscream.net
Wed Sep 7 17:17:33 EEST 2011


On 07/09/11 15:48, Stephan Bosch wrote:
> On 9/7/2011 2:40 PM, Tom Hendrikx wrote:
>> The above snippet poses some other issue that I cannot easily solve: the
>> ascii-numeric comparator only handles integer values.
>>
>> All 0.xxxx header values are truncated to 0 by the comparator, just like
>> the sieve script value "0.95". After comparision, this results in true
>> for all cases.
>>
>> I don't really see a way to interact with floats in sieve, other than
>> using regular expressions. However this gets clumsy/hairy quite fast
>> when you're matching a hypothetical header value>=0.73 in stead of>=0.99.
>>
>> Any ideas?
> 
> Yes. This can be a problem. However, the usual application for this is
> matching against a spam header. If it is, you can use the spamtest
> extension instead. Then you can configure the gory details in the
> background
> (http://wiki2.dovecot.org/Pigeonhole/Sieve/Extensions/SpamtestVirustest).
> 
> Otherwise, things indeed tend to get hairy. I've puzzled a bit and came
> up with the following:
> 
> ====
> require "variables";
> require "relational";
> require "comparator-i;ascii-numeric";
> require "regex";
> 
> # Extract integer and fractional part separately:
> set "val_int" "0";
> set "val_frac" "0";
> if header :regex "X-Header-Name" "([0-9]+)\\.([0-9]+)" {
>   set "val_int" "${1}";
>   set "val_frac" "${2}";
> }
> 
> if allof (
>   /* Compare the integer part */
>   string :comparator "i;ascii-numeric" :value "ge" "${val_int}" "5",
>   /* Compare the fractional part */
>   string :value "ge" "${val_frac}" "34" ) {
>   discard;
> }
> ====
> 
> As you can see, the integer and fractional parts of the fractional
> number are extracted separately using a :regex match. Then the
> comparison is performed. The integer part is compared using
> i;ascii-numeric. Quite counter-intuitively, the fractional part is
> compared using a normal string comparison. The earlier regex match made
> sure that the ${val_frac} variable only contains digits. The string
> comparison makes sure that the length of the fractional part does not
> matter (much) and that the comparison works as expected. A length
> difference will only have an effect when there are spurious trailing
> zeros and all the preceeding digits are equal, thereby causing the
> longer string to have higher value, which is not strictly correct.
> 
> The above certainly does not deserve an award for beauty, it does not
> handle negative numbers (can be added), and it is not tested very well. 
> So, use this with caution. Unfortunately, there is no i;ascii-fractional
> (or whatever) collation and afaik nothing like that is in the works at
> the IETF.
> 

Thanks for the idea :)
My first alternative way of thinking was to put the header value in a
variable, then multiply it by 10000 (in my actual issue, the fraction
always has 4 characters), then handle it as an int. However, doing a
calculation is also not supported.

I was trying to do some nifty stuff with DSPAM headers, which adds
header that indicates "Spam" or "Innocent", and a fractional value
between 0 and 1 that indicates the confidence that the filter has in its
own classification:

X-DSPAM-Result: Spam
X-DSPAM-Confidence: 0.9456
==> quite sure it is spam

X-DSPAM-Result: Innocent
X-DSPAM-Confidence: 0.9889
==> even more sure that it is not spam

Based on these headers, I wanted to do something with messages that the
filter was really sure about, like pushing them to spamcop.

Combining these headers in the sieve spamtest configuration to create a
sliding scale between 1 and 10 is not really possible.

-- 
Regards,
	Tom



More information about the dovecot mailing list