This patch adds functionality so that folded DSPAM headers won't cause message corruption. You may turn on showFactors. Errata (from patch #10): "Mails with encoded bodies will be broken because this module does not change the mime type." This is nonsense, MIME type changes will be picked up by this module (even with patch 10). --- original/amavisd 2006-05-15 22:26:22.000000000 +0200 +++ modified/amavisd 2006-05-21 12:23:13.000000000 +0200 @@ -14912,7 +14912,7 @@ sub is_DSPAM_header($) { my($self, $line) = @_; - return ($line =~ m/^X-DSPAM-[^:]*:[ \t]*.*$/); # this does not handle folding! + return ($line =~ m/^X-DSPAM-[^:]*:[ \t]*.*$/); } sub handle_DSPAM_header($$) { @@ -14945,7 +14945,7 @@ sub assert_header_complete($$$) { my($self, $header, $line) = @_; - if (not (length($header) > 0 and $self->header_complete($line))) { + if (length($header) == 0 or not $self->header_complete($line)) { $self->{'error'} = 1; do_log(0, "premature end of message header read from DSPAM output!"); } @@ -14956,26 +14956,52 @@ return $self->{'error'}; } +# This routine reads header items and is able to handle folded items which +# span over multiple lines. These items will be unified into a single string +# so that the is_DSPAM_header() routine can handle it. +# For header output the original (folded) version is used in order to +# break cryptographic algorithms such as DomainKeys(c) as less as possible. +sub read_header_item($$) { + my($self, $stdout, $previous_line) = @_; + my($header_item) = $previous_line; + if (not defined $header_item) { + $header_item = $stdout->getline(); + } + my($original_header_item) = $header_item; + chomp($header_item); + + my($next_line) = $stdout->getline(); + while (defined $next_line and $next_line =~ m/^(\s+(.+))$/) { + $original_header_item .= $1."\n"; + $header_item .= " ".$2; + chomp($header_item); + $next_line = $stdout->getline(); + } + if ($self->is_DSPAM_header($header_item)) { + $self->handle_DSPAM_header($header_item); + $original_header_item = undef; + } + return ($original_header_item, $next_line); +} + sub read_header($$$) { my($self) = @_; my($stdout, $stderr) = ($self->dspam_stdout, $self->dspam_stderr()); - my($line, $header) = ("", ""); - while ($self->more_lines_available($stdout) and not $self->header_complete($line) and not $self->dspam_error($stderr)) { - $line = $stdout->getline(); - if ($self->is_DSPAM_header($line)) { - $self->handle_DSPAM_header($line); - } else { - $header .= $line; - } + my($header, $header_item, $next_line); + while(not $self->dspam_error($stderr)) { + ($header_item, $next_line) = $self->read_header_item($stdout, $next_line); + if (not $self->is_DSPAM_header($header_item)) { + $header .= $header_item; + } + last if (defined $next_line and $self->header_complete($next_line)); } - $self->dspam_error($stderr); unless ($self->error_occurred) { - $self->assert_header_complete($header, $line); + $self->assert_header_complete($header, $next_line); $self->assert_no_error_occurred($stdout); } - return $header; + return $header."\n"; } sub write_new_mail($$$$) {