You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@spamassassin.apache.org by mm...@apache.org on 2009/08/25 18:42:46 UTC

svn commit: r807706 - in /spamassassin/trunk/lib/Mail/SpamAssassin: Conf.pm PerMsgStatus.pm

Author: mmartinec
Date: Tue Aug 25 16:42:45 2009
New Revision: 807706

URL: http://svn.apache.org/viewvc?rev=807706&view=rev
Log:
Bug 6185 - 'add_header' config option adds header fields in
random order - change internal representation to preserve
the declared order of added header fields

Modified:
    spamassassin/trunk/lib/Mail/SpamAssassin/Conf.pm
    spamassassin/trunk/lib/Mail/SpamAssassin/PerMsgStatus.pm

Modified: spamassassin/trunk/lib/Mail/SpamAssassin/Conf.pm
URL: http://svn.apache.org/viewvc/spamassassin/trunk/lib/Mail/SpamAssassin/Conf.pm?rev=807706&r1=807705&r2=807706&view=diff
==============================================================================
--- spamassassin/trunk/lib/Mail/SpamAssassin/Conf.pm (original)
+++ spamassassin/trunk/lib/Mail/SpamAssassin/Conf.pm Tue Aug 25 16:42:45 2009
@@ -694,6 +694,14 @@
 (so a C<header_name> Foo will generate a header called X-Spam-Foo).
 header_name is restricted to the character set [A-Za-z0-9_-].
 
+The order of C<add_header> configuration options is preserved, inserted
+headers will follow this order of declarations. When combining C<add_header>
+with C<clear_headers> and C<remove_header>, keep in mind that C<add_header>
+appends a new header to the current list, after first removing any existing
+header fields of the same name. Note also that C<add_header>, C<clear_headers>
+and C<remove_header> may appear in multiple .cf files, which are interpreted
+in alphabetic order.
+
 C<string> can contain tags as explained below in the B<TEMPLATE TAGS> section.
 You can also use C<\n> and C<\t> in the header to add newlines and tabulators
 as desired.  A backslash has to be written as \\, any other escaped chars will
@@ -707,7 +715,7 @@
 You can customize existing headers with B<add_header> (only the specified
 subset of messages will be changed).
 
-See also C<clear_headers> for removing headers.
+See also C<clear_headers> and C<remove_header> for removing headers.
 
 Here are some examples (these are the defaults, note that Checker-Version can
 not be changed or removed):
@@ -744,10 +752,14 @@
       $hline = join("\\", @line);
       chop($hline);  # remove dummy newline again
       if (($type eq "ham") || ($type eq "all")) {
-        $self->{headers_ham}->{$name} = $hline;
+        $self->{headers_ham} =
+          [ grep { lc($_->[0]) ne lc($name) } @{$self->{headers_ham}} ];
+        push(@{$self->{headers_ham}}, [$name, $hline]);
       }
       if (($type eq "spam") || ($type eq "all")) {
-        $self->{headers_spam}->{$name} = $hline;
+        $self->{headers_spam} =
+          [ grep { lc($_->[0]) ne lc($name) } @{$self->{headers_spam}} ];
+        push(@{$self->{headers_spam}}, [$name, $hline]);
       }
     }
   });
@@ -779,11 +791,14 @@
       my ($type, $name) = ($1, $2);
       return if ( $name eq "Checker-Version" );
 
+      $name = lc($name);
       if (($type eq "ham") || ($type eq "all")) {
-        delete $self->{headers_ham}->{$name};
+        $self->{headers_ham} =
+          [ grep { lc($_->[0]) ne $name } @{$self->{headers_ham}} ];
       }
       if (($type eq "spam") || ($type eq "all")) {
-        delete $self->{headers_spam}->{$name};
+        $self->{headers_spam} =
+          [ grep { lc($_->[0]) ne $name } @{$self->{headers_spam}} ];
       }
     }
   });
@@ -794,6 +809,11 @@
 before any B<add_header> options to prevent the default headers from being
 added to the message.
 
+C<add_header>, C<clear_headers> and C<remove_header> may appear in multiple
+.cf files, which are interpreted in alphabetic order, so C<clear_headers>
+in a later file will remove all added headers from previously interpreted
+configuration files, which may or may not be desired.
+
 Note that B<X-Spam-Checker-Version> is not removable because the version
 information is needed by mail administrators and developers to debug
 problems.  Without at least one header, it might not even be possible to
