diff -Naur Mail-SpamAssassin-3.1.1-vanilla/lib/Mail/SpamAssassin/Conf/Parser.pm Mail-SpamAssassin-3.1.1/lib/Mail/SpamAssassin/Conf/Parser.pm --- Mail-SpamAssassin-3.1.1-vanilla/lib/Mail/SpamAssassin/Conf/Parser.pm 2006-03-10 13:29:53.000000000 -0600 +++ Mail-SpamAssassin-3.1.1/lib/Mail/SpamAssassin/Conf/Parser.pm 2006-03-22 22:03:22.000000000 -0600 @@ -856,7 +856,12 @@ $conf->{tests}->{$name} = $text; $conf->{test_types}->{$name} = $type; $conf->{tflags}->{$name} ||= ''; - $conf->{priority}->{$name} ||= 0; + if ($type == $Mail::SpamAssassin::Conf::TYPE_META_TESTS) { + $conf->{priority}->{$name} ||= 500; + } + else { + $conf->{priority}->{$name} ||= 0; + } $conf->{source_file}->{$name} = $self->{currentfile}; if ($self->{scoresonly}) { diff -Naur Mail-SpamAssassin-3.1.1-vanilla/lib/Mail/SpamAssassin/Conf.pm Mail-SpamAssassin-3.1.1/lib/Mail/SpamAssassin/Conf.pm --- Mail-SpamAssassin-3.1.1-vanilla/lib/Mail/SpamAssassin/Conf.pm 2006-03-10 13:29:55.000000000 -0600 +++ Mail-SpamAssassin-3.1.1/lib/Mail/SpamAssassin/Conf.pm 2006-03-22 14:26:42.000000000 -0600 @@ -2149,6 +2149,67 @@ =back +=item shortcircuit SYMBOLIC_TEST_NAME [default|spam|ham] + +Short Circuiting a test will force all other pending rules to be +skipped. Recomended usage would be in conjunction with priority to +set rules with strong S/O values (ie 1.0) to be ran first and make +instant spam or ham classification based on that. + +=over 4 + +=item spam + +override the default score of this rule with the score from C. + +=item ham + +override the default score of this rule with the score from C. + +=item default + +uses the default score for this rule. + +=back + +=cut + + push (@cmds, { + setting => 'shortcircuit', + is_priv => 1, + type => $CONF_TYPE_HASH_KEY_VALUE + }); + +=item shortcircuit_spam_score n.nn (default: 100) + +when shortcircuit is used on a rule, and the shortcircuit type is +set to C, this value should be applied in place of the default +score for that rule. + +=cut + + push (@cmds, { + setting => 'shortcircuit_spam_score', + default => 100, + type => $CONF_TYPE_NUMERIC + }); + +=item shortcircuit_ham_score n.nn (default: -100) + +when shortcircuit is used on a rule, and the shortcircuit type is +set to C, this value should be applied in place of the default +score for that rule. + +=cut + + push (@cmds, { + setting => 'shortcircuit_ham_score', + default => -100, + type => $CONF_TYPE_NUMERIC + }); + +=back + =head1 ADMINISTRATOR SETTINGS These settings differ from the ones above, in that they are considered 'more diff -Naur Mail-SpamAssassin-3.1.1-vanilla/lib/Mail/SpamAssassin/Constants.pm Mail-SpamAssassin-3.1.1/lib/Mail/SpamAssassin/Constants.pm --- Mail-SpamAssassin-3.1.1-vanilla/lib/Mail/SpamAssassin/Constants.pm 2006-03-10 13:29:55.000000000 -0600 +++ Mail-SpamAssassin-3.1.1/lib/Mail/SpamAssassin/Constants.pm 2006-03-22 22:01:13.000000000 -0600 @@ -259,8 +259,8 @@ # --------------------------------------------------------------------------- -use constant META_TEST_MIN_PRIORITY => 500; -use constant HARVEST_DNSBL_PRIORITY => 500; +use constant META_TEST_MIN_PRIORITY => -500; +use constant HARVEST_DNSBL_PRIORITY => -800; # regular expression that matches message separators in The University of # Washington's MBX mailbox format diff -Naur Mail-SpamAssassin-3.1.1-vanilla/lib/Mail/SpamAssassin/PerMsgStatus.pm Mail-SpamAssassin-3.1.1/lib/Mail/SpamAssassin/PerMsgStatus.pm --- Mail-SpamAssassin-3.1.1-vanilla/lib/Mail/SpamAssassin/PerMsgStatus.pm 2006-03-10 13:29:55.000000000 -0600 +++ Mail-SpamAssassin-3.1.1/lib/Mail/SpamAssassin/PerMsgStatus.pm 2006-03-22 22:11:52.000000000 -0600 @@ -170,11 +170,14 @@ # happen in Conf.pm when we switch a rules from one priority to another next unless ($self->{conf}->{priorities}->{$priority} > 0); + # if shortcircuiting is set, we skip all other priorities... + last if (exists $self->{shortcircuit}); + dbg("check: running tests for priority: $priority"); # only harvest the dnsbl queries once priority HARVEST_DNSBL_PRIORITY # has been reached and then only run once - if ($priority >= HARVEST_DNSBL_PRIORITY && $needs_dnsbl_harvest_p) { + if ($priority >= HARVEST_DNSBL_PRIORITY && $needs_dnsbl_harvest_p && !exists $self->{shortcircuit}) { # harvest the DNS results $self->harvest_dnsbl_queries(); $needs_dnsbl_harvest_p = 0; @@ -213,7 +216,7 @@ # sanity check, it is possible that no rules >= HARVEST_DNSBL_PRIORITY ran so the harvest # may not have run yet. Check, and if so, go ahead and harvest here. - if ($needs_dnsbl_harvest_p) { + if ($needs_dnsbl_harvest_p && !exists $self->{shortcircuit}) { # harvest the DNS results $self->harvest_dnsbl_queries(); @@ -1613,6 +1616,8 @@ my ($self, $priority) = @_; local ($_); + return if (exists $self->{shortcircuit}); + # note: we do this only once for all head pattern tests. Only # eval tests need to use stuff in here. $self->{test_log_msgs} = (); # clear test state @@ -1639,6 +1644,9 @@ my $evalstr2 = ''; while (my($rulename, $rule) = each %{$self->{conf}{head_tests}->{$priority}}) { + last if (exists $self->{shortcircuit}); + dbg("priority: running high priority ($priority) header $rulename") if ($priority < 0); + my $def = ''; my ($hdrname, $testtype, $pat) = $rule =~ /^\s*(\S+)\s*(\=|\!)\~\s*(\S.*?\S)\s*$/; @@ -1717,6 +1725,8 @@ my ($self, $priority, $textary) = @_; local ($_); + return if (exists $self->{shortcircuit}); + dbg("rules: running body-text per-line regexp tests; score so far=".$self->{score}); my $doing_user_rules = @@ -1740,6 +1750,8 @@ my $evalstr2 = ''; while (my($rulename, $pat) = each %{$self->{conf}{body_tests}->{$priority}}) { + last if (exists $self->{shortcircuit}); + dbg("priority: running high priority ($priority) body $rulename") if ($priority < 0); $evalstr .= ' if ($self->{conf}->{scores}->{q{'.$rulename.'}}) { # call procedurally as it is faster. @@ -2129,6 +2141,8 @@ my ($self, $priority, @uris) = @_; local ($_); + return if (exists $self->{shortcircuit}); + dbg("uri: running uri tests; score so far=".$self->{score}); my $doing_user_rules = @@ -2152,6 +2166,9 @@ my $evalstr2 = ''; while (my($rulename, $pat) = each %{$self->{conf}{uri_tests}->{$priority}}) { + last if (exists $self->{shortcircuit}); + dbg("priority: running high priority ($priority) body uri $rulename") if ($priority < 0); + $evalstr .= ' if ($self->{conf}->{scores}->{q{'.$rulename.'}}) { '.$rulename.'_uri_test($self, @_); # call procedurally for speed @@ -2218,6 +2235,8 @@ my ($self, $priority, $textary) = @_; local ($_); + return if (exists $self->{shortcircuit}); + dbg("rules: running raw-body-text per-line regexp tests; score so far=".$self->{score}); my $doing_user_rules = @@ -2241,7 +2260,9 @@ my $evalstr2 = ''; while (my($rulename, $pat) = each %{$self->{conf}{rawbody_tests}->{$priority}}) { - $evalstr .= ' + last if (exists $self->{shortcircuit}); + dbg("priority: running high priority ($priority) rawbody $rulename") if ($priority < 0); + $evalstr .= ' if ($self->{conf}->{scores}->{q{'.$rulename.'}}) { '.$rulename.'_rawbody_test($self, @_); # call procedurally for speed } @@ -2330,6 +2351,7 @@ my $evalstr = ''; while (my($rulename, $pat) = each %{$self->{conf}{full_tests}->{$priority}}) { + dbg("priority: running high priority ($priority) body $rulename") if ($priority < 0); $evalstr .= ' if ($self->{conf}->{scores}->{q{'.$rulename.'}}) { '.$self->hash_line_for_rule($rulename).' @@ -2378,25 +2400,25 @@ sub do_head_eval_tests { my ($self, $priority) = @_; return unless (defined($self->{conf}->{head_evals}->{$priority})); - $self->run_eval_tests ($self->{conf}->{head_evals}->{$priority}, ''); + $self->run_eval_tests ($priority,$self->{conf}->{head_evals}->{$priority}, ''); } sub do_body_eval_tests { my ($self, $priority, $bodystring) = @_; return unless (defined($self->{conf}->{body_evals}->{$priority})); - $self->run_eval_tests ($self->{conf}->{body_evals}->{$priority}, 'BODY: ', $bodystring); + $self->run_eval_tests ($priority,$self->{conf}->{body_evals}->{$priority}, 'BODY: ', $bodystring); } sub do_rawbody_eval_tests { my ($self, $priority, $bodystring) = @_; return unless (defined($self->{conf}->{rawbody_evals}->{$priority})); - $self->run_eval_tests ($self->{conf}->{rawbody_evals}->{$priority}, 'RAW: ', $bodystring); + $self->run_eval_tests ($priority,$self->{conf}->{rawbody_evals}->{$priority}, 'RAW: ', $bodystring); } sub do_full_eval_tests { my ($self, $priority, $fullmsgref) = @_; return unless (defined($self->{conf}->{full_evals}->{$priority})); - $self->run_eval_tests ($self->{conf}->{full_evals}->{$priority}, '', $fullmsgref); + $self->run_eval_tests ($priority,$self->{conf}->{full_evals}->{$priority}, '', $fullmsgref); } ########################################################################### @@ -2405,6 +2427,8 @@ my ($self, $priority) = @_; local ($_); + return if (exists $self->{shortcircuit}); + dbg("rules: running meta tests; score so far=" . $self->{score} ); my $doing_user_rules = @@ -2431,6 +2455,9 @@ # Go through each rule and figure out what we need to do foreach $rulename (@metas) { + last if (exists $self->{shortcircuit}); + dbg("priority: running high priority ($priority) meta $rulename") if ($priority < 0); + my $rule = $self->{conf}->{meta_tests}->{$priority}->{$rulename}; my $token; @@ -2543,14 +2570,19 @@ ########################################################################### sub run_eval_tests { - my ($self, $evalhash, $prepend2desc, @extraevalargs) = @_; + my ($self, $priority, $evalhash, $prepend2desc, @extraevalargs) = @_; local ($_); + + return if (exists $self->{shortcircuit}); my $debugenabled = would_log('dbg'); my $scoreset = $self->{conf}->get_score_set(); while (my ($rulename, $test) = each %{$evalhash}) { + last if (exists $self->{shortcircuit}); + dbg("priority: running high priority ($priority) eval $rulename") if ($priority < 0); + # Score of 0, skip it. next unless ($self->{conf}->{scores}->{$rulename}); @@ -2753,6 +2785,18 @@ my $score = $self->{conf}->{scores}->{$rule}; + my $sc = $self->{conf}->{shortcircuit}; + if (defined $sc->{$rule}) { + $self->{shortcircuit} = $rule; + if ($sc->{$rule} =~ m/spam/) { + $score = $self->{conf}->{shortcircuit_spam_score}; + } + elsif ($sc->{$rule} =~ m/ham/) { + $score = $self->{conf}->{shortcircuit_ham_score}; + } + dbg("shortcircuit: hit on rule $rule, sc type is " . $sc->{$rule} . ", apply score of $score"); + } + $self->_handle_hit($rule, $score, $area, $desc); } diff -Naur Mail-SpamAssassin-3.1.1-vanilla/lib/Mail/SpamAssassin/Plugin/URIDNSBL.pm Mail-SpamAssassin-3.1.1/lib/Mail/SpamAssassin/Plugin/URIDNSBL.pm --- Mail-SpamAssassin-3.1.1-vanilla/lib/Mail/SpamAssassin/Plugin/URIDNSBL.pm 2006-03-10 13:29:54.000000000 -0600 +++ Mail-SpamAssassin-3.1.1/lib/Mail/SpamAssassin/Plugin/URIDNSBL.pm 2006-03-22 22:10:36.000000000 -0600 @@ -398,6 +398,8 @@ return if ($self->{dns_not_available}); my $scan = $opts->{permsgstatus}; + return if (exists $scan->{shortcircuit}); + my $scanstate = $scan->{uribl_scanstate}; # try to complete a few more diff -Naur Mail-SpamAssassin-3.1.1-vanilla/MANIFEST Mail-SpamAssassin-3.1.1/MANIFEST --- Mail-SpamAssassin-3.1.1-vanilla/MANIFEST 2006-03-10 13:30:24.000000000 -0600 +++ Mail-SpamAssassin-3.1.1/MANIFEST 2006-03-22 14:26:42.000000000 -0600 @@ -197,6 +197,7 @@ rules/30_text_pt_br.cf rules/50_scores.cf rules/60_awl.cf +rules/60_shortcircuit.cf rules/60_whitelist.cf rules/60_whitelist_spf.cf rules/60_whitelist_subject.cf diff -Naur Mail-SpamAssassin-3.1.1-vanilla/rules/60_shortcircuit.cf Mail-SpamAssassin-3.1.1/rules/60_shortcircuit.cf --- Mail-SpamAssassin-3.1.1-vanilla/rules/60_shortcircuit.cf 1969-12-31 18:00:00.000000000 -0600 +++ Mail-SpamAssassin-3.1.1/rules/60_shortcircuit.cf 2006-03-22 22:02:07.000000000 -0600 @@ -0,0 +1,57 @@ +# SpamAssassin rules file: spam and ham shortcircuiting using priorities +# +# Please don't modify this file as your changes will be overwritten with +# the next update. Use @@LOCAL_RULES_DIR@@/local.cf instead. +# See 'perldoc Mail::SpamAssassin::Conf' for details. +# +# <@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. +# + +########################################################################### +# HAM + +priority USER_IN_WHITELIST -1000 +shortcircuit USER_IN_WHITELIST default + +priority USER_IN_DEF_WHITELIST -1000 +shortcircuit USER_IN_DEF_WHITELIST default + +priority USER_IN_ALL_SPAM_TO -1000 +shortcircuit USER_IN_ALL_SPAM_TO default + +priority SUBJECT_IN_WHITELIST -1000 +shortcircuit SUBJECT_IN_WHITELIST default + +priority ALL_TRUSTED -950 +shortcircuit ALL_TRUSTED default + + +########################################################################### +# SPAM + +priority USER_IN_BLACKLIST -900 +shortcircuit USER_IN_BLACKLIST default + +priority USER_IN_BLACKLIST_TO -900 +shortcircuit USER_IN_BLACKLIST_TO default + +priority SUBJECT_IN_BLACKLIST -900 +shortcircuit SUBJECT_IN_BLACKLIST default + +# some people may want this? +# priority BAYES_99 -900 +# shortcircuit BAYES_99 spam +