]> Sergey Matveev's repositories - public-inbox.git/commitdiff
mda: support multiple List-ID matches
authorEric Wong <e@80x24.org>
Mon, 28 Oct 2019 10:45:26 +0000 (10:45 +0000)
committerEric Wong <e@80x24.org>
Wed, 30 Oct 2019 08:49:39 +0000 (08:49 +0000)
While it's not RFC2919-conformant, mail software can
theoretically set multiple List-ID headers.  Deliver to all
inboxes which match a given List-ID since that's likely the
intended.

Cc: Eric W. Biederman <ebiederm@xmission.com>
Link: https://public-inbox.org/meta/87pniltscf.fsf@x220.int.ebiederm.org/
lib/PublicInbox/MDA.pm
script/public-inbox-learn
script/public-inbox-mda
t/mda.t

index ce2c870f89edcd353d263d1c8fed28a0d08ede1f..b0dfac4564cfe12425a1ece5d31caa06f63069d4 100644 (file)
@@ -83,19 +83,25 @@ sub set_list_headers {
        }
 }
 
-# TODO: deal with multiple List-ID headers?
-sub inbox_for_list_id ($$) {
+sub inboxes_for_list_id ($$) {
        my ($klass, $config, $simple) = @_;
 
        # newer Email::Simple allows header_raw, as does Email::MIME:
-       my $list_id = $simple->can('header_raw') ?
+       my @list_ids = $simple->can('header_raw') ?
                        $simple->header_raw('List-Id') :
                        $simple->header('List-Id');
-       my $ibx;
-       if (defined $list_id && $list_id =~ /<[ \t]*(.+)?[ \t]*>/) {
-               $ibx = $config->lookup_list_id($1);
+       my @dests;
+       for my $list_id (@list_ids) {
+               $list_id =~ /<[ \t]*(.+)?[ \t]*>/ or next;
+               if (my $ibx = $config->lookup_list_id($1)) {
+                       push @dests, $ibx;
+               }
+       }
+       if (scalar(@list_ids) > 1) {
+               warn "W: multiple List-IDs in message:\n";
+               warn "W: List-ID: $_\n" for @list_ids
        }
-       $ibx;
+       \@dests;
 }
 
 1;
index 79f3ead5c722cda3d17cea9f4fc8ea185fa39530..3073294a18bb526138d24e6898325157726c9586 100644 (file)
@@ -95,8 +95,9 @@ if ($train eq 'spam') {
                next if $seen{"$ibx"}++;
                remove_or_add($ibx, $train, $addr);
        }
-       my $ibx = PublicInbox::MDA->inbox_for_list_id($pi_config, $mime);
-       if ($ibx && !$seen{"$ibx"}) {
+       my $dests = PublicInbox::MDA->inboxes_for_list_id($pi_config, $mime);
+       for my $ibx (@$dests) {
+               next if !$seen{"$ibx"}++;
                remove_or_add($ibx, $train, $ibx->{-primary_address});
        }
 }
index 821bd9cca36bb00d33d074c0c8e37d22f3387be5..dca8a0ea0e8aa64f859676773e736d4cae77a3a1 100755 (executable)
@@ -44,12 +44,11 @@ if (defined $recipient) {
        push @$dests, $ibx if $ibx;
 }
 if (!scalar(@$dests)) {
-       my $ibx = PublicInbox::MDA->inbox_for_list_id($config, $simple);
-       if (!defined($ibx) && !defined($recipient)) {
+       $dests = PublicInbox::MDA->inboxes_for_list_id($config, $simple);
+       if (!scalar(@$dests) && !defined($recipient)) {
                die "ORIGINAL_RECIPIENT not defined in ENV\n";
        }
-       defined($ibx) or do_exit(67); # EX_NOUSER 5.1.1 user unknown
-       push @$dests, $ibx;
+       scalar(@$dests) or do_exit(67); # EX_NOUSER 5.1.1 user unknown
 }
 
 my $err;
diff --git a/t/mda.t b/t/mda.t
index 99592b2d9e901874f9a271f512c1b943897808e5..35811ac6f19e9a103d338fc7a40c31dc0ede67f8 100644 (file)
--- a/t/mda.t
+++ b/t/mda.t
@@ -308,6 +308,25 @@ EOF
        my $cur = `git --git-dir=$maindir diff HEAD~1..HEAD`;
        like($cur, qr/this message would not be accepted without --no-precheck/,
                '--no-precheck delivered message anyways');
+
+       # try a message with multiple List-ID headers
+       $in = <<EOF;
+List-ID: <foo.bar>
+List-ID: <$list_id>
+Message-ID: <2lids\@example>
+Subject: two List-IDs
+From: user <user\@example.com>
+To: $addr
+Date: Fri, 02 Oct 1993 00:00:00 +0000
+
+EOF
+       ($out, $err) = ('', '');
+       IPC::Run::run([$mda], \$in, \$out, \$err);
+       is($?, 0, 'mda OK with multiple List-Id matches');
+       $cur = `git --git-dir=$maindir diff HEAD~1..HEAD`;
+       like($cur, qr/Message-ID: <2lids\@example>/,
+               'multi List-ID match delivered');
+       like($err, qr/multiple List-ID/, 'warned about multiple List-ID');
 }
 
 done_testing();