196 lines
5.2 KiB
Perl
196 lines
5.2 KiB
Perl
# <@LICENSE>
|
|
# Copyright 2004 Apache Software Foundation
|
|
#
|
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
# you may not use this file except in compliance with the License.
|
|
# You may obtain a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
# See the License for the specific language governing permissions and
|
|
# limitations under the License.
|
|
# </@LICENSE>
|
|
|
|
package Mail::SpamAssassin::Plugin::P595Body;
|
|
|
|
use Mail::SpamAssassin::Plugin;
|
|
use Mail::SpamAssassin::Logger;
|
|
use Mail::SpamAssassin::Plugin::BodyRuleBaseExtractor;
|
|
use Mail::SpamAssassin::Plugin::OneLineBodyRuleType;
|
|
use Mail::SpamAssassin::Util qw(qr_to_string);
|
|
|
|
use strict;
|
|
use warnings;
|
|
# use bytes;
|
|
use re 'taint';
|
|
|
|
our @ISA = qw(Mail::SpamAssassin::Plugin);
|
|
|
|
sub new {
|
|
my $class = shift;
|
|
my $mailsaobject = shift;
|
|
$class = ref($class) || $class;
|
|
my $self = $class->SUPER::new($mailsaobject);
|
|
bless ($self, $class);
|
|
|
|
$self->{one_line_body} = Mail::SpamAssassin::Plugin::OneLineBodyRuleType->new();
|
|
|
|
if ($] < 5.009005) {
|
|
die "this plugin requires perl 5.9.5 or later";
|
|
}
|
|
|
|
return $self;
|
|
}
|
|
|
|
###########################################################################
|
|
|
|
sub finish_parsing_end {
|
|
my ($self, $params) = @_;
|
|
my $conf = $params->{conf};
|
|
|
|
my $main = $self->{main};
|
|
|
|
$conf->{skip_body_rules} ||= { };
|
|
$self->setup_test_set ($conf, $conf->{body_tests}, 'body');
|
|
}
|
|
|
|
sub setup_test_set {
|
|
my ($self, $conf, $test_set, $ruletype) = @_;
|
|
foreach my $pri (keys %{$test_set}) {
|
|
my $nicepri = $pri; $nicepri =~ s/-/neg/g;
|
|
$self->setup_test_set_pri($conf, $test_set->{$pri},
|
|
$ruletype.'_'.$nicepri, $pri);
|
|
}
|
|
}
|
|
|
|
sub setup_test_set_pri {
|
|
my ($self, $conf, $rules, $ruletype, $pri) = @_;
|
|
|
|
my $alternates = [];
|
|
while (my ($rule, $pat) = each %{$conf->{body_tests}->{$pri}}) {
|
|
# ignore rules marked for ReplaceTags work!
|
|
next if ($conf->{replace_rules}->{$rule});
|
|
# ignore regex capture template rules
|
|
next if ($conf->{capture_rules}->{$rule});
|
|
next if ($conf->{capture_template_rules}->{$rule});
|
|
|
|
#$pat = Mail::SpamAssassin::Util::regexp_remove_delimiters($pat);
|
|
$pat = qr_to_string($conf->{test_qrs}->{$rule});
|
|
next unless !$pat;
|
|
|
|
# use the REGMARK feature:
|
|
# see http://taint.org/2006/11/16/154546a.html#comment-1011
|
|
#
|
|
push @{$alternates}, "$pat(*:$rule)";
|
|
|
|
# TODO: need a cleaner way to do this. I expect when rule types
|
|
# are implementable in plugins, I can do it that way
|
|
$conf->{skip_body_rules}->{$rule} = 1;
|
|
}
|
|
|
|
my $sub = '
|
|
sub {
|
|
our $REGMARK;
|
|
our @matched = ();
|
|
$_[0] =~ m#('.join('|', @{$alternates}).')(?{
|
|
push @matched, $REGMARK;
|
|
})(*FAIL)#;
|
|
return @matched;
|
|
}
|
|
';
|
|
# warn "JMD $sub";
|
|
|
|
$conf->{$ruletype}->{trie_re_sub} = eval $sub;
|
|
if ($@) { warn "REGMARK sub compilation failed: $@"; }
|
|
}
|
|
|
|
###########################################################################
|
|
|
|
# delegate these to the OneLineBodyRuleType object
|
|
sub check_start {
|
|
my ($self, $params) = @_;
|
|
$self->{one_line_body}->check_start($params);
|
|
}
|
|
|
|
sub check_rules_at_priority {
|
|
my ($self, $params) = @_;
|
|
$self->{one_line_body}->check_rules_at_priority($params);
|
|
}
|
|
|
|
sub check_cleanup {
|
|
my ($self, $params) = @_;
|
|
$self->{one_line_body}->check_cleanup($params);
|
|
}
|
|
|
|
###########################################################################
|
|
|
|
sub run_body_fast_scan {
|
|
my ($self, $params) = @_;
|
|
|
|
return unless ($params->{ruletype} eq 'body');
|
|
|
|
my $pri = $params->{priority};
|
|
my $nicepri = $params->{priority}; $nicepri =~ s/-/neg/g;
|
|
my $ruletype = ($params->{ruletype}.'_'.$nicepri);
|
|
my $scanner = $params->{permsgstatus};
|
|
my $conf = $scanner->{conf};
|
|
|
|
my $trie_re_sub = $conf->{$ruletype}->{trie_re_sub};
|
|
if (!$trie_re_sub)
|
|
{
|
|
dbg("zoom: run_body_fast_scan for $ruletype skipped, no rules");
|
|
return;
|
|
}
|
|
|
|
my $do_dbg = (would_log('dbg', 'zoom') > 1);
|
|
my $scoresptr = $conf->{scores};
|
|
|
|
dbg("zoom: run_body_fast_scan for $ruletype start");
|
|
|
|
{
|
|
no strict "refs";
|
|
foreach my $line (@{$params->{lines}})
|
|
{
|
|
my @caught = $trie_re_sub->($line);
|
|
next unless (scalar @caught > 0);
|
|
|
|
my %alreadydone;
|
|
foreach my $rulename (@caught) {
|
|
{
|
|
next if not defined $rulename;
|
|
# only try each rule once per line
|
|
next if exists $alreadydone{$rulename};
|
|
$alreadydone{$rulename} = undef;
|
|
|
|
# ignore 0-scored rules, of course
|
|
next unless $scoresptr->{$rulename};
|
|
|
|
$scanner->got_hit($rulename, "BODY: ", ruletype => "p595_body");
|
|
}
|
|
}
|
|
}
|
|
use strict "refs";
|
|
}
|
|
|
|
dbg("zoom: run_body_fast_scan for $ruletype done");
|
|
}
|
|
|
|
sub finish {
|
|
my ($self) = @_;
|
|
|
|
my $do_dbg = (would_log('dbg', 'zoom') > 1);
|
|
return unless $do_dbg;
|
|
|
|
my $miss = $self->{rule2xs_misses};
|
|
foreach my $r (sort { $miss->{$a} <=> $miss->{$b} } keys %{$miss}) {
|
|
dbg("zoom: %s misses for rule2xs rule %s", $miss->{$r},$r);
|
|
}
|
|
}
|
|
|
|
###########################################################################
|
|
|
|
1;
|