aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--README37
-rwxr-xr-xbin/spamcat2
-rw-r--r--config/spamcat.conf1
-rw-r--r--lib/SpamCat.pm38
-rwxr-xr-xt/bin.t4
-rw-r--r--t/conf.t3
-rwxr-xr-xt/delivert25
-rw-r--r--t/fixtures/bar.expected15
-rw-r--r--t/fixtures/sample.conf2
-rw-r--r--t/lib.t50
10 files changed, 78 insertions, 99 deletions
diff --git a/README b/README
index 256e536..f7dc217 100644
--- a/README
+++ b/README
@@ -76,8 +76,9 @@ total messages from this sender, and there are 19 remaining).
* INSTALLATION
1) See INSTALL to install the library and spamcat executable.
2) Once the spamcat executable is installed you'll need to add it to
- your procmail, sieve, or some other similar device that takes an
- email on standard input and expects local delivery.
+ your procmail, sieve, or some other similar device that writes
+ email to standard input and receives the transformed email on
+ standard output.
3) You will also need to create a config file for spamcat (see
config/spamcat.conf for an example) somewhere that can be read by
spamcat.
@@ -89,35 +90,35 @@ total messages from this sender, and there are 19 remaining).
*** main.cf
Postfix needs to know that the spam domain should be handled locally.
-#+BEGIN_COMMENT
-virtual_mailbox_domains = spamcat.domain somewhere.else
-#+END_COMMENT
+#+begin_example
+ Virtual_mailbox_domains = spamcat.domain somewhere.else
+#+end_example
*** virtual aliases table
Make sure postfix can route the spam domain to the user who should
receive it.
-#+BEGIN_COMMENT
-@spamcat.domain hidden-address@somewhere.else
-#+END_COMMENT
+#+begin_example
+ @spamcat.domain hidden-address@somewhere.else
+#+end_example
** Dovecot/Sieve
The sieve file for the user which receives mail for the spam domain
should pipe the email into spamcat, which will handle final delivery
for the spam domain.
-#+BEGIN_COMMENT
-require ["fileinto", "envelope", "vnd.dovecot.pipe"];
+#+begin_example
+ require ["fileinto", "envelope", "vnd.dovecot.filter"];
+
+ if address :contains "to" "@spamcat.domain" {
+ filter "spamcat" ["-c", "/path/to/spamcat.conf"];
+ }
+#+end_example
-if address :contains "to" "@spamcat.domain" {
- pipe :try "spamcat" ["-c", "/path/to/spamcat.conf"];
- fileinto "Junk";
-}
-#+END_COMMENT
** DNS
The MX record for your spam domain should point to the MTA that hosts
spamcat.
-#+BEGIN_COMMENT
-spamcat.domain MX 10 yourmta.domain.
-#+END_COMMENT
+#+begin_example
+ spamcat.domain MX 10 yourmta.domain.
+#+end_example
diff --git a/bin/spamcat b/bin/spamcat
index 9af410d..dbe9ea7 100755
--- a/bin/spamcat
+++ b/bin/spamcat
@@ -108,5 +108,5 @@ if ($#ARGV >= 0) {
pod2usage(1);
}
} else {
- $sch->deliver;
+ $sch->filter;
}
diff --git a/config/spamcat.conf b/config/spamcat.conf
index 1f1313d..5ef87cd 100644
--- a/config/spamcat.conf
+++ b/config/spamcat.conf
@@ -1,4 +1,3 @@
DBPATH=/var/vmail/spork.org/bjc/spamcat.sqlite3
DEFAULT_COUNT=20
-DELIVER=/usr/local/libexec/dovecot/deliver
DOMAINS=bjc.spork.org \ No newline at end of file
diff --git a/lib/SpamCat.pm b/lib/SpamCat.pm
index 4807149..cbae3fd 100644
--- a/lib/SpamCat.pm
+++ b/lib/SpamCat.pm
@@ -23,7 +23,7 @@ sub new {
bless \%conf, $class;
}
-sub deliver {
+sub filter {
my ($self) = @_;
local $/;
@@ -44,26 +44,22 @@ sub deliver {
}
}
- if (defined $count) {
- return if $count == 0;
-
- if ($count > 0) {
- my $count_str = '[' . ($self->{default_count} - $count + 1) . '/' . $self->{default_count} . ']';
- my $new_subject = $email->header('Subject');
- if ($new_subject) {
- $new_subject .= ' - ' . $count_str;
- } else {
- $new_subject = $count_str;
- }
- $email->header_set('Subject' => $new_subject);
- $email->header_set('X-SpamCat-Remaining' => $count);
- }
+ #
+ # Negative counts indicate unlimited delivery.
+ #
+ if (defined $count && $count >= 0) {
+ my $count_str = '[' . ($self->{default_count} - $count + 1) . '/' . $self->{default_count} . ']';
+ my $new_subject = $email->header('Subject');
+ if ($new_subject) {
+ $new_subject .= ' - ' . $count_str;
+ } else {
+ $new_subject = $count_str;
+ }
+ $email->header_set('Subject' => $new_subject);
+ $email->header_set('X-SpamCat-Remaining' => $count);
}
- my $deliverfh = IO::File->new("| " . $self->{deliver}) ||
- die "Couldn't open pipe to " . $self->{deliver} . ": $!\n";
- print $deliverfh $email->as_string;
- $deliverfh->close;
+ print $email->as_string;
}
sub parse_to {
@@ -164,8 +160,10 @@ sub decrement_count_t {
if (!defined $count) {
$count = $self->{default_count};
$q = 'INSERT INTO emails (count, sender) VALUES (?, ?)';
+ } elsif ($count <= 0) {
+ return $count;
} else {
- $count = $count <= 0 ? $count : $count - 1;
+ $count--;
$q = "UPDATE emails SET count = ?, modified = CURRENT_TIMESTAMP WHERE sender = ?";
}
diff --git a/t/bin.t b/t/bin.t
index 2c59e20..2bfb451 100755
--- a/t/bin.t
+++ b/t/bin.t
@@ -22,7 +22,6 @@ BEGIN {
die "Couldn't create $tmpdir/spamcat.conf: $!\n";
print $fh "DBPATH = $tmpdir/spamcat.sqlite3\n";
print $fh "DEFAULT_COUNT = 20\n";
- print $fh "DELIVER = t/delivert $tmpdir\n";
print $fh "DOMAINS = spamcat.example.com\n";
}
@@ -39,8 +38,7 @@ my @dumpconfig = `$spamcat -c $conffile dumpconfig`;
my %got = parse_configdump(@dumpconfig);
my %expected = (DBPATH => '/tmp/spamcat.sqlite3',
DEFAULT_COUNT => 10,
- DELIVER => 't/delivert',
- DOMAINS => "spamcat.example.com, spamcat2.example.com, spamcat3");
+ DOMAINS => "spamcat.example.com, spamcat2.example.com, spamcat3");
is_deeply(\%got, \%expected);
# Unknown senders have the default number of mails left.
diff --git a/t/conf.t b/t/conf.t
index dbe2217..02a3095 100644
--- a/t/conf.t
+++ b/t/conf.t
@@ -1,6 +1,6 @@
# -*- mode: cperl -*-
-use Test::More tests => 7;
+use Test::More tests => 6;
use strict;
use warnings;
@@ -13,6 +13,5 @@ ok(%conf);
is($conf{dbpath}, '/tmp/spamcat.sqlite3');
is($conf{default_count}, 10);
-is($conf{deliver}, 't/delivert');
is_deeply($conf{domains},
['spamcat.example.com', 'spamcat2.example.com', 'spamcat3']);
diff --git a/t/delivert b/t/delivert
deleted file mode 100755
index 794e0a1..0000000
--- a/t/delivert
+++ /dev/null
@@ -1,25 +0,0 @@
-#!/usr/bin/env perl
-
-use Email::Simple;
-use IO::File;
-
-use strict;
-use warnings;
-
-die usage() unless $#ARGV == 0;
-my $path = shift;
-
-local $/;
-my $email = Email::Simple->new(<>);
-
-my $msgid = $email->header('Message-ID');
-$msgid =~ s/<(.*)@.*>/$1/;
-
-my $fh = IO::File->new(">$path/$msgid") ||
- die "Couldn't write to $path/$msgid: $!\n";
-print $fh $email->as_string;
-$fh->close;
-
-sub usage {
- "Usage: $0 path\n";
-}
diff --git a/t/fixtures/bar.expected b/t/fixtures/bar.expected
new file mode 100644
index 0000000..e554c65
--- /dev/null
+++ b/t/fixtures/bar.expected
@@ -0,0 +1,15 @@
+Return-Path: <test@mta.example.com>
+Delivered-To: spamcat@example.com
+Received: from mta.example.com
+ by mta.example.com (Dovecot) with LMTP id 9DDcI25oblTvgAEAQc1eRg
+ for <spamcat@example.com>; Thu, 20 Nov 2014 17:17:18 -0500
+Received: by mta.example.com (Postfix, from userid 1001)
+ id 844956F1EE; Thu, 20 Nov 2014 17:17:18 -0500 (EST)
+To: bar@spamcat.example.com
+Subject: test - [21/20]
+Message-Id: <bar@mta.example.com>
+Date: Thu, 20 Nov 2014 17:17:18 -0500 (EST)
+From: sender@example.com (Spamcat Sender)
+X-SpamCat-Remaining: 0
+
+Sample email.
diff --git a/t/fixtures/sample.conf b/t/fixtures/sample.conf
index e0d644b..ba3054d 100644
--- a/t/fixtures/sample.conf
+++ b/t/fixtures/sample.conf
@@ -2,5 +2,5 @@
DBPATH=/tmp/spamcat.sqlite3 # So should most whitespace and inline comments.
DEFAULT_COUNT =10 # Make sure key=val doesn't work in comments
-DELIVER= t/delivert # by saying DEFAULT_COUNT=8
+ # by saying DEFAULT_COUNT=8
DOMAINS = spamcat.example.com, spamcat2.example.com spamcat3
diff --git a/t/lib.t b/t/lib.t
index 8afc46e..41b5704 100644
--- a/t/lib.t
+++ b/t/lib.t
@@ -1,6 +1,6 @@
# -*- Mode: cperl -*-
-use Test::More tests => 46;
+use Test::More tests => 40;
use strict;
use warnings;
@@ -10,8 +10,7 @@ BEGIN {
$tmpdir = "/tmp/spamcat.t.$$";
%conf = (dbpath => "$tmpdir/spamcat.sqlite3",
default_count => 20,
- deliver => "t/delivert $tmpdir",
- domains => ['spamcat.example.com', 'spamcat2.example.com']);
+ domains => ['spamcat.example.com', 'spamcat2.example.com']);
system("rm -rf $tmpdir") == 0
or die "Couldn't remove $tmpdir: $!\n";
@@ -58,13 +57,13 @@ is($addrs[0], 'baz@pham.com');
is($addrs[0], 'baz@pham.com');
is($addrs[1], 'one@two.com');
-ok(SpamCat->can('deliver'), 'Has delivery method');
-test_file('foo', 1);
-test_file('foo2', 1);
-test_file('multiple', 1);
-test_file('wrongdomain', 1);
-test_file('nosubj', 1);
-test_file('bar', 0);
+ok(SpamCat->can('filter'), 'Has filter method');
+test_file('foo');
+test_file('foo2');
+test_file('multiple');
+test_file('wrongdomain');
+test_file('nosubj');
+test_file('bar');
$sch->set_count('always-allowed', -1);
test_file('always-allowed', 1);
@@ -85,31 +84,26 @@ is($rows[4]->{sender}, 'nosubj');
is($rows[4]->{count}, 20);
sub test_file {
- my ($filen, $should_exist) = @_;
+ my ($filen) = @_;
my $input = IO::File->new("<t/fixtures/$filen") ||
die "Couldn't open $filen: $!\n";
my $inputfd = fileno($input);
open STDIN, ">&$inputfd" || die "Couldn't open $inputfd: $!\n";
+ open STDOUT, ">$tmpdir/$filen" || die "Couldn't open $tmpdir/$filen: $!\n";
- $sch->deliver();
+ $sch->filter();
- if ($should_exist) {
- ok(-f "$tmpdir/$filen") || diag("$tmpdir/$filen doesn't exist.");
+ local $/;
+ my $fh = IO::File->new("<$tmpdir/$filen") ||
+ die "Couldn't open $tmpdir/$filen for reading: $!\n";
+ my $got = <$fh>;
+ $fh->close;
- local $/;
- my $fh = IO::File->new("<$tmpdir/$filen") ||
- die "Couldn't open $tmpdir/$filen for reading: $!\n";
- my $got = <$fh>;
- $fh->close;
+ $fh = IO::File->new("<t/fixtures/$filen.expected") ||
+ die "Couldn't open t/fixtures/$filen.expected for reading: $!\n";
+ my $expected = <$fh>;
+ $fh->close;
- $fh = IO::File->new("<t/fixtures/$filen.expected") ||
- die "Couldn't open t/fixtures/$filen.expected for reading: $!\n";
- my $expected = <$fh>;
- $fh->close;
-
- is($got, $expected) || diag("Test for $filen output failed.");
- } else {
- ok(! -f "$tmpdir/$filen") || diag("$tmpdir/$filen exists.");
- }
+ is($got, $expected) || diag("Test for $filen output failed.");
}