@@ -805,12 +825,10 @@
     setting => 'clear_headers',
     code => sub {
       my ($self, $key, $value, $line) = @_;
-      for my $name (keys %{ $self->{headers_ham} }) {
-        delete $self->{headers_ham}->{$name} if $name ne "Checker-Version";
-      }
-      for my $name (keys %{ $self->{headers_spam} }) {
-        delete $self->{headers_spam}->{$name} if $name ne "Checker-Version";
-      }
+      my @h = grep { lc($_->[0]) eq "checker-version" }
+                   @{$self->{headers_ham}};
+      $self->{headers_ham}  = !@h ? [] : [ $h[0] ];
+      $self->{headers_spam} = !@h ? [] : [ $h[0] ];
     }
   });
 
@@ -853,8 +871,9 @@
       }
 
       $self->{report_safe} = $value+0;
-      if (! $self->{report_safe}) {
-        $self->{headers_spam}->{"Report"} = "_REPORT_";
+      if (! $self->{report_safe} &&
+          ! (grep { lc($_->[0]) eq "report" } @{$self->{headers_spam}}) ) {
+        push(@{$self->{headers_spam}}, ["Report", "_REPORT_"]);
       }
     }
   });
@@ -3298,8 +3317,8 @@
   $self->{rewrite_header} = { };
   $self->{want_rebuild_for_type} = { };
   $self->{user_defined_rules} = { };
-  $self->{headers_spam} = { };
-  $self->{headers_ham} = { };
+  $self->{headers_spam} = [ ];
+  $self->{headers_ham} = [ ];
 
   $self->{bayes_ignore_headers} = [ ];
   $self->{bayes_ignore_from} = { };
@@ -3322,10 +3341,11 @@
   $self->{internal_networks_configured} = 0;
 
   # Make sure we add in X-Spam-Checker-Version
-  $self->{headers_spam}->{"Checker-Version"} =
-                "SpamAssassin _VERSION_ (_SUBVERSION_) on _HOSTNAME_";
-  $self->{headers_ham}->{"Checker-Version"} =
-                $self->{headers_spam}->{"Checker-Version"};
+  { my $r = [ "Checker-Version",
+              "SpamAssassin _VERSION_ (_SUBVERSION_) on _HOSTNAME_" ];
+    push(@{$self->{headers_spam}}, $r);
+    push(@{$self->{headers_ham}},  $r);
+  }
 
   # these should potentially be settable by end-users
   # perhaps via plugin?

Modified: spamassassin/trunk/lib/Mail/SpamAssassin/PerMsgStatus.pm
URL: http://svn.apache.org/viewvc/spamassassin/trunk/lib/Mail/SpamAssassin/PerMsgStatus.pm?rev=807706&r1=807705&r2=807706&view=diff
==============================================================================
--- spamassassin/trunk/lib/Mail/SpamAssassin/PerMsgStatus.pm (original)
+++ spamassassin/trunk/lib/Mail/SpamAssassin/PerMsgStatus.pm Tue Aug 25 16:42:45 2009
@@ -722,11 +722,11 @@
   $newmsg .= "Date: $date" if defined $date;
   $newmsg .= "Message-Id: $msgid" if defined $msgid;
 
-  foreach my $header (keys %{$self->{conf}->{headers_spam}}) {
-    my $data = $self->{conf}->{headers_spam}->{$header};
-    my $line = $self->_process_header($header,$data);
+  foreach my $hf_ref (@{$self->{conf}->{headers_spam}}) {
+    my ($hfname, $hfbody) = @$hf_ref;
+    my $line = $self->_process_header($hfname,$hfbody);
     $line = $self->qp_encode_header($line);
-    $newmsg .= "X-Spam-$header: $line\n" # add even if empty
+    $newmsg .= "X-Spam-$hfname: $line\n" # add even if empty
   }
 
   if (defined $self->{conf}->{report_safe_copy_headers}) {
@@ -908,10 +908,11 @@
 
   # use string appends to put this back together -- I finally benchmarked it.
   # join() is 56% of the speed of just using string appends. ;)
-  while (my ($header, $data) = each %{$self->{conf}->{$addition}}) {
-    my $line = $self->_process_header($header,$data);
+  foreach my $hf_ref (@{$self->{conf}->{$addition}}) {
+    my ($hfname, $hfbody) = @$hf_ref;
+    my $line = $self->_process_header($hfname,$hfbody);
     $line = $self->qp_encode_header($line);
-    $new_hdrs_pre .= "X-Spam-$header: $line\n";
+    $new_hdrs_pre .= "X-Spam-$hfname: $line\n";
   }
 
   # fix up line endings appropriately