/usr/share/perl5/Mail/SpamAssassin/Plugin/Reuse.pm is in spamassassin 3.3.2-5+deb7u3.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 | =head1 NAME
Mail::SpamAssassin::Plugin::Reuse - For reusing old rule hits during a mass-check
=head1 SYNOPSIS
loadplugin Mail::SpamAssassin::Plugin::Reuse
ifplugin Mail::SpamAssassin::Plugin::Reuse
reuse NETWORK_RULE [ NETWORK_RULE_OLD_NAME ]
endif
=head1 DESCRIPTION
The purpose of this plugin is to work in conjunction with B<mass-check
--reuse> to map rules hit in input messages to rule hits in the
mass-check output.
=cut
package Mail::SpamAssassin::Plugin::Reuse;
use bytes;
use strict;
use warnings;
use Mail::SpamAssassin::Conf;
use Mail::SpamAssassin::Logger;
use vars qw(@ISA);
@ISA = qw(Mail::SpamAssassin::Plugin);
# constructor
sub new {
my $invocant = shift;
my $samain = shift;
# some boilerplate...
my $class = ref($invocant) || $invocant;
my $self = $class->SUPER::new($samain);
bless ($self, $class);
$self->set_config($samain->{conf});
# make sure we run last (or close) of the finish_parsing_start since
# we need all other rules to be defined
$self->register_method_priority("finish_parsing_start", 100);
return $self;
}
sub set_config {
my ($self, $conf) = @_;
my @cmds = ();
# reuse CURRENT_NAME ADDITIONAL_NAMES_IN_INPUT ...
# e.g.
# reuse NET_TEST_V1 NET_TEST_V0
push (@cmds, { setting => 'reuse',
code => sub {
my ($conf, $key, $value, $line) = @_;
if ($value !~ /\s*(\w+)(?:\s+(\w+(?:\s+\w+)*))?\s*$/) {
return $Mail::SpamAssassin::Conf::INVALID_VALUE;
}
my $new_name = $1;
my @old_names = ($new_name);
if ($2) {
push @old_names, split (' ', $2);
}
dbg("reuse: read rule, old: @old_names new: $new_name");
foreach my $old (@old_names) {
push @{$conf->{reuse_tests}->{$new_name}}, $old;
}
}});
$conf->{parser}->register_commands(\@cmds);
}
sub finish_parsing_start {
my ($self, $opts) = @_;
my $conf = $opts->{conf};
dbg("reuse: finish_parsing_start called");
return 0 if (!exists $conf->{reuse_tests});
foreach my $rule_name (keys %{$conf->{reuse_tests}}) {
# If the rule does not exist, add a new EMPTY test, set default score
if (!exists $conf->{tests}->{$rule_name}) {
dbg("reuse: $rule_name does not exist, adding empty test");
$conf->{parser}->add_test($rule_name, undef, $Mail::SpamAssassin::Conf::TYPE_EMPTY_TESTS);
}
if (!exists $conf->{scores}->{$rule_name}) {
my $set_score = ($rule_name =~/^T_/) ? 0.01 : 1.0;
$set_score = -$set_score if ( ($conf->{tflags}->{$rule_name}||'') =~ /\bnice\b/ );
foreach my $ss (0..3) {
$conf->{scoreset}->[$ss]->{$rule_name} = $set_score;
}
}
# Figure out when to add any hits -- grab priority and "stage"
my $priority = $conf->{priority}->{$rule_name} || 0;
my $stage = $self->_get_stage_from_rule($opts->{conf}, $rule_name);
$conf->{reuse_tests_order}->{$rule_name} = [ $priority, $stage ];
}
}
sub check_start {
my ($self, $opts) = @_;
my $pms = $opts->{permsgstatus};
# Can we reuse?
my $msg = $pms->get_message();
unless (exists $msg->{metadata}->{reuse_tests_hit}) {
dbg("reuse: no old test hits passed in");
return 0;
}
my $old_hash = $msg->{metadata}->{reuse_tests_hit};
# now go through the rules and priorities and figure out which ones
# need to be disabled
foreach my $rule (keys %{$pms->{conf}->{reuse_tests}}) {
dbg("reuse: looking at rule $rule");
my ($priority, $stage) = @{$pms->{conf}->{reuse_tests_order}->{$rule}};
# score set could change after check_start but before we add hits,
# so we need to disable the rule in all sets
foreach my $ss (0..3) {
if (exists $pms->{conf}->{scoreset}->[$ss]->{$rule}) {
dbg("reuse: disabling rule $rule in score set $ss");
$pms->{reuse_old_scores}->{$rule}->[$ss] =
$pms->{conf}->{scoreset}->[$ss]->{$rule};
$pms->{conf}->{scoreset}->[$ss]->{$rule} = 0;
}
}
# now, check for hits
OLD: foreach my $old_test (@{$pms->{conf}->{reuse_tests}->{$rule}}) {
dbg("reuse: looking for rule $old_test");
if ($old_hash->{$old_test}) {
push @{$pms->{reuse_hits_to_add}->{"$priority $stage"}}, $rule;
dbg("reuse: rule $rule hit, will add at priority $priority, stage " .
"$stage");
last OLD;
}
}
}
}
sub check_end {
my ($self, $opts) = @_;
my $pms = $opts->{permsgstatus};
foreach my $disabled_rule (keys %{$pms->{reuse_old_scores}}) {
foreach my $ss (0..3) {
next unless exists $pms->{conf}->{scoreset}->[$ss]->{$disabled_rule};
$pms->{conf}->{scoreset}->[$ss]->{$disabled_rule} =
$pms->{reuse_old_scores}->{$disabled_rule}->[$ss];
}
}
delete $pms->{reuse_old_scores};
}
sub start_rules {
my ($self, $opts) = @_;
return $self->_add_hits($opts->{permsgstatus}, $opts->{priority},
$opts->{ruletype});
}
sub _add_hits {
my ($self, $pms, $priority, $stage) = @_;
return unless exists $pms->{reuse_hits_to_add}->{"$priority $stage"};
foreach my $rule (@{$pms->{reuse_hits_to_add}->{"$priority $stage"}}) {
# Add hit even if rule was originally disabled
my $ss = $pms->{conf}->get_score_set();
$pms->{conf}->{scores}->{$rule} =
$pms->{reuse_old_scores}->{$rule}->[$ss] || 0.001;
dbg("reuse: registering hit for $rule: score: " .
$pms->{conf}->{scores}->{$rule});
$pms->got_hit($rule);
$pms->{conf}->{scores}->{$rule} = 0;
}
}
my %type_to_stage = (
$Mail::SpamAssassin::Conf::TYPE_HEAD_TESTS => "head",
$Mail::SpamAssassin::Conf::TYPE_HEAD_EVALS => "eval",
$Mail::SpamAssassin::Conf::TYPE_BODY_TESTS => "body",
$Mail::SpamAssassin::Conf::TYPE_BODY_EVALS => "eval",
$Mail::SpamAssassin::Conf::TYPE_FULL_TESTS => "full",
$Mail::SpamAssassin::Conf::TYPE_FULL_EVALS => "eval",
$Mail::SpamAssassin::Conf::TYPE_RAWBODY_TESTS => "rawbody",
$Mail::SpamAssassin::Conf::TYPE_RAWBODY_EVALS => "eval",
$Mail::SpamAssassin::Conf::TYPE_URI_TESTS => "uri",
$Mail::SpamAssassin::Conf::TYPE_URI_EVALS => "eval",
$Mail::SpamAssassin::Conf::TYPE_META_TESTS => "meta",
$Mail::SpamAssassin::Conf::TYPE_RBL_EVALS => "eval",
);
sub _get_stage_from_rule {
my ($self, $conf, $rule) = @_;
my $type = $conf->{test_types}->{$rule};
if ($type && $type == $Mail::SpamAssassin::Conf::TYPE_EMPTY_TESTS) {
# this is a "fake" rule... see if the rule "text"/"definition" is
# the name of the "parent" rule"
my $parent = $conf->{tests}->{$rule};
if ($parent) {
$type = $conf->{test_types}->{$parent};
}
}
if ($type && exists $type_to_stage{$type}) {
return $type_to_stage{$type};
}
else {
# Run before the meta rules run so that they can use these hits as
# inputs.
return "meta";
}
}
|