user/dev discussion of public-inbox itself
 help / color / mirror / code / Atom feed
From: Eric Wong <e@80x24.org>
To: meta@public-inbox.org
Cc: "Eric W. Biederman" <ebiederm@xmission.com>
Subject: [PATCH 6/7] mda, watch: wire up List-ID header support
Date: Tue, 15 Oct 2019 20:36:32 +0000	[thread overview]
Message-ID: <20191015203633.17665-7-e@80x24.org> (raw)
In-Reply-To: <20191015203633.17665-1-e@80x24.org>

This also adds watchheader tests for -watch, which we never
had before :x
---
 Documentation/public-inbox-config.pod | 18 ++++++++++++++++
 Documentation/public-inbox-mda.pod    |  3 +++
 lib/PublicInbox/WatchMaildir.pm       | 31 +++++++++++++++++++++------
 script/public-inbox-mda               | 17 ++++++++++++---
 t/mda.t                               | 28 ++++++++++++++++++++++++
 t/watch_maildir_v2.t                  | 31 +++++++++++++++++++++++++++
 6 files changed, 118 insertions(+), 10 deletions(-)

diff --git a/Documentation/public-inbox-config.pod b/Documentation/public-inbox-config.pod
index 8d545f7a..6a9739f7 100644
--- a/Documentation/public-inbox-config.pod
+++ b/Documentation/public-inbox-config.pod
@@ -85,6 +85,24 @@ the given header.  Multiple values are not currently supported.
 
 Default: none; only for L<public-inbox-watch(1)> users
 
+=item publicinbox.<name>.listid
+
+The L<rfc2919|https://tools.ietf.org/html/rfc2919> header without
+angle brackets for L<public-inbox-mda(1)> deliveries and
+L<public-inbox-watch(1)>.
+
+For public-inbox-watch users, this is a shortcut for specifying
+C<publicinbox.$NAME.watchheader=List-Id:<foo.example.com>>
+
+For public-inbox-mda users, this may be used to avoid recipient
+matching via C<ORIGINAL_RECIPIENT> environment variable.
+
+This may be specified multiple times for merging multiple mailing
+lists into a single public-inbox, only one C<List-Id> header
+needs to match.
+
+Default: none
+
 =item publicinbox.<name>.nntpmirror
 
 This may be the full NNTP URL of an independently-run mirror.
diff --git a/Documentation/public-inbox-mda.pod b/Documentation/public-inbox-mda.pod
index 64ec690c..921b7a15 100644
--- a/Documentation/public-inbox-mda.pod
+++ b/Documentation/public-inbox-mda.pod
@@ -25,6 +25,9 @@ L<public-inbox-config(5)/publicinboxmda.spamcheck>
 The original recipient email address, set by the MTA.  Postfix
 sets it by default, untested on other MTAs.
 
+This does not have to be set if relying on C<publicinbox.$NAME.listid>
+directives configured in L<public-inbox-config(5)>.
+
 =item PI_CONFIG
 
 Per-user config file parseable by L<git-config(1)>.
diff --git a/lib/PublicInbox/WatchMaildir.pm b/lib/PublicInbox/WatchMaildir.pm
index f63140c8..08b1aab4 100644
--- a/lib/PublicInbox/WatchMaildir.pm
+++ b/lib/PublicInbox/WatchMaildir.pm
@@ -59,9 +59,19 @@ sub new {
 
 		my $watch = $ibx->{watch} or return;
 		if (is_maildir($watch)) {
-			if (my $wm = $ibx->{watchheader}) {
-				my ($k, $v) = split(/:/, $wm, 2);
-				$ibx->{-watchheader} = [ $k, qr/\Q$v\E/ ];
+			my $watch_hdrs = [];
+			if (my $wh = $ibx->{watchheader}) {
+				my ($k, $v) = split(/:/, $wh, 2);
+				push @$watch_hdrs, [ $k, qr/\Q$v\E/ ];
+			}
+			if (my $list_ids = $ibx->{listid}) {
+				for (@$list_ids) {
+					my $re = qr/<[ \t]*\Q$_\E[ \t]*>/;
+					push @$watch_hdrs, ['List-Id', $re ];
+				}
+			}
+			if (scalar @$watch_hdrs) {
+				$ibx->{-watchheaders} = $watch_hdrs;
 			}
 			my $new = "$watch/new";
 			my $cur = "$watch/cur";
@@ -159,10 +169,17 @@ sub _try_path {
 		my $mime = _path_to_mime($path) or next;
 		my $im = _importer_for($self, $ibx);
 
-		my $wm = $ibx->{-watchheader};
-		if ($wm) {
-			my $v = $mime->header_obj->header_raw($wm->[0]);
-			next unless ($v && $v =~ $wm->[1]);
+		# any header match means it's eligible for the inbox:
+		if (my $watch_hdrs = $ibx->{-watchheaders}) {
+			my $ok;
+			my $hdr = $mime->header_obj;
+			for my $wh (@$watch_hdrs) {
+				my $v = $hdr->header_raw($wh->[0]);
+				next unless defined($v) && $v =~ $wh->[1];
+				$ok = 1;
+				last;
+			}
+			next unless $ok;
 		}
 
 		if (my $scrub = $ibx->filter($im)) {
diff --git a/script/public-inbox-mda b/script/public-inbox-mda
index 4e6e04e2..2655a6c5 100755
--- a/script/public-inbox-mda
+++ b/script/public-inbox-mda
@@ -36,10 +36,21 @@ my $config = PublicInbox::Config->new;
 my $key = 'publicinboxmda.spamcheck';
 my $default = 'PublicInbox::Spamcheck::Spamc';
 my $spamc = PublicInbox::Spamcheck::get($config, $key, $default);
+my $dst;
 my $recipient = $ENV{ORIGINAL_RECIPIENT};
-defined $recipient or die "ORIGINAL_RECIPIENT not defined in ENV\n";
-my $dst = $config->lookup($recipient); # first check
-defined $dst or do_exit(67); # EX_NOUSER 5.1.1 user unknown
+if (defined $recipient) {
+	$dst = $config->lookup($recipient); # first check
+}
+if (!defined $dst) {
+	my $list_id = $simple->header('List-Id');
+	if (defined $list_id && $list_id =~ /<[ \t]*(.+)?[ \t]*>/) {
+		$dst = $config->lookup_list_id($1);
+	}
+	if (!defined $dst && !defined $recipient) {
+		die "ORIGINAL_RECIPIENT not defined in ENV\n";
+	}
+	defined $dst or do_exit(67); # EX_NOUSER 5.1.1 user unknown
+}
 $dst->{mainrepo} or do_exit(67);
 $dst = PublicInbox::InboxWritable->new($dst);
 
diff --git a/t/mda.t b/t/mda.t
index 5621b7d6..3cab590b 100644
--- a/t/mda.t
+++ b/t/mda.t
@@ -267,6 +267,34 @@ EOF
 	}
 }
 
+# List-ID based delivery
+{
+	local $ENV{PI_EMERGENCY} = $faildir;
+	local $ENV{HOME} = $home;
+	local $ENV{ORIGINAL_RECIPIENT} = undef;
+	local $ENV{PATH} = $main_path;
+	my $list_id = 'foo.example.com';
+	my $mid = 'list-id-delivery@example.com';
+	my $simple = Email::Simple->new(<<EOF);
+From: user <user\@example.com>
+To: You <you\@example.com>
+Cc: $addr
+Message-ID: <$mid>
+List-Id: <$list_id>
+Subject: this message will be trained as spam
+Date: Thu, 01 Jan 1970 00:00:00 +0000
+
+EOF
+	system(qw(git config --file), $pi_config, "$cfgpfx.listid", $list_id);
+	$? == 0 or die "failed to set listid $?";
+	my $in = $simple->as_string;
+	IPC::Run::run([$mda], \$in);
+	is($?, 0, 'mda OK with List-Id match');
+	my $path = mid2path($mid);
+	my $msg = `git --git-dir=$maindir cat-file blob HEAD:$path`;
+	like($msg, qr/\Q$list_id\E/, 'delivered message w/ List-ID matches');
+}
+
 done_testing();
 
 sub fail_bad_header {
diff --git a/t/watch_maildir_v2.t b/t/watch_maildir_v2.t
index 0a5a8017..99551ceb 100644
--- a/t/watch_maildir_v2.t
+++ b/t/watch_maildir_v2.t
@@ -171,4 +171,35 @@ EOF
 	is($both, $$msg, 'got original message back from v2');
 }
 
+{
+	my $want = <<'EOF';
+From: <u@example.com>
+List-Id: <i.want.you.to.want.me>
+Message-ID: <do.want@example.com>
+EOF
+	my $do_not_want = <<'EOF';
+From: <u@example.com>
+List-Id: <do.not.want>
+X-Mailing-List: no@example.com
+Message-ID: <do.not.want@example.com>
+EOF
+	my $cfg = $orig."$cfgpfx.listid=i.want.you.to.want.me\n";
+	PublicInbox::Emergency->new($maildir)->prepare(\$want);
+	PublicInbox::Emergency->new($maildir)->prepare(\$do_not_want);
+	my $config = PublicInbox::Config->new(\$cfg);
+	PublicInbox::WatchMaildir->new($config)->scan('full');
+	$ibx = $config->lookup_name('test');
+	my $num = $ibx->mm->num_for('do.want@example.com');
+	ok(defined $num, 'List-ID matched for watch');
+	$num = $ibx->mm->num_for('do.not.want@example.com');
+	is($num, undef, 'unaccepted List-ID matched for watch');
+
+	$cfg = $orig."$cfgpfx.watchheader=X-Mailing-List:no\@example.com\n";
+	$config = PublicInbox::Config->new(\$cfg);
+	PublicInbox::WatchMaildir->new($config)->scan('full');
+	$ibx = $config->lookup_name('test');
+	$num = $ibx->mm->num_for('do.not.want@example.com');
+	ok(defined $num, 'X-Mailing-List matched');
+}
+
 done_testing;

  parent reply	other threads:[~2019-10-15 20:36 UTC|newest]

Thread overview: 8+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2019-10-15 20:36 [PATCH 0/7] List-ID support in mda, watch, www Eric Wong
2019-10-15 20:36 ` [PATCH 1/7] Config.pm: Add support for mailing list information Eric Wong
2019-10-15 20:36 ` [PATCH 2/7] config: we always have {-section_order} Eric Wong
2019-10-15 20:36 ` [PATCH 3/7] config: simplify lookup* methods Eric Wong
2019-10-15 20:36 ` [PATCH 4/7] config: avoid unnecessary '||' use Eric Wong
2019-10-15 20:36 ` [PATCH 5/7] config: allow "0" as a valid mainrepo path Eric Wong
2019-10-15 20:36 ` Eric Wong [this message]
2019-10-15 20:36 ` [PATCH 7/7] wwwtext: show listid config directive(s) Eric Wong

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

  List information: https://public-inbox.org/README

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20191015203633.17665-7-e@80x24.org \
    --to=e@80x24.org \
    --cc=ebiederm@xmission.com \
    --cc=meta@public-inbox.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
Code repositories for project(s) associated with this public inbox

	https://80x24.org/public-inbox.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).