user/dev discussion of public-inbox itself
 help / color / mirror / code / Atom feed
* [PATCH 0/3] support per-inbox "replyto" parameter
@ 2017-06-14  0:10 Eric Wong
  2017-06-14  0:10 ` [PATCH 1/3] view: split out reply logic into its own module Eric Wong
                   ` (2 more replies)
  0 siblings, 3 replies; 4+ messages in thread
From: Eric Wong @ 2017-06-14  0:10 UTC (permalink / raw)
  To: meta

These changes should facilitate hosting mirrors of (unfortunately)
centralized mailing lists.  More changes, such as email address
obfuscation may be necessary to support misguided people who believe
in address obfuscation.

Eric Wong (3):
      view: split out reply logic into its own module
      replyto parameter support
      reply: support Reply-To

 MANIFEST                  |  2 ++
 lib/PublicInbox/Config.pm |  2 +-
 lib/PublicInbox/Reply.pm  | 84 +++++++++++++++++++++++++++++++++++++++++++++++
 lib/PublicInbox/View.pm   | 50 +++-------------------------
 t/reply.t                 | 67 +++++++++++++++++++++++++++++++++++++
 t/view.t                  | 12 -------
 6 files changed, 158 insertions(+), 59 deletions(-)


^ permalink raw reply	[flat|nested] 4+ messages in thread

* [PATCH 1/3] view: split out reply logic into its own module
  2017-06-14  0:10 [PATCH 0/3] support per-inbox "replyto" parameter Eric Wong
@ 2017-06-14  0:10 ` Eric Wong
  2017-06-14  0:10 ` [PATCH 2/3] replyto parameter support Eric Wong
  2017-06-14  0:10 ` [PATCH 3/3] reply: support Reply-To Eric Wong
  2 siblings, 0 replies; 4+ messages in thread
From: Eric Wong @ 2017-06-14  0:10 UTC (permalink / raw)
  To: meta

We'll be adding more reply options for centralized mailing
lists.  So split out the logic so it's easy-to-find.
Organizing code is hard :<
---
 MANIFEST                 |  1 +
 lib/PublicInbox/Reply.pm | 54 ++++++++++++++++++++++++++++++++++++++++++++++++
 lib/PublicInbox/View.pm  | 47 ++---------------------------------------
 t/view.t                 |  2 +-
 4 files changed, 58 insertions(+), 46 deletions(-)
 create mode 100644 lib/PublicInbox/Reply.pm

diff --git a/MANIFEST b/MANIFEST
index 3bfd9a4..0475cdd 100644
--- a/MANIFEST
+++ b/MANIFEST
@@ -76,6 +76,7 @@ lib/PublicInbox/NewsWWW.pm
 lib/PublicInbox/ParentPipe.pm
 lib/PublicInbox/ProcessPipe.pm
 lib/PublicInbox/Qspawn.pm
+lib/PublicInbox/Reply.pm
 lib/PublicInbox/SaPlugin/ListMirror.pm
 lib/PublicInbox/Search.pm
 lib/PublicInbox/SearchIdx.pm
diff --git a/lib/PublicInbox/Reply.pm b/lib/PublicInbox/Reply.pm
new file mode 100644
index 0000000..73a4df1
--- /dev/null
+++ b/lib/PublicInbox/Reply.pm
@@ -0,0 +1,54 @@
+# Copyright (C) 2014-2017 all contributors <meta@public-inbox.org>
+# License: AGPL-3.0+ <https://www.gnu.org/licenses/agpl-3.0.txt>
+package PublicInbox::Reply;
+use strict;
+use warnings;
+use URI::Escape qw/uri_escape_utf8/;
+use PublicInbox::Hval qw/ascii_html/;
+use PublicInbox::Address;
+use PublicInbox::MID qw/mid_clean mid_escape/;
+
+sub squote_maybe ($) {
+	my ($val) = @_;
+	if ($val =~ m{([^\w@\./,\%\+\-])}) {
+		$val =~ s/(['!])/'\\$1'/g; # '!' for csh
+		return "'$val'";
+	}
+	$val;
+}
+
+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 @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};
+	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";
+
+	(\@arg, ascii_html($href));
+}
+
+1;
diff --git a/lib/PublicInbox/View.pm b/lib/PublicInbox/View.pm
index 9ef4712..0d85581 100644
--- a/lib/PublicInbox/View.pm
+++ b/lib/PublicInbox/View.pm
@@ -6,7 +6,6 @@
 package PublicInbox::View;
 use strict;
 use warnings;
-use URI::Escape qw/uri_escape_utf8/;
 use Date::Parse qw/str2time/;
 use PublicInbox::Hval qw/ascii_html/;
 use PublicInbox::Linkify;
@@ -14,6 +13,7 @@ use PublicInbox::MID qw/mid_clean id_compress mid_mime mid_escape/;
 use PublicInbox::MsgIter;
 use PublicInbox::Address;
 use PublicInbox::WwwStream;
+use PublicInbox::Reply;
 require POSIX;
 
 use constant INDENT => '  ';
@@ -57,7 +57,7 @@ sub msg_reply {
 		$info = qq(\n  List information: <a\nhref="$url">$url</a>\n);
 	}
 
-	my ($arg, $link) = mailto_arg_link($hdr);
+	my ($arg, $link) = PublicInbox::Reply::mailto_arg_link($hdr);
 	push @$arg, '/path/to/YOUR_REPLY';
 	$arg = ascii_html(join(" \\\n    ", '', @$arg));
 	<<EOF
@@ -618,49 +618,6 @@ sub _parent_headers {
 	$rv;
 }
 
-sub squote_maybe ($) {
-	my ($val) = @_;
-	if ($val =~ m{([^\w@\./,\%\+\-])}) {
-		$val =~ s/(['!])/'\\$1'/g; # '!' for csh
-		return "'$val'";
-	}
-	$val;
-}
-
-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 @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};
-	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";
-
-	(\@arg, ascii_html($href));
-}
-
 sub html_footer {
 	my ($hdr, $standalone, $ctx, $rhref) = @_;
 
diff --git a/t/view.t b/t/view.t
index 2181b5e..abd0001 100644
--- a/t/view.t
+++ b/t/view.t
@@ -15,7 +15,7 @@ my @q = (
 while (@q) {
 	my $input = shift @q;
 	my $expect = shift @q;
-	my $res = PublicInbox::View::squote_maybe($input);
+	my $res = PublicInbox::Reply::squote_maybe($input);
 	is($res, $expect, "quote $input => $res");
 }
 
-- 
EW


^ permalink raw reply related	[flat|nested] 4+ messages in thread

* [PATCH 2/3] replyto parameter support
  2017-06-14  0:10 [PATCH 0/3] support per-inbox "replyto" parameter Eric Wong
  2017-06-14  0:10 ` [PATCH 1/3] view: split out reply logic into its own module Eric Wong
