54 lines
1.5 KiB
Plaintext
54 lines
1.5 KiB
Plaintext
|
package ClamAV;
|
||
|
use strict;
|
||
|
|
||
|
# version 2.0, 2010-01-07
|
||
|
# - use SA public interface set_tag() and add_header, instead of
|
||
|
# pushing a header field directly into $conf->{headers_spam}
|
||
|
|
||
|
# our $CLAMD_SOCK = 3310; # for TCP-based usage
|
||
|
our $CLAMD_SOCK = "{{ clamav_clamd_spamassassin_local_socket }}";
|
||
|
|
||
|
use Mail::SpamAssassin;
|
||
|
use Mail::SpamAssassin::Plugin;
|
||
|
use Mail::SpamAssassin::Logger;
|
||
|
use File::Scan::ClamAV;
|
||
|
our @ISA = qw(Mail::SpamAssassin::Plugin);
|
||
|
|
||
|
sub new {
|
||
|
my ($class, $mailsa) = @_;
|
||
|
$class = ref($class) || $class;
|
||
|
my $self = $class->SUPER::new($mailsa);
|
||
|
bless($self, $class);
|
||
|
$self->register_eval_rule("check_clamav");
|
||
|
return $self;
|
||
|
}
|
||
|
|
||
|
sub check_clamav {
|
||
|
my($self, $pms, $fulltext) = @_;
|
||
|
dbg("ClamAV: invoking File::Scan::ClamAV, port/socket: %s", $CLAMD_SOCK);
|
||
|
my $clamav = new File::Scan::ClamAV(port => $CLAMD_SOCK);
|
||
|
my($code, $virus) = $clamav->streamscan(${$fulltext});
|
||
|
my $isspam = 0;
|
||
|
my $header = "";
|
||
|
if (!$code) {
|
||
|
my $errstr = $clamav->errstr();
|
||
|
$header = "Error ($errstr)";
|
||
|
} elsif ($code eq 'OK') {
|
||
|
$header = "No";
|
||
|
} elsif ($code eq 'FOUND') {
|
||
|
$header = "Yes ($virus)";
|
||
|
$isspam = 1;
|
||
|
# include the virus name in SpamAssassin's report
|
||
|
$pms->test_log($virus);
|
||
|
} else {
|
||
|
$header = "Error (Unknown return code from ClamAV: $code)";
|
||
|
}
|
||
|
dbg("ClamAV: result - $header");
|
||
|
$pms->set_tag('CLAMAVRESULT', $header);
|
||
|
# add a metadatum so that rules can match against the result too
|
||
|
$pms->{msg}->put_metadata('X-Spam-Virus',$header);
|
||
|
return $isspam;
|
||
|
}
|
||
|
|
||
|
1;
|