about summary refs log tree commit homepage
diff options
context:
space:
mode:
-rw-r--r--MANIFEST14
-rw-r--r--lib/PublicInbox/Config.pm10
-rwxr-xr-xpublic-inbox-mda42
-rwxr-xr-xt/fail-bin/spamc3
-rwxr-xr-xt/main-bin/spamc3
-rw-r--r--t/mda.t83
6 files changed, 143 insertions, 12 deletions
diff --git a/MANIFEST b/MANIFEST
index cddd320e..3dba6942 100644
--- a/MANIFEST
+++ b/MANIFEST
@@ -1,9 +1,16 @@
 .gitignore
 COPYING
 Documentation/design_notes.txt
+INSTALL
+MANIFEST
 Makefile.PL
 README
+examples/public-inbox-config
+lib/PublicInbox.pm
+lib/PublicInbox/Config.pm
+lib/PublicInbox/Feed.pm
 lib/PublicInbox/Filter.pm
+lib/PublicInbox/View.pm
 public-inbox-mda
 sa_config/Makefile
 sa_config/README
@@ -12,4 +19,11 @@ sa_config/user/.spamassassin/user_prefs
 scripts/dc-dlvr
 scripts/import_gmane_spool
 scripts/report-spam
+t/config.t
+t/fail-bin/spamc
+t/feed.t
 t/filter.t
+t/main-bin/spamc
+t/mda.t
+t/precheck.t
+t/view.t
diff --git a/lib/PublicInbox/Config.pm b/lib/PublicInbox/Config.pm
index d91c28a9..9ba4ad32 100644
--- a/lib/PublicInbox/Config.pm
+++ b/lib/PublicInbox/Config.pm
@@ -3,12 +3,13 @@
 package PublicInbox::Config;
 use strict;
 use warnings;
+use File::Path::Expand qw/expand_filename/;
 
 # returns key-value pairs of config directives in a hash
 sub new {
         my ($class, $file) = @_;
 
-        local $ENV{GIT_CONFIG} = $file;
+        local $ENV{GIT_CONFIG} = defined $file ? $file : default_file();
 
         my @cfg = `git config -l`;
         $? == 0 or die "git config -l failed: $?\n";
@@ -37,4 +38,11 @@ sub lookup {
         \%rv;
 }
 
+sub default_file {
+        my $f = $ENV{PI_CONFIG};
+        return $f if defined $f;
+        my $pi_dir = $ENV{PI_DIR} || expand_filename('~/.public-inbox/');
+        "$pi_dir/config";
+}
+
 1;
diff --git a/public-inbox-mda b/public-inbox-mda
index 291b5574..8f63fa7e 100755
--- a/public-inbox-mda
+++ b/public-inbox-mda
@@ -3,17 +3,37 @@
 # License: AGPLv3 or later (https://www.gnu.org/licenses/agpl-3.0.txt)
 use strict;
 use warnings;
+my $usage = 'public-inbox-mda < rfc2822_message';
+
 use Email::Filter;
 use Email::Address;
-use PublicInbox::Filter;
+use File::Path::Expand qw/expand_filename/;
 use IPC::Run qw(run);
-my $usage = "public-inbox-mda main_repo fail_repo < rfc2822_message";
-my $filter = Email::Filter->new(emergency => "~/emergency.mbox");
-my $main_repo = shift @ARGV or die "Usage: $usage\n";
-my $fail_repo = shift @ARGV or die "Usage: $usage\n";
+use constant MDA => 'ssoma-mda';
+use PublicInbox;
+use PublicInbox::Filter;
+use PublicInbox::Config;
+
+# n.b: hopefully we can setup the failbox path without bailing due to
+# user error, we really want to setup the emergency destination ASAP
+# in case there's bugs in our code or user error.
+my $failbox = $ENV{PI_FAILBOX} || '~/public-inbox-fail.mbox';
+$failbox = expand_filename($failbox);
+
+# this reads the message from stdin
+my $filter = Email::Filter->new(emergency => $failbox);
+my $config = PublicInbox::Config->new;
+
+my $recipient = $ENV{RECIPIENT};
+defined $recipient or die "RECIPIENT not defined in ENV\n";
+my $dst = $config->lookup($recipient);
+defined $dst or exit(1);
+my $main_repo = $dst->{mainrepo} or exit(1);
+my $fail_repo = $dst->{failrepo} or exit(1);
+my $filtered; # string dest
 
-my $filtered;
-if (PublicInbox->precheck($filter) && do_spamc($filter->simple, \$filtered)) {
+if (PublicInbox->precheck($filter, $recipient) &&
+    do_spamc($filter->simple, \$filtered)) {
         # update our message with SA headers (in case our filter rejects it)
         my $simple = Email::Simple->new($filtered);
         $filtered = undef;
@@ -23,18 +43,18 @@ if (PublicInbox->precheck($filter) && do_spamc($filter->simple, \$filtered)) {
                 # run spamc again on the HTML-free message
                 if (do_spamc($simple, \$filtered)) {
                         $filter->simple(Email::Simple->new($filtered));
-                        $filter->pipe("ssoma-mda", $main_repo);
+                        $filter->pipe(MDA, $main_repo);
                 } else {
-                        $filter->pipe("ssoma-mda", $fail_repo);
+                        $filter->pipe(MDA, $fail_repo);
                 }
         } else {
                 # PublicInbox::Filter nuked everything, oops :x
-                $filter->pipe("ssoma-mda", $fail_repo);
+                $filter->pipe(MDA, $fail_repo);
         }
 } else {
         # if SA thinks it's spam or there's an error:
         # don't bother with our own filtering
-        $filter->pipe("ssoma-mda", $fail_repo);
+        $filter->pipe(MDA, $fail_repo);
 }
 die "Email::Filter failed to exit\n";
 
diff --git a/t/fail-bin/spamc b/t/fail-bin/spamc
new file mode 100755
index 00000000..209e7dc9
--- /dev/null
+++ b/t/fail-bin/spamc
@@ -0,0 +1,3 @@
+#!/bin/sh
+cat
+exit 1
diff --git a/t/main-bin/spamc b/t/main-bin/spamc
new file mode 100755
index 00000000..480d2f8e
--- /dev/null
+++ b/t/main-bin/spamc
@@ -0,0 +1,3 @@
+#!/bin/sh
+# trivial spamc mock
+exec cat
diff --git a/t/mda.t b/t/mda.t
new file mode 100644
index 00000000..9f918d35
--- /dev/null
+++ b/t/mda.t
@@ -0,0 +1,83 @@
+# Copyright (C) 2014, Eric Wong <normalperson@yhbt.net> and all contributors
+# License: AGPLv3 or later (https://www.gnu.org/licenses/agpl-3.0.txt)
+use strict;
+use warnings;
+use Test::More;
+use Email::MIME;
+use File::Temp qw/tempdir/;
+use Cwd;
+use IPC::Run qw(run);
+
+my $mda = "blib/script/public-inbox-mda";
+my $tmpdir = tempdir(CLEANUP => 1);
+my $home = "$tmpdir/pi-home";
+my $pi_home = "$home/.public-inbox";
+my $pi_config = "$pi_home/config";
+my $maindir = "$tmpdir/main.git";
+my $faildir = "$tmpdir/fail.git";
+my $main_bin = getcwd()."/t/main-bin";
+my $main_path = "$main_bin:$ENV{PATH}"; # for spamc ham mock
+my $fail_bin = getcwd()."/t/fail-bin";
+my $fail_path = "$fail_bin:$ENV{PATH}"; # for spamc spam mock
+my $addr = 'test-public@example.com';
+my $cfgpfx = "publicinbox.test";
+
+{
+        ok(-x "$main_bin/spamc",
+                "spamc ham mock found (run in top of source tree");
+        ok(-x "$fail_bin/spamc",
+                "spamc mock found (run in top of source tree");
+        ok(-x $mda, "$mda is executable");
+        is(1, mkdir($home, 0755), "setup ~/ for testing");
+        is(1, mkdir($pi_home, 0755), "setup ~/.public-inbox");
+        is(0, system(qw(git init -q --bare), $maindir), "git init (main)");
+        is(0, system(qw(git init -q --bare), $faildir), "git init (fail)");
+
+        my %cfg = (
+                "$cfgpfx.address" => $addr,
+                "$cfgpfx.mainrepo" => $maindir,
+                "$cfgpfx.failrepo" => $faildir,
+        );
+        while (my ($k,$v) = each %cfg) {
+                is(0, system(qw(git config --file), $pi_config, $k, $v),
+                        "setup $k");
+        }
+}
+
+{
+        my $failbox = "$home/fail.mbox";
+        local $ENV{PI_FAILBOX} = $failbox;
+        local $ENV{HOME} = $home;
+        local $ENV{RECIPIENT} = $addr;
+        my $simple = Email::Simple->new(<<EOF);
+From: Me <me\@example.com>
+To: You <you\@example.com>
+Cc: $addr
+Message-Id: <blah\@example.com>
+Subject: hihi
+Date: Thu, 01 Jan 1970 00:00:00 +0000
+
+EOF
+        my $in = $simple->as_string;
+
+        # ensure successful message delivery
+        {
+                local $ENV{PATH} = $main_path;
+                run([$mda], \$in);
+                local $ENV{GIT_DIR} = $maindir;
+                my $rev = `git rev-list HEAD`;
+                like($rev, qr/\A[a-f0-9]{40}/, "good revision committed");
+        }
+
+        # ensure failures work
+        {
+                local $ENV{PATH} = $fail_path;
+                run([$mda], \$in);
+                local $ENV{GIT_DIR} = $faildir;
+                my $rev = `git rev-list HEAD`;
+                like($rev, qr/\A[a-f0-9]{40}/, "bad revision committed");
+        }
+        ok(!-e $failbox, "nothing in PI_FAILBOX");
+}
+
+done_testing();