@ 2017-06-14  0:10 ` Eric Wong
  2017-06-14  0:10 ` [PATCH 3/3] reply: support Reply-To Eric Wong
  2 siblings, 0 replies; 4+ messages in thread
From: Eric Wong @ 2017-06-14  0:10 UTC (permalink / raw)
  To: meta

This allows us to support centralized mailing lists (which suck,
but better than no mailing list at all).
---
 MANIFEST                  |  1 +
 lib/PublicInbox/Config.pm |  2 +-
 lib/PublicInbox/Reply.pm  | 66 +++++++++++++++++++++++++++++++++-------------
 lib/PublicInbox/View.pm   |  5 ++--
 t/reply.t                 | 67 +++++++++++++++++++++++++++++++++++++++++++++++
 t/view.t                  | 12 ---------
 6 files changed, 120 insertions(+), 33 deletions(-)
 create mode 100644 t/reply.t

diff --git a/MANIFEST b/MANIFEST
index 0475cdd..d0b7f2b 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 f6275cd..323f8a1 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 73a4df1..5bbe8f4 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 0d85581..2d81640 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 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();
diff --git a/t/view.t b/t/view.t
index abd0001..1f4ed93 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' },
-- 
EW


^ permalink raw reply related	[flat|nested] 4+ messages in thread

* [PATCH 3/3] reply: support Reply-To
  2017-06-14  0:10 [PATCH 0/3] support per-inbox "replyto" parameter Eric Wong
  2017-06-14  0:10 ` [PATCH 1/3] view: split out reply logic into its own module Eric Wong
  2017-06-14  0:10 ` [PATCH 2/3] replyto parameter support Eric Wong
@ 2017-06-14  0:10 ` Eric Wong
  2 siblings, 0 replies; 4+ messages in thread
From: Eric Wong @ 2017-06-14  0:10 UTC (permalink / raw)
  To: meta

Reply-To is common and probably should've been supported,
since day one, but we won't omit other addresses, either.
---
 lib/PublicInbox/Reply.pm | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lib/PublicInbox/Reply.pm b/lib/PublicInbox/Reply.pm
index 5bbe8f4..13ae052 100644
--- a/lib/PublicInbox/Reply.pm
+++ b/lib/PublicInbox/Reply.pm
@@ -26,7 +26,7 @@ sub add_addrs {
 	}
 }
 
-my @reply_headers = qw(From To Cc);
+my @reply_headers = qw(From To Cc Reply-To);
 my $reply_headers = join('|', @reply_headers);
 
 sub mailto_arg_link {
-- 
EW


^ permalink raw reply related	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2017-06-14  0:11 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-06-14  0:10 [PATCH 0/3] support per-inbox "replyto" parameter Eric Wong
2017-06-14  0:10 ` [PATCH 1/3] view: split out reply logic into its own module Eric Wong
2017-06-14  0:10 ` [PATCH 2/3] replyto parameter support Eric Wong
2017-06-14  0:10 ` [PATCH 3/3] reply: support Reply-To Eric Wong

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).