diff options
author | Eric Wong <e@80x24.org> | 2016-06-24 01:15:13 +0000 |
---|---|---|
committer | Eric Wong <e@80x24.org> | 2016-06-24 02:00:26 +0000 |
commit | c515264dd69156fc89c59685f788b1093afb8731 (patch) | |
tree | ada1a21aa82b369dbe1ac8c865474a9318228f7d /lib/PublicInbox/Spamcheck | |
parent | 3c24b7e7e47be9646226d921897cc9ec92e9be8a (diff) | |
download | public-inbox-c515264dd69156fc89c59685f788b1093afb8731.tar.gz |
This should hopefully make it easier to try other anti-spam systems (or none at all) in the future.
Diffstat (limited to 'lib/PublicInbox/Spamcheck')
-rw-r--r-- | lib/PublicInbox/Spamcheck/Spamc.pm | 94 |
1 files changed, 94 insertions, 0 deletions
diff --git a/lib/PublicInbox/Spamcheck/Spamc.pm b/lib/PublicInbox/Spamcheck/Spamc.pm new file mode 100644 index 00000000..312e52df --- /dev/null +++ b/lib/PublicInbox/Spamcheck/Spamc.pm @@ -0,0 +1,94 @@ +# Copyright (C) 2016 all contributors <meta@public-inbox.org> +# License: AGPL-3.0+ <https://www.gnu.org/licenses/agpl-3.0.txt> +package PublicInbox::Spamcheck::Spamc; +use strict; +use warnings; +use PublicInbox::Spawn qw(popen_rd spawn); +use IO::File; +use Fcntl qw(:DEFAULT SEEK_SET); + +sub new { + my ($class) = @_; + bless { + checkcmd => [qw(spamc -E --headers)], + hamcmd => [qw(spamc -L ham)], + spamcmd => [qw(spamc -L spam)], + }, $class; +} + +sub spamcheck { + my ($self, $msg, $out) = @_; + + my $tmp; + my $fd = _msg_to_fd($self, $msg, \$tmp); + my $rdr = { 0 => $fd }; + my ($fh, $pid) = popen_rd($self->{checkcmd}, undef, $rdr); + defined $pid or die "failed to popen_rd spamc: $!\n"; + my $r; + unless (ref $out) { + my $buf = ''; + $out = \$buf; + } + do { + $r = sysread($fh, $$out, 65536, length($$out)); + } while (defined($r) && $r != 0); + defined $r or die "read failed: $!"; + close $fh or die "close failed: $!"; + waitpid($pid, 0); + ($? || $$out eq '') ? 0 : 1; +} + +sub hamlearn { + my ($self, $msg, $rdr) = @_; + _learn($self, $msg, $rdr, 'hamcmd'); +} + +sub spamlearn { + my ($self, $msg, $rdr) = @_; + _learn($self, $msg, $rdr, 'spamcmd'); +} + +sub _learn { + my ($self, $msg, $rdr, $field) = @_; + $rdr ||= {}; + $rdr->{1} ||= $self->_devnull; + $rdr->{2} ||= $self->_devnull; + my $tmp; + $rdr->{0} = _msg_to_fd($self, $msg, \$tmp); + my $pid = spawn($self->{$field}, undef, $rdr); + waitpid($pid, 0); + !$?; +} + +sub _devnull { + my ($self) = @_; + my $fd = $self->{-devnullfd}; + return $fd if defined $fd; + open my $fh, '+>', '/dev/null' or + die "failed to open /dev/null: $!"; + $self->{-devnull} = $fh; + $self->{-devnullfd} = fileno($fh); +} + +sub _msg_to_fd { + my ($self, $msg, $tmpref) = @_; + my $tmpfh; + my $fd; + if (my $ref = ref($msg)) { + + return $msg->fileno if $ref ne 'SCALAR' && $msg->can('fileno'); + + $tmpfh = IO::File->new_tmpfile; + $tmpfh->autoflush(1); + $msg = \($msg->as_string) if $ref ne 'SCALAR'; + print $tmpfh $$msg or die "failed to print: $!"; + sysseek($tmpfh, 0, SEEK_SET) or + die "sysseek(fh) failed: $!"; + $$tmpref = $tmpfh; + + return fileno($tmpfh); + } + $msg; +} + +1; |