about summary refs log tree commit homepage
diff options
context:
space:
mode:
authorEric Wong <e@80x24.org>2017-06-14 00:10:52 +0000
committerEric Wong <e@80x24.org>2017-06-15 23:13:00 +0000
commitef3ca9b80fcb464d851c2f8d87f3f02f4f70986d (patch)
tree905052112686dec08eea7d4b6d2c87216e36fe0b
parent92afb41e15dfdcda291b432173bd49ddfc49614a (diff)
downloadpublic-inbox-ef3ca9b80fcb464d851c2f8d87f3f02f4f70986d.tar.gz
This allows us to support centralized mailing lists (which suck,
but better than no mailing list at all).
-rw-r--r--MANIFEST1
-rw-r--r--lib/PublicInbox/Config.pm2
-rw-r--r--lib/PublicInbox/Reply.pm66
-rw-r--r--lib/PublicInbox/View.pm5
-rw-r--r--t/reply.t67
-rw-r--r--t/view.t12
6 files changed, 120 insertions, 33 deletions
diff --git a/MANIFEST b/MANIFEST
index 0475cdd6..d0b7f2be 100644
--- a/MANIFEST
+++ b/MANIFEST
@@ -159,6 +159,7 @@ t/psgi_mount.t
 t/psgi_search.t
 t/psgi_text.t
 t/qspawn.t
+t/reply.t
 t/search-thr-index.t
 t/search.t
 t/spamcheck_spamc.t
diff --git a/lib/PublicInbox/Config.pm b/lib/PublicInbox/Config.pm
index f6275cdd..323f8a1a 100644
--- a/lib/PublicInbox/Config.pm
+++ b/lib/PublicInbox/Config.pm
@@ -136,7 +136,7 @@ sub _fill {
 
         foreach my $k (qw(mainrepo address filter url newsgroup
                         infourl watch watchheader httpbackendmax
-                        feedmax nntpserver)) {
+                        replyto feedmax nntpserver)) {
                 my $v = $self->{"$pfx.$k"};
                 $rv->{$k} = $v if defined $v;
         }
diff --git a/lib/PublicInbox/Reply.pm b/lib/PublicInbox/Reply.pm
index 73a4df11..5bbe8f4e 100644
--- a/lib/PublicInbox/Reply.pm
+++ b/lib/PublicInbox/Reply.pm
@@ -17,36 +17,66 @@ sub squote_maybe ($) {
         $val;
 }
 
+sub add_addrs {
+        my ($to, $cc, @addrs) = @_;
+        foreach my $address (@addrs) {
+                my $dst = lc($address);
+                $cc->{$dst} ||= $address;
+                $$to ||= $dst;
+        }
+}
+
+my @reply_headers = qw(From To Cc);
+my $reply_headers = join('|', @reply_headers);
+
 sub mailto_arg_link {
-        my ($hdr) = @_;
-        my %cc; # everyone else
-        my $to; # this is the From address
-
-        foreach my $h (qw(From To Cc)) {
-                my $v = $hdr->header($h);
-                defined($v) && ($v ne '') or next;
-                my @addrs = PublicInbox::Address::emails($v);
-                foreach my $address (@addrs) {
-                        my $dst = lc($address);
-                        $cc{$dst} ||= $address;
-                        $to ||= $dst;
+        my ($ibx, $hdr) = @_;
+        my $cc = {}; # everyone else
+        my $to; # this is the From address by default
+
+        foreach my $rt (split(/\s*,\s*/, $ibx->{replyto} || ':all')) {
+                if ($rt eq ':all') {
+                        foreach my $h (@reply_headers) {
+                                my $v = $hdr->header($h);
+                                defined($v) && ($v ne '') or next;
+                                my @addrs = PublicInbox::Address::emails($v);
+                                add_addrs(\$to, $cc, @addrs);
+                        }
+                } elsif ($rt eq ':list') {
+                        add_addrs(\$to, $cc, $ibx->{-primary_address});
+                } elsif ($rt =~ /\A(?:$reply_headers)\z/io) {
+                        my $v = $hdr->header($rt);
+                        if (defined($v) && ($v ne '')) {
+                                my @addrs = PublicInbox::Address::emails($v);
+                                add_addrs(\$to, $cc, @addrs);
+                        }
+                } elsif ($rt =~ /@/) {
+                        add_addrs(\$to, $cc, $rt);
+                } else {
+                        warn "Unrecognized replyto = '$rt' in config\n";
                 }
         }
-        my @arg;
 
+        my @arg;
         my $subj = $hdr->header('Subject') || '';
         $subj = "Re: $subj" unless $subj =~ /\bRe:/i;
         my $mid = $hdr->header_raw('Message-ID');
         push @arg, '--in-reply-to='.squote_maybe(mid_clean($mid));
         my $irt = mid_escape($mid);
-        delete $cc{$to};
+        delete $cc->{$to};
         push @arg, "--to=$to";
         $to = uri_escape_utf8($to);
         $subj = uri_escape_utf8($subj);
-        my @cc = sort values %cc;
-        push(@arg, map { "--cc=$_" } @cc);
-        my $cc = uri_escape_utf8(join(',', @cc));
-        my $href = "mailto:$to?In-Reply-To=$irt&Cc=${cc}&Subject=$subj";
+        my @cc = sort values %$cc;
+        $cc = '';
+        if (@cc) {
+                push(@arg, map { "--cc=$_" } @cc);
+                $cc = '&Cc=' . uri_escape_utf8(join(',', @cc));
+        }
+
+        # order matters, Subject is the least important header,
+        # so it is last in case it's lost/truncated in a copy+paste
+        my $href = "mailto:$to?In-Reply-To=$irt${cc}&Subject=$subj";
 
         (\@arg, ascii_html($href));
 }
diff --git a/lib/PublicInbox/View.pm b/lib/PublicInbox/View.pm
index 0d85581d..2d816408 100644
--- a/lib/PublicInbox/View.pm
+++ b/lib/PublicInbox/View.pm
@@ -52,12 +52,13 @@ sub msg_reply {
          'https://en.wikipedia.org/wiki/Posting_style#Interleaved_style';
 
         my $info = '';
-        if (my $url = $ctx->{-inbox}->{infourl}) {
+        my $ibx = $ctx->{-inbox};
+        if (my $url = $ibx->{infourl}) {
                 $url = PublicInbox::Hval::prurl($ctx->{env}, $url);
                 $info = qq(\n  List information: <a\nhref="$url">$url</a>\n);
         }
 
-        my ($arg, $link) = PublicInbox::Reply::mailto_arg_link($hdr);
+        my ($arg, $link) = PublicInbox::Reply::mailto_arg_link($ibx, $hdr);
         push @$arg, '/path/to/YOUR_REPLY';
         $arg = ascii_html(join(" \\\n    ", '', @$arg));
         <<EOF
diff --git a/t/reply.t b/t/reply.t
new file mode 100644
index 00000000..640069cb
--- /dev/null
+++ b/t/reply.t
@@ -0,0 +1,67 @@
+# Copyright (C) 2017 all contributors <meta@public-inbox.org>
+# License: AGPL-3+ <https://www.gnu.org/licenses/agpl-3.0.txt>
+use strict;
+use warnings;
+use Test::More;
+use Email::MIME;
+use_ok 'PublicInbox::Reply';
+
+my @q = (
+        'foo@bar', 'foo@bar',
+        'a b', "'a b'",
+        "a'b", "'a'\\''b'",
+);
+
+while (@q) {
+        my $input = shift @q;
+        my $expect = shift @q;
+        my $res = PublicInbox::Reply::squote_maybe($input);
+        is($res, $expect, "quote $input => $res");
+}
+
+my $mime = Email::MIME->new(<<'EOF');
+From: from <from@example.com>
+To: to <to@example.com>
+Cc: cc@example.com
+Message-Id: <blah@example.com>
+Subject: hihi
+
+EOF
+
+my $hdr = $mime->header_obj;
+my $ibx = { -primary_address => 'primary@example.com' };
+
+my ($arg, $link) = PublicInbox::Reply::mailto_arg_link($ibx, $hdr);
+my $exp = [
+    '--in-reply-to=blah@example.com',
+    '--to=from@example.com',
+    '--cc=cc@example.com',
+    '--cc=to@example.com'
+];
+
+is_deeply($arg, $exp, 'default reply is to :all');
+$ibx->{replyto} = ':all';
+($arg, $link) = PublicInbox::Reply::mailto_arg_link($ibx, $hdr);
+is_deeply($arg, $exp, '":all" also works');
+
+$exp = [ '--in-reply-to=blah@example.com', '--to=primary@example.com' ];
+$ibx->{replyto} = ':list';
+($arg, $link) = PublicInbox::Reply::mailto_arg_link($ibx, $hdr);
+is_deeply($arg, $exp, '":list" works for centralized lists');
+
+$exp = [
+         '--in-reply-to=blah@example.com',
+         '--to=primary@example.com',
+         '--cc=cc@example.com',
+         '--cc=to@example.com'
+];
+$ibx->{replyto} = ':list,Cc,To';
+($arg, $link) = PublicInbox::Reply::mailto_arg_link($ibx, $hdr);
+is_deeply($arg, $exp, '":list,Cc,To" works for kinda centralized lists');
+
+$ibx->{replyto} = 'new@example.com';
+($arg, $link) = PublicInbox::Reply::mailto_arg_link($ibx, $hdr);
+$exp = [ '--in-reply-to=blah@example.com', '--to=new@example.com' ];
+is_deeply($arg, $exp, 'explicit address works, too');
+
+done_testing();
diff --git a/t/view.t b/t/view.t
index abd00018..1f4ed937 100644
--- a/t/view.t
+++ b/t/view.t
@@ -7,18 +7,6 @@ use Email::MIME;
 use Plack::Util;
 use_ok 'PublicInbox::View';
 
-my @q = (
-        'foo@bar', 'foo@bar',
-        'a b', "'a b'",
-        "a'b", "'a'\\''b'",
-);
-while (@q) {
-        my $input = shift @q;
-        my $expect = shift @q;
-        my $res = PublicInbox::Reply::squote_maybe($input);
-        is($res, $expect, "quote $input => $res");
-}
-
 # FIXME: make this test less fragile
 my $ctx = {
         env => { HTTP_HOST => 'example.com', 'psgi.url_scheme' => 'http' },