Hi all,

I created a small plugin using the new plugin API in SpamAssassin 3.x. The plugin connects to a local ClamAV server (through TCP) and checks the email for virus. If a virus is found, it returns a positive return code to indicate spam and sets the header "X-Spam-Virus: Yes ($virusname)".

It may seem odd to invoke an antivirus scanner through SpamAssassin, but it works very well for me so far. It saved me from dealing with Amavisd (which was quite painful, in all honesty).

This is my first Perl code ever, so be gentle. ;-) The code is public domain, do whatever you like with it. Note that it requires File::Scan::ClamAV. Tested with SpamAssassin 3.0.1, ClamAV 0.80 and courier 0.44.

Regards,
Troels Walsted Hansen

package ClamAV;
use strict;
use Mail::SpamAssassin;
use Mail::SpamAssassin::Plugin;
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, $permsgstatus, $fulltext) = @_;
  my $av = new File::Scan::ClamAV(port => 3310);
  my ($code, $virus) = $av->streamscan(${$fulltext});
  if(!$code) {
    my $errstr = $av->errstr();
    Mail::SpamAssassin::Plugin::dbg("ClamAV: Error scanning: $errstr");
    $permsgstatus->{main}->{conf}->{headers_spam}->{"Virus"} = "Error 
($errstr)";
  } elsif($code eq 'OK') {
    Mail::SpamAssassin::Plugin::dbg("ClamAV: No virus detected");
    $permsgstatus->{main}->{conf}->{headers_spam}->{"Virus"} = "No";
  } elsif($code eq 'FOUND') {
    Mail::SpamAssassin::Plugin::dbg("ClamAV: Detected virus: $virus");
    $permsgstatus->{main}->{conf}->{headers_spam}->{"Virus"} = "Yes ($virus)";
    return 1;
  } 
  return 0;
}

1;


loadplugin ClamAV clamav.pm
full CLAMAV eval:check_clamav()
describe CLAMAV Clam AntiVirus detected a virus
score CLAMAV 10


Reply via email to