Bladeren bron

Added methods to read the configuration file as specified in INSTALL. Output any configuration error using dbg() in Mail::SpamAssassin::Logger.



git-svn-id: https://svn.microneil.com/svn/PKG-SNF-CS-NIX/trunk@6 233e721a-07f6-49eb-a7da-05e0e16828fc
master
adeniz 15 jaren geleden
bovenliggende
commit
e971f5dd8e
1 gewijzigde bestanden met toevoegingen van 379 en 4 verwijderingen
  1. 379
    4
      SNF_CS_Developer_Package.3.0.2_p4/SNF4SA/snf4sa.pm

+ 379
- 4
SNF_CS_Developer_Package.3.0.2_p4/SNF4SA/snf4sa.pm Bestand weergeven

@@ -19,6 +19,7 @@ use strict;
use Mail::SpamAssassin;
use Mail::SpamAssassin::Plugin;
use Mail::SpamAssassin::PerMsgStatus;
use Mail::SpamAssassin::Logger;
use IO::Socket;
use IO::File;
@@ -27,7 +28,6 @@ our @ISA = qw(Mail::SpamAssassin::Plugin);
# Convenience variables and pseudo-constants
my $CRLF = "\x0d\x0a";
my $DefaultMaxTempFileSize = 64 * 1024;
# translation table for SNF rule codes
my $rule_code_xlat = {
@@ -75,11 +75,309 @@ sub new {
$self->{Temp_Dir} = '/tmp/snf4sa';
# Maximum email message size (including headers).
$self->{SNF_MaxTempFileSize} = $DefaultMaxTempFileSize;
$self->{SNF_MaxTempFileSize} = 64 * 1024;
# Key for GBUdb maximum weight.
$self->{GBUdb_MaxWeightKey} = "gbudb_max_weight";
# Key for SNFServer code in configuration file.
$self->{SNF_CodeKey} = "snf_result";
# Key for SA score increment in configuration file.
$self->{SA_DeltaScoreKey} = "sa_score";
# Key for short circuit in configuration file.
$self->{SA_ShortCircuitYesKey} = "short_circuit_yes";
# Key for no short circuit in configuration file.
$self->{SA_ShortCircuitNoKey} = "short_circuit_no";
return $self;
}
# DEBUG/TEST.
#sub extract_metadata {
#
# my ($self, $opts) = @_;
#
# print "***********************\n";
# print "extract_metadata called\n";
# print "***********************\n";
#
# $opts->{msg}->put_metadata("X-Extract-Metadata:", "Test header");
#
#}
# END OF DEBUG/TEST.
sub have_shortcircuited {
my ($self, $permsgstatus) = @_;
# print "************************************\n";
# print "****have_shortcircuited returning 0\n";
# print "************************************\n";
return 0;
}
sub parse_config {
my ($self, $options) = @_;
# DEBUG.
#print "parse_confg. key: $options->{key}\n";
#print "parse_config. line: $options->{line}\n";
#print "parse_config. value: $options->{value}\n";
#END OF DEBUG.
# Process GBUdb_max_weight.
if (lc($options->{key}) eq $self->{GBUdb_MaxWeightKey}) {
# GBUdb maximum weight.
my $tempValue = $options->{value};
# Test that the value was a number.
#$self->log_debug("Found $self->{GBUdb_MaxWeightKey} . " value: $options->{value}, tempValue: $tempValue\n"; # DEBUG.
if ($tempValue =~ /^([+-]?)(?=\d|\.\d)\d*(\.\d*)?([Ee]([+-]?\d+))?$/) {
# Value was a number. Load and return success.
$options->{conf}->{gbuDbMaxWeight} = $tempValue;
$self->inhibit_further_callbacks();
return 1;
} else {
$self->log_debug("Invalid value for $self->{GBUdb_MaxWeightKey} " .
$tempValue);
}
} elsif (lc($options->{key}) eq $self->{SNF_CodeKey}) {
# Relationship between SNFServer code and SA score delta.
my $snf = $self->parse_snf_sa_mapping($options);
if (defined($snf)) {
my @codes = @{$snf->{snfCode}};
print "snf->{snfCode}: @codes\n";
print "snf->{deltaScore}: $snf->{deltaScore}\n";
print "snf->{shortCircuit}: $snf->{shortCircuit}\n";
# Save configuration.
# Successfully parsed.
return 1;
}
}
# Wasn't handled.
return 0;
}
# Parse a snf_result configuration line.
#
# Input--
#
# $line--String containing the snf_result line without the first word.
#
# Returns has reference with the following fields (if no error)--
#
# snfCode--Array of SNFServer result codes that this configuration
# line specifies.
#
# deltaScore--SA score increment for the codes in @snfCode.
#
# shortCircuit--True if a SNFServer code in @snfCode is to
# short-circuit the message scan, false otherwise.
#
# If the line cannot be parsed, the return value is undef.
#
sub parse_snf_sa_mapping
{
my ($self, $options) = @_;
my $value = $options->{value};
my $ret_hash = {
snfCode => undef,
deltaScore => undef,
shortCircuit => undef
};
# SNFServer codes found.
my @snfCode = ();
# Remove leading and trailing whitespace.
$value =~ s/^\s+//;
$value =~ s/\s+$//;
# Convert to lower case.
$value = lc($value);
# Split up by white space.
my @specVal = split(/\s+/, $value);
if (0 == @specVal) {
# No separate words.
$self->log_debug("No separate words found in configuration line '" .
$options->{line} . "'");
return undef;
}
# Convert each SNFServer result specification into an integer.
my $lastSpec;
for ($lastSpec = 0; $lastSpec < @specVal; $lastSpec++) {
# Check for next keyword.
if ($specVal[$lastSpec] eq $self->{SA_DeltaScoreKey}) {
# We've completed the processing of the SNFServer result
# codes.
last;
}
# Get the code values.
my @codeVal = $self->get_code_values($specVal[$lastSpec]);
if (0 == @codeVal) {
# No code values were obtained.
$self->log_debug("Couldn't parse all the SNFServer code values " .
"in configuration line '" .
$options->{line} . "'");
return undef;
}
# Add to the list of codes.
@snfCode = (@snfCode, @codeVal);
}
# Sort the SNFServer result codes and remove duplicates.
@snfCode = sort { $a <=> $b } @snfCode;
my $prev = -1;
my @temp = grep($_ != $prev && ($prev = $_), @snfCode);
$ret_hash->{snfCode} = \@temp;
# The $specVal[$lastSpec] is $self->{SA_DeltaScoreKey}. Return if
# there aren't enough parameters.
$lastSpec++;
if ($lastSpec >= @specVal) {
# Not enough parameters.
$self->log_debug("Not enough parameters in configuration line '" .
$options->{line} . "'");
return undef;
}
# Extract the SA delta score.
$ret_hash->{deltaScore} = $specVal[$lastSpec];
if (!($ret_hash->{deltaScore} =~
/^([+-]?)(?=\d|\.\d)\d*(\.\d*)?([Ee]([+-]?\d+))?$/)) {
# SA delta score isn't a number.
$self->log_debug("Value after '" . $self->{SA_DeltaScoreKey} .
"' ($specVal[$lastSpec]) must be a number " .
"in configuration line '" .
$options->{line} . "'");
return undef;
}
# Get short circuit spec.
$lastSpec++;
$ret_hash->{shortCircuit} = 0;
if ( ($lastSpec + 1) == @specVal) {
# A parameter was specified.
my $shortCircuitSpec = $specVal[$lastSpec];
if ($self->{SA_ShortCircuitYesKey} eq $shortCircuitSpec) {
# Specified short-circuit evaluation.
$ret_hash->{shortCircuit} = 1;
} elsif ($self->{SA_ShortCircuitNoKey} ne $shortCircuitSpec) {
# Invalid short-circuit specification.
$self->log_debug("Invalid short-circuit specification: '" .
$specVal[$lastSpec] .
"' in configuration line '" . $options->{line} .
"'. Must be '$self->{SA_ShortCircuitYesKey}' " .
" or '$self->{SA_ShortCircuitNoKey}'.");
return undef;
}
} elsif ($lastSpec != @specVal) {
# Too many parameters were specified.
$self->log_debug("Too many parameters were specified in " .
"configuration line '" . $options->{line} . "'");
return undef;
}
return $ret_hash;
}
sub get_code_values
{
my ($self, $specElement) = @_;
my @snfCode = ();
# Split the specification.
my @codeVal = split(/-/, $specElement);
#$self->log_debug("snf4sa: get_code_values. specElement: $specElement. codeVal: @codeVal"); # DEBUG
if (1 == @codeVal) {
if ($specElement =~ /^\d+$/) {
# Found a single code.
$snfCode[0] = 1 * $specElement;
}
} elsif (2 == @codeVal) {
# Check range.
if ( ($codeVal[0] =~ /^\d+$/) && ($codeVal[1] =~ /^\d+$/) ) {
# Found a range of codes.
$codeVal[0] = 1 * $codeVal[0];
$codeVal[1] = 1 * $codeVal[1];
if ($codeVal[0] <= $codeVal[1]) {
# Add these SNF codes.
for (my $i = $codeVal[0]; $i <= $codeVal[1]; $i++) {
push(@snfCode, $i);
}
}
}
}
return @snfCode;
}
# Output a debug message.
#
# Input--
#
# $message--String containing the message to output.
#
sub log_debug
{
my ($self, $message) = @_;
dbg("snf4sa: $message");
}
# Check the message with SNFServer.
sub snf4sa_sacheck {
my ($self, $permsgstatus, $fulltext) = @_;
@@ -121,6 +419,24 @@ sub snf4sa_sacheck {
# xci_scan connects to SNFServer with XCI to scan the message
my $SNF_XCI_Return = $self->xci_scan( $filename );
#print "header:\n\n$SNF_XCI_Return->{header}"; # DEBUG
#print "\nEnd of header\n\n"; # DEBUG
# Initialize the change in the SA score.
my $deltaScore = 0.0;
# Perform GBUdb processing.
if (defined($permsgstatus->{main}->{conf}->{gbuDbMaxWeight})) {
#print "gbudbMaxWeight: $permsgstatus->{main}->{conf}->{gbuDbMaxWeight}\n\n"; # DEBUG.
# Calculate the contribution to the scrore from the GBUdb results.
$deltaScore +=
$self->calc_GBUdb($SNF_XCI_Return->{header},
$permsgstatus->{main}->{conf}->{gbuDbMaxWeight});
}
# Remove the temp file, we are done with it.
unlink($filename);
@@ -154,9 +470,68 @@ sub snf4sa_sacheck {
# Add the header.
$permsgstatus->set_tag("SNFRESULTTAG", "$rc ($rcx)");
#all SA cares about is whether a 0 or 1 comes back. 0 = good 1=spam.
return $testscore;
# Submit the score.
if ($deltaScore) {
$permsgstatus->got_hit("SNF4SA", "", score => $deltaScore);
for my $set (0..3) {
$permsgstatus->{scoreset}->[$set]->{"SNF4SA"} =
sprintf("%0.3f", $deltaScore);
}
}
# Always return zero, since the score was submitted via got_hit()
# above.
return 0;
}
sub calc_GBUdb
{
my ( $self, $headers, $weight ) = @_;
# Split the header into lines.
my @headerLine = split(/\n/, $headers);
# Find the line containing the GBUdb results.
my $line;
foreach $line (@headerLine) {
# Search for the tag.
if ($line =~ /^X-GBUdb-Analysis:/) {
# GBUdb analysis was done. Extract the values.
my $ind0 = index($line, "c=");
my $ind1 = index($line, " ", $ind0 + 2);
if (-1 == $ind0) {
return 0.0;
}
my $c = 1.0 * substr($line, $ind0 + 2, $ind1 - $ind0 - 2);
print "calc_GBUdb. line: $line\n"; # DEBUG
print "calc_GBUdb. c: $c, ind0: $ind0, ind1: $ind1\n"; # DEBUG
$ind0 = index($line, "p=");
$ind1 = index($line, " ", $ind0 + 2);
if (-1 == $ind0) {
return 0.0;
}
my $p = 1.0 * substr($line, $ind0 + 2, $ind1 - $ind0 - 2);
print "calc_GBUdb. p: $p, ind0: $ind0, ind1: $ind1\n"; # DEBUG
# Calculate and return the score.
my $score = ($p * $c);
$score *= $score * $weight;
if ($p < 0.0) {
$score *= -1.0;
}
print "calc_GBUdb. score: $score\n"; # DEBUG
return $score;
}
}
}
sub abort

Laden…
Annuleren
Opslaan