]> Sergey Matveev's repositories - public-inbox.git/blob - lib/PublicInbox/Reply.pm
592dfb624f7a7091af7cdf4bd935d09624488d74
[public-inbox.git] / lib / PublicInbox / Reply.pm
1 # Copyright (C) all contributors <meta@public-inbox.org>
2 # License: AGPL-3.0+ <https://www.gnu.org/licenses/agpl-3.0.txt>
3
4 # For reply instructions and address generation in WWW UI
5 package PublicInbox::Reply;
6 use strict;
7 use v5.10.1;
8 use URI::Escape qw/uri_escape_utf8/;
9 use PublicInbox::Hval qw(ascii_html obfuscate_addrs mid_href);
10 use PublicInbox::Address;
11 use PublicInbox::MID qw(mid_clean);
12 use PublicInbox::Config;
13
14 *squote_maybe = \&PublicInbox::Config::squote_maybe;
15
16 sub add_addrs {
17         my ($to, $cc, @addrs) = @_;
18         foreach my $address (@addrs) {
19                 my $dst = lc($address);
20                 $cc->{$dst} ||= $address;
21                 $$to ||= $dst;
22         }
23 }
24
25 my @reply_headers = qw(From To Cc Reply-To);
26 my $reply_headers = join('|', @reply_headers);
27
28 sub mailto_arg_link {
29         my ($ibx, $hdr) = @_;
30         my $cc = {}; # everyone else
31         my $to; # this is the From address by default
32         my $reply_to_all = 'reply-to-all'; # the only good default :P
33         my $reply_to_cfg = $ibx->{replyto};
34
35         $reply_to_cfg ||= ':all';
36         if ($reply_to_cfg =~ /\A:none=(.*)/) {
37                 my $msg = $1;
38                 $msg = 'replies disabled' if $msg eq '';
39                 return \$msg;
40         }
41
42         foreach my $rt (split(/\s*,\s*/, $reply_to_cfg)) {
43                 if ($rt eq ':all') {
44                         foreach my $h (@reply_headers) {
45                                 my $v = $hdr->header($h);
46                                 defined($v) && ($v ne '') or next;
47                                 my @addrs = PublicInbox::Address::emails($v);
48                                 add_addrs(\$to, $cc, @addrs);
49                         }
50                 } elsif ($rt eq ':list') {
51                         $reply_to_all = 'reply-to-list';
52                         add_addrs(\$to, $cc, $ibx->{-primary_address});
53                 } elsif ($rt =~ /\A(?:$reply_headers)\z/io) {
54                         # ugh, this is weird...
55                         my $v = $hdr->header($rt);
56                         if (defined($v) && ($v ne '')) {
57                                 my @addrs = PublicInbox::Address::emails($v);
58                                 add_addrs(\$to, $cc, @addrs);
59                         }
60                 } elsif ($rt =~ /@/) {
61                         add_addrs(\$to, $cc, $rt);
62                 } else {
63                         warn "Unrecognized replyto = '$rt' in config\n";
64                 }
65         }
66
67         my @arg;
68         my $obfs = $ibx->{obfuscate};
69         my $subj = $hdr->header('Subject') || '';
70         $subj = "Re: $subj" unless $subj =~ /\bRe:/i;
71         my $subj_raw = $subj;
72         my $mid = $hdr->header_raw('Message-ID');
73         push @arg, '--in-reply-to='.squote_maybe(mid_clean($mid));
74         my $irt = mid_href($mid);
75         add_addrs(\$to, $cc, $ibx->{-primary_address}) unless defined($to);
76         delete $cc->{$to};
77         if ($obfs) {
78                 my $arg_to = $to;
79                 obfuscate_addrs($ibx, $arg_to, '$(echo .)');
80                 push @arg, "--to=$arg_to";
81                 # no $subj for $href below
82         } else {
83                 push @arg, "--to=$to";
84                 $subj = uri_escape_utf8($subj);
85         }
86         my @cc = sort values %$cc;
87         $cc = '';
88         if (@cc) {
89                 if ($obfs) {
90                         push(@arg, map {
91                                 my $addr = $_;
92                                 obfuscate_addrs($ibx, $addr, '$(echo .)');
93                                 "--cc=$addr";
94                         } @cc);
95                 } else {
96                         $cc = '&Cc=' . uri_escape_utf8(join(',', @cc));
97                         push(@arg, map { "--cc=$_" } @cc);
98                 }
99         }
100
101         push @arg, "--subject=".squote_maybe($subj_raw);
102
103         # I'm not sure if address obfuscation and mailto: links can
104         # be made compatible; and address obfuscation is misguided,
105         # anyways.
106         return (\@arg, '', $reply_to_all) if $obfs;
107
108         # keep `@' instead of using `%40' for RFC 6068
109         utf8::encode($to);
110         $to =~ s!([^A-Za-z0-9\-\._~\@])!$URI::Escape::escapes{$1}!ge;
111
112         # order matters, Subject is the least important header,
113         # so it is last in case it's lost/truncated in a copy+paste
114         my $href = "mailto:$to?In-Reply-To=$irt${cc}&Subject=$subj";
115
116         (\@arg, ascii_html($href), $reply_to_all);
117 }
118
119 1;