# Copyright (C) 2016 all contributors <meta@public-inbox.org>
# License: AGPL-3.0+ <https://www.gnu.org/licenses/agpl-3.0.txt>
+#
+# ref: https://cr.yp.to/proto/maildir.html
+# http://wiki2.dovecot.org/MailboxFormat/Maildir
package PublicInbox::WatchMaildir;
use strict;
use warnings;
sub new {
my ($class, $config) = @_;
- my (%mdmap, @mdir);
+ my (%mdmap, @mdir, $spamc);
+
+ # XXX is "publicinboxlearn" really a good namespace for this?
my $k = 'publicinboxlearn.watchspam';
if (my $spamdir = $config->{$k}) {
if ($spamdir =~ s/\Amaildir://) {
warn "unsupported $k=$spamdir\n";
}
}
+
+ $k = 'publicinboxwatch.spamcheck';
+ my $spamcheck = $config->{$k};
+ if ($spamcheck) {
+ if ($spamcheck eq 'spamc') {
+ $spamcheck = 'PublicInbox::Spamcheck::Spamc';
+ }
+ if ($spamcheck =~ /::/) {
+ eval "require $spamcheck";
+ $spamcheck = _spamcheck_cb($spamcheck->new);
+ } else {
+ warn "unsupported $k=$spamcheck\n";
+ $spamcheck = undef;
+ }
+ }
foreach $k (keys %$config) {
$k =~ /\Apublicinbox\.([^\.]+)\.watch\z/ or next;
my $name = $1;
my $mdre = join('|', map { quotemeta($_) } @mdir);
$mdre = qr!\A($mdre)/!;
bless {
+ spamcheck => $spamcheck,
mdmap => \%mdmap,
mdir => \@mdir,
mdre => $mdre,
_done_for_now($self);
}
-sub _check_spam {
+sub _remove_spam {
my ($self, $path) = @_;
- $path =~ /:2,[A-R]*S[T-Z]*\z/ or return;
+ $path =~ /:2,[A-R]*S[T-Z]*\z/i or return;
my $mime = _path_to_mime($path) or return;
_force_mid($mime);
foreach my $inbox (values %{$self->{mdmap}}) {
sub _try_path {
my ($self, $path) = @_;
my @p = split(m!/+!, $path);
- return unless $p[-1] =~ /\A[a-zA-Z0-9][\w:,=\.]+\z/;
+ return if $p[-1] !~ /\A[a-zA-Z0-9][\w:,=\.]+\z/;
+ if ($p[-1] =~ /:2,([A-Z]+)\z/i) {
+ my $flags = $1;
+ return if $flags =~ /[DT]/; # no [D]rafts or [T]rashed mail
+ }
return unless -f $path;
if ($path !~ $self->{mdre}) {
warn "unrecognized path: $path\n";
return;
}
if (!ref($inbox) && $inbox eq 'watchspam') {
- return _check_spam($self, $path);
+ return _remove_spam($self, $path);
}
my $im = _importer_for($self, $inbox);
my $mime = _path_to_mime($path) or return;
}
_force_mid($mime);
- $im->add($mime);
+ $im->add($mime, $self->{spamcheck});
}
sub watch {
undef;
}
+sub _spamcheck_cb {
+ my ($sc) = @_;
+ sub {
+ my ($mime) = @_;
+ my $tmp = '';
+ if ($sc->spamcheck($mime, \$tmp)) {
+ return Email::MIME->new(\$tmp);
+ }
+ warn $mime->header('Message-ID')." failed spam check\n";
+ undef;
+ }
+}
+
1;