]> Sergey Matveev's repositories - public-inbox.git/commitdiff
replyto parameter support
authorEric Wong <e@80x24.org>
Wed, 14 Jun 2017 00:10:52 +0000 (00:10 +0000)
committerEric Wong <e@80x24.org>
Thu, 15 Jun 2017 23:13:00 +0000 (23:13 +0000)
This allows us to support centralized mailing lists (which suck,
but better than no mailing list at all).

MANIFEST
lib/PublicInbox/Config.pm
lib/PublicInbox/Reply.pm
lib/PublicInbox/View.pm
t/reply.t [new file with mode: 0644]
t/view.t

index 0475cdd62ce77612c316f5c9f1d6094131ee17f9..d0b7f2be44421345d93de630e7e10be114865ddc 100644 (file)
--- 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
index f6275cdd24663d2f5b3f8235d7e188a04863b923..323f8a1aa6e13397c7933ec7a156654b84554ed8 100644 (file)
@@ -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;
        }
index 73a4df119bdabe9dcb55fa5bb250df911cab8b66..5bbe8f4e7878ea17df34b43fc19f6edd9682769c 100644 (file)
@@ -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));
 }
index 0d85581dfd966eed4a0e4e0db2f2817c2f0e1713..2d816408cee5ca7437cbe0b11fde8084f363f67e 100644 (file)
@@ -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 (file)
index 0000000..640069c
--- /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();
index abd00018e73381f84f4573a342502d24cfbce5a7..1f4ed9373a8857a385cea3a84b78c3226325c0dd 100644 (file)
--- 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' },