You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@spamassassin.apache.org by gb...@apache.org on 2019/10/21 09:34:52 UTC
svn commit: r1868685 - in /spamassassin: branches/3.4/UPGRADE
branches/3.4/lib/Mail/SpamAssassin/Conf.pm
branches/3.4/lib/Mail/SpamAssassin/PerMsgStatus.pm trunk/UPGRADE
trunk/lib/Mail/SpamAssassin/Conf.pm
trunk/lib/Mail/SpamAssassin/PerMsgStatus.pm
Author: gbechis
Date: Mon Oct 21 09:34:51 2019
New Revision: 1868685
URL: http://svn.apache.org/viewvc?rev=1868685&view=rev
Log:
Add a new subjprefix keyword.
This keyword will add a prefix in emails Subject if a rule is matched.
To enable this option "rewrite_header Subject" config option must be enabled
as well.
The check "if can(Mail::SpamAssassin::Conf::feature_subjprefix)"
should be used to silence warnings in previous SpamAssassin
versions.
This feature could not work out-of-the box if the glue
software that calls SpamAssassin (MimeDefang, Amavisd-new, ...)
uses the original email instead of the one produced by SA.
Some improvements to those softwares may be needed before enabling
this feature.
Modified:
spamassassin/branches/3.4/UPGRADE
spamassassin/branches/3.4/lib/Mail/SpamAssassin/Conf.pm
spamassassin/branches/3.4/lib/Mail/SpamAssassin/PerMsgStatus.pm
spamassassin/trunk/UPGRADE
spamassassin/trunk/lib/Mail/SpamAssassin/Conf.pm
spamassassin/trunk/lib/Mail/SpamAssassin/PerMsgStatus.pm
Modified: spamassassin/branches/3.4/UPGRADE
URL: http://svn.apache.org/viewvc/spamassassin/branches/3.4/UPGRADE?rev=1868685&r1=1868684&r2=1868685&view=diff
==============================================================================
--- spamassassin/branches/3.4/UPGRADE (original)
+++ spamassassin/branches/3.4/UPGRADE Mon Oct 21 09:34:51 2019
@@ -1,6 +1,9 @@
Note for Users Upgrading to SpamAssassin 3.4.3
----------------------------------------------
+- New subjprefix keyword added, this can be used to add a prefix to
+ email Subject if the original email matches a particular rule
+
- New Util::is_fqdn_valid() function to validate hostname (DNS name) format
(Bug 7736). To check if a name contains valid TLD, it's still needed to
additionally use RegistryBoundaries::is_domain_valid()
Modified: spamassassin/branches/3.4/lib/Mail/SpamAssassin/Conf.pm
URL: http://svn.apache.org/viewvc/spamassassin/branches/3.4/lib/Mail/SpamAssassin/Conf.pm?rev=1868685&r1=1868684&r2=1868685&view=diff
==============================================================================
--- spamassassin/branches/3.4/lib/Mail/SpamAssassin/Conf.pm (original)
+++ spamassassin/branches/3.4/lib/Mail/SpamAssassin/Conf.pm Mon Oct 21 09:34:51 2019
@@ -900,6 +900,25 @@ header.
}
});
+=item subjprefix
+
+Add a prefix in emails Subject if a rule is matched.
+To enable this option "rewrite_header Subject" config
+option must be enabled as well.
+
+The check C<if can(Mail::SpamAssassin::Conf::feature_subjprefix)>
+should be used to silence warnings in previous
+SpamAssassin versions.
+
+=cut
+
+ push (@cmds, {
+ command => 'subjprefix',
+ setting => 'subjprefix',
+ is_frequent => 1,
+ type => $CONF_TYPE_HASH_KEY_VALUE,
+ });
+
=item add_header { spam | ham | all } header_name string
Customized headers can be added to the specified type of messages (spam,
@@ -4303,6 +4322,8 @@ optional, and the default is shown below
_LANGUAGES_ possible languages of mail
_PREVIEW_ content preview
_REPORT_ terse report of tests hit (for header reports)
+ _SUBJPREFIX_ subject prefix based on rules, to be prepended to Subject
+ header by SpamAssassin caller
_SUMMARY_ summary of tests hit for standard report (for body reports)
_CONTACTADDRESS_ contents of the 'report_contact' setting
_HEADER(NAME)_ includes the value of a message header. value is the same
@@ -4440,6 +4461,7 @@ sub new {
$self->{descriptions} = { };
#tie %{$self->{descriptions}}, 'Mail::SpamAssassin::Util::TieOneStringHash'
# or warn "tie failed";
+ $self->{subjprefix} = { };
# after parsing, tests are refiled into these hashes for each test type.
# this allows e.g. a full-text test to be rewritten as a body test in
@@ -5019,6 +5041,7 @@ sub new_netset {
sub finish {
my ($self) = @_;
untie %{$self->{descriptions}};
+ untie %{$self->{subjprefix}};
%{$self} = ();
}
@@ -5042,6 +5065,7 @@ sub feature_dns_query_restriction { 1 }
sub feature_registryboundaries { 1 } # replaces deprecated registrarboundaries
sub feature_compile_regexp { 1 } # Util::compile_regexp
sub feature_meta_rules_matching { 1 } # meta rules_matching() expression
+sub feature_subjprefix { 1 } # add subject prefixes rule option
sub has_tflags_nosubject { 1 } # tflags nosubject
sub perl_min_version_5010000 { return $] >= 5.010000 } # perl version check ("perl_version" not neatly backwards-compatible)
Modified: spamassassin/branches/3.4/lib/Mail/SpamAssassin/PerMsgStatus.pm
URL: http://svn.apache.org/viewvc/spamassassin/branches/3.4/lib/Mail/SpamAssassin/PerMsgStatus.pm?rev=1868685&r1=1868684&r2=1868685&view=diff
==============================================================================
--- spamassassin/branches/3.4/lib/Mail/SpamAssassin/PerMsgStatus.pm (original)
+++ spamassassin/branches/3.4/lib/Mail/SpamAssassin/PerMsgStatus.pm Mon Oct 21 09:34:51 2019
@@ -213,6 +213,11 @@ BEGIN {
"\n" . ($pms->{tag_data}->{REPORT} || "");
},
+ SUBJPREFIX => sub {
+ my $pms = shift;
+ ($pms->{tag_data}->{SUBJPREFIX} || "");
+ },
+
HEADER => sub {
my $pms = shift;
my $hdr = shift;
@@ -269,6 +274,7 @@ sub new {
'master_deadline' => $msg->{master_deadline}, # dflt inherited from msg
'deadline_exceeded' => 0, # time limit exceeded, skipping further tests
'uri_detail_list' => { },
+ 'subjprefix' => "",
};
dbg("check: pms new, time limit in %.3f s",
@@ -293,7 +299,7 @@ sub new {
# known valid tags that might not get their entry in pms->{tag_data}
# in some circumstances
my $tag_data_ref = $self->{tag_data};
- foreach (qw(SUMMARY REPORT RBL)) { $tag_data_ref->{$_} = '' }
+ foreach (qw(SUMMARY REPORT SUBJPREFIX RBL)) { $tag_data_ref->{$_} = '' }
foreach (qw(AWL AWLMEAN AWLCOUNT AWLPRESCORE
DCCB DCCR DCCREP PYZOR DKIMIDENTITY DKIMDOMAIN
BAYESTC BAYESTCLEARNED BAYESTCSPAMMY BAYESTCHAMMY
@@ -1042,6 +1048,8 @@ sub _get_added_headers {
sub rewrite_report_safe {
my ($self) = @_;
+ my $tag;
+
# This is the original message. We do not want to make any modifications so
# we may recover it if necessary. It will be put into the new message as a
# message/rfc822 MIME part.
@@ -1079,8 +1087,15 @@ sub rewrite_report_safe {
# possibilities right now, it's easier not to...
if (defined $self->{conf}->{rewrite_header}->{Subject}) {
+ # Add a prefix to the subject if needed
+ if((defined $self->{subjprefix}) and ($self->{subjprefix} ne "")) {
+ $tag = $self->_replace_tags($self->{subjprefix});
+ $tag =~ s/\n/ /gs;
+ $subject = $tag . $subject;
+ }
+ # Add a **SPAM** prefix
$subject = "\n" if !defined $subject;
- my $tag = $self->_replace_tags($self->{conf}->{rewrite_header}->{Subject});
+ $tag = $self->_replace_tags($self->{conf}->{rewrite_header}->{Subject});
$tag =~ s/\n/ /gs; # strip tag's newlines
$subject =~ s/^(?:\Q${tag}\E )?/${tag} /g; # For some reason the tag may already be there!?
}
@@ -1208,6 +1223,9 @@ EOM
sub rewrite_no_report_safe {
my ($self) = @_;
+ my $ntag;
+ my $pref_subject = 0;
+
# put the pristine headers into an array
# skip the X-Spam- headers, but allow the X-Spam-Prev headers to remain.
# since there may be a missing header/body
@@ -1259,11 +1277,55 @@ sub rewrite_no_report_safe {
# The tag should be a comment for this header ...
$tag = "($tag)" if ($hdr =~ /^(?:From|To)$/);
- local $1;
+ if((defined $self->{subjprefix}) and (defined $self->{conf}->{rewrite_header}->{Subject})) {
+ if($self->{subjprefix} ne "") {
+ $ntag = $self->_replace_tags($self->{subjprefix});
+ $ntag =~ s/\n/ /gs;
+ $ntag =~ s/\s+$//;
+
+ local $1;
+ if(defined $ntag) {
+ s/^([^:]+:)[ \t]*(?:\Q${ntag}\E )?/$1 ${ntag} /i;
+ }
+ }
+ }
s/^([^:]+:)[ \t]*(?:\Q${tag}\E )?/$1 ${tag} /i;
}
$addition = 'headers_spam';
+ } else {
+ # special-case: Subject lines. ensure one exists, if we're
+ # supposed to mark it up.
+ my $created_subject = 0;
+ my $subject = $self->{msg}->get_pristine_header('Subject');
+ if (!defined($subject)
+ && exists $self->{conf}->{rewrite_header}->{'Subject'})
+ {
+ push(@pristine_headers, "Subject: \n");
+ $created_subject = 1;
+ }
+
+ # Deal with header rewriting
+ foreach (@pristine_headers) {
+ # if we're not going to do a rewrite, skip this header!
+ next if (!/^(Subject):/i);
+ my $hdr = ucfirst(lc($1));
+ next if (!defined $self->{conf}->{rewrite_header}->{$hdr});
+
+ if((defined $self->{subjprefix}) and (defined $self->{conf}->{rewrite_header}->{Subject})) {
+ if($self->{subjprefix} ne "") {
+ $ntag = $self->_replace_tags($self->{subjprefix});
+ $ntag =~ s/\n/ /gs;
+ $ntag =~ s/\s+$//;
+
+ local $1;
+ if(defined $ntag) {
+ s/^([^:]+:)[ \t]*(?:\Q${ntag}\E )?/$1 ${ntag} /i;
+ }
+ }
+ }
+ }
+
}
# Break the pristine header set into two blocks; $new_hdrs_pre is the stuff
@@ -2666,6 +2728,9 @@ sub _handle_hit {
$self->_wrap_desc($desc,
3+length($rule)+length($score)+length($area), " " x 28),
($self->{test_log_msgs}->{LONG} || ''));
+ if((defined $self->{subjprefix}) and ($self->{subjprefix} ne "")) {
+ $self->{tag_data}->{SUBJPREFIX} = $self->{subjprefix};
+ }
}
sub _wrap_desc {
@@ -2796,6 +2861,16 @@ sub got_hit {
#$rule_descr = $rule if !defined $rule_descr || $rule_descr eq '';
$rule_descr = "No description available." if !defined $rule_descr || $rule_descr eq '';
+ if(defined $self->{conf}->{rewrite_header}->{Subject}) {
+ my $rule_subjprefix = $conf_ref->{subjprefix}->{$rule};
+ if (defined $rule_subjprefix) {
+ dbg("subjprefix: setting Subject prefix to $rule_subjprefix");
+ if($self->{subjprefix} !~ /\Q$rule_subjprefix\E/) {
+ $self->{subjprefix} .= $rule_subjprefix . " "; # save dynamic subject prefix.
+ }
+ }
+ }
+
$self->_handle_hit($rule,
$score,
$area,
Modified: spamassassin/trunk/UPGRADE
URL: http://svn.apache.org/viewvc/spamassassin/trunk/UPGRADE?rev=1868685&r1=1868684&r2=1868685&view=diff
==============================================================================
--- spamassassin/trunk/UPGRADE (original)
+++ spamassassin/trunk/UPGRADE Mon Oct 21 09:34:51 2019
@@ -2,6 +2,9 @@
Note for Users Upgrading to SpamAssassin 4.0.0
----------------------------------------------
+- New subjprefix keyword added, this can be used to add a prefix to
+ email Subject if the original email matches a particular rule
+
- All log output (stderr, file, syslog) is now escaped properly,
\r \n \t \\, and control chars, DEL, UTF-8 sequences as \x{XX}.
Whitespace is not normalized anymore like in versions <4.0.
Modified: spamassassin/trunk/lib/Mail/SpamAssassin/Conf.pm
URL: http://svn.apache.org/viewvc/spamassassin/trunk/lib/Mail/SpamAssassin/Conf.pm?rev=1868685&r1=1868684&r2=1868685&view=diff
==============================================================================
--- spamassassin/trunk/lib/Mail/SpamAssassin/Conf.pm (original)
+++ spamassassin/trunk/lib/Mail/SpamAssassin/Conf.pm Mon Oct 21 09:34:51 2019
@@ -899,6 +899,25 @@ header.
}
});
+=item subjprefix
+
+Add a prefix in emails Subject if a rule is matched.
+To enable this option "rewrite_header Subject" config
+option must be enabled as well.
+
+The check C<if can(Mail::SpamAssassin::Conf::feature_subjprefix)>
+should be used to silence warnings in previous
+SpamAssassin versions.
+
+=cut
+
+ push (@cmds, {
+ command => 'subjprefix',
+ setting => 'subjprefix',
+ is_frequent => 1,
+ type => $CONF_TYPE_HASH_KEY_VALUE,
+ });
+
=item add_header { spam | ham | all } header_name string
Customized headers can be added to the specified type of messages (spam,
@@ -4552,6 +4571,8 @@ optional, and the default is shown below
_LANGUAGES_ possible languages of mail
_PREVIEW_ content preview
_REPORT_ terse report of tests hit (for header reports)
+ _SUBJPREFIX_ subject prefix based on rules, to be prepended to Subject
+ header by SpamAssassin caller
_SUMMARY_ summary of tests hit for standard report (for body reports)
_CONTACTADDRESS_ contents of the 'report_contact' setting
_HEADER(NAME)_ includes the value of a message header. value is the same
@@ -4689,6 +4710,7 @@ sub new {
$self->{descriptions} = { };
#tie %{$self->{descriptions}}, 'Mail::SpamAssassin::Util::TieOneStringHash'
# or warn "tie failed";
+ $self->{subjprefix} = { };
# after parsing, tests are refiled into these hashes for each test type.
# this allows e.g. a full-text test to be rewritten as a body test in
@@ -5264,6 +5286,7 @@ sub new_netset {
sub finish {
my ($self) = @_;
untie %{$self->{descriptions}};
+ untie %{$self->{subjprefix}};
%{$self} = ();
}
@@ -5289,6 +5312,7 @@ sub feature_geodb { 1 } # if needed for
sub feature_dns_block_rule { 1 } # supports 'dns_block_rule' config option
sub feature_compile_regexp { 1 } # Util::compile_regexp
sub feature_meta_rules_matching { 1 } # meta rules_matching() expression
+sub feature_subjprefix { 1 } # add subject prefixes rule option
sub feature_get_host { 1 } # $pms->get() :host :domain :ip :revip # was implemented together with AskDNS::has_tag_header # Bug 7734
sub has_tflags_nosubject { 1 } # tflags nosubject
sub perl_min_version_5010000 { return $] >= 5.010000 } # perl version check ("perl_version" not neatly backwards-compatible)
Modified: spamassassin/trunk/lib/Mail/SpamAssassin/PerMsgStatus.pm
URL: http://svn.apache.org/viewvc/spamassassin/trunk/lib/Mail/SpamAssassin/PerMsgStatus.pm?rev=1868685&r1=1868684&r2=1868685&view=diff
==============================================================================
--- spamassassin/trunk/lib/Mail/SpamAssassin/PerMsgStatus.pm (original)
+++ spamassassin/trunk/lib/Mail/SpamAssassin/PerMsgStatus.pm Mon Oct 21 09:34:51 2019
@@ -216,6 +216,11 @@ BEGIN {
"\n" . ($pms->{tag_data}->{REPORT} || "");
},
+ SUBJPREFIX => sub {
+ my $pms = shift;
+ ($pms->{tag_data}->{SUBJPREFIX} || "");
+ },
+
HEADER => sub {
my $pms = shift;
my $hdr = shift;
@@ -275,6 +280,7 @@ sub new {
'deadline_exceeded' => 0, # time limit exceeded, skipping further tests
'tmpfiles' => { },
'uri_detail_list' => { },
+ 'subjprefix' => "",
};
dbg("check: pms new, time limit in %.3f s",
@@ -299,7 +305,7 @@ sub new {
# known valid tags that might not get their entry in pms->{tag_data}
# in some circumstances
my $tag_data_ref = $self->{tag_data};
- foreach (qw(SUMMARY REPORT RBL)) { $tag_data_ref->{$_} = '' }
+ foreach (qw(SUMMARY REPORT SUBJPREFIX RBL)) { $tag_data_ref->{$_} = '' }
foreach (qw(AWL AWLMEAN AWLCOUNT AWLPRESCORE
DCCB DCCR DCCREP PYZOR DKIMIDENTITY DKIMDOMAIN
BAYESTC BAYESTCLEARNED BAYESTCSPAMMY BAYESTCHAMMY
@@ -1057,6 +1063,8 @@ sub _get_added_headers {
sub rewrite_report_safe {
my ($self) = @_;
+ my $tag;
+
# This is the original message. We do not want to make any modifications so
# we may recover it if necessary. It will be put into the new message as a
# message/rfc822 MIME part.
@@ -1096,8 +1104,15 @@ sub rewrite_report_safe {
# possibilities right now, it's easier not to...
if (defined $self->{conf}->{rewrite_header}->{Subject}) {
+ # Add a prefix to the subject if needed
+ if((defined $self->{subjprefix}) and ($self->{subjprefix} ne "")) {
+ $tag = $self->_replace_tags($self->{subjprefix});
+ $tag =~ s/\n/ /gs;
+ $subject = $tag . $subject;
+ }
+ # Add a **SPAM** prefix
$subject = "\n" if !defined $subject;
- my $tag = $self->_replace_tags($self->{conf}->{rewrite_header}->{Subject});
+ $tag = $self->_replace_tags($self->{conf}->{rewrite_header}->{Subject});
$tag =~ s/\n/ /gs; # strip tag's newlines
$subject =~ s/^(?:\Q${tag}\E )?/${tag} /g; # For some reason the tag may already be there!?
}
@@ -1225,6 +1240,9 @@ EOM
sub rewrite_no_report_safe {
my ($self) = @_;
+ my $ntag;
+ my $pref_subject = 0;
+
# put the pristine headers into an array
# skip the X-Spam- headers, but allow the X-Spam-Prev headers to remain.
# since there may be a missing header/body
@@ -1276,11 +1294,55 @@ sub rewrite_no_report_safe {
# The tag should be a comment for this header ...
$tag = "($tag)" if ($hdr =~ /^(?:From|To)$/);
- local $1;
+ if((defined $self->{subjprefix}) and (defined $self->{conf}->{rewrite_header}->{Subject})) {
+ if($self->{subjprefix} ne "") {
+ $ntag = $self->_replace_tags($self->{subjprefix});
+ $ntag =~ s/\n/ /gs;
+ $ntag =~ s/\s+$//;
+
+ local $1;
+ if(defined $ntag) {
+ s/^([^:]+:)[ \t]*(?:\Q${ntag}\E )?/$1 ${ntag} /i;
+ }
+ }
+ }
s/^([^:]+:)[ \t]*(?:\Q${tag}\E )?/$1 ${tag} /i;
}
$addition = 'headers_spam';
+ } else {
+ # special-case: Subject lines. ensure one exists, if we're
+ # supposed to mark it up.
+ my $created_subject = 0;
+ my $subject = $self->{msg}->get_pristine_header('Subject');
+ if (!defined($subject)
+ && exists $self->{conf}->{rewrite_header}->{'Subject'})
+ {
+ push(@pristine_headers, "Subject: \n");
+ $created_subject = 1;
+ }
+
+ # Deal with header rewriting
+ foreach (@pristine_headers) {
+ # if we're not going to do a rewrite, skip this header!
+ next if (!/^(Subject):/i);
+ my $hdr = ucfirst(lc($1));
+ next if (!defined $self->{conf}->{rewrite_header}->{$hdr});
+
+ if((defined $self->{subjprefix}) and (defined $self->{conf}->{rewrite_header}->{Subject})) {
+ if($self->{subjprefix} ne "") {
+ $ntag = $self->_replace_tags($self->{subjprefix});
+ $ntag =~ s/\n/ /gs;
+ $ntag =~ s/\s+$//;
+
+ local $1;
+ if(defined $ntag) {
+ s/^([^:]+:)[ \t]*(?:\Q${ntag}\E )?/$1 ${ntag} /i;
+ }
+ }
+ }
+ }
+
}
# Break the pristine header set into two blocks; $new_hdrs_pre is the stuff
@@ -2800,6 +2862,9 @@ sub _handle_hit {
$self->_wrap_desc($desc,
3+length($rule)+length($score)+length($area), " " x 28),
($self->{test_log_msgs}->{LONG} || ''));
+ if((defined $self->{subjprefix}) and ($self->{subjprefix} ne "")) {
+ $self->{tag_data}->{SUBJPREFIX} = $self->{subjprefix};
+ }
}
sub _wrap_desc {
@@ -2930,6 +2995,16 @@ sub got_hit {
#$rule_descr = $rule if !defined $rule_descr || $rule_descr eq '';
$rule_descr = "No description available." if !defined $rule_descr || $rule_descr eq '';
+ if(defined $self->{conf}->{rewrite_header}->{Subject}) {
+ my $rule_subjprefix = $conf_ref->{subjprefix}->{$rule};
+ if (defined $rule_subjprefix) {
+ dbg("subjprefix: setting Subject prefix to $rule_subjprefix");
+ if($self->{subjprefix} !~ /\Q$rule_subjprefix\E/) {
+ $self->{subjprefix} .= $rule_subjprefix . " "; # save dynamic subject prefix.
+ }
+ }
+ }
+
$self->_handle_hit($rule,
$score,
$area,