]> Sergey Matveev's repositories - public-inbox.git/blob - lib/PublicInbox/WwwText.pm
remove unused/redundant zlib-related imports
[public-inbox.git] / lib / PublicInbox / WwwText.pm
1 # Copyright (C) 2016-2020 all contributors <meta@public-inbox.org>
2 # License: AGPL-3.0+ <https://www.gnu.org/licenses/agpl-3.0.txt>
3
4 # used for displaying help texts and other non-mail content
5 package PublicInbox::WwwText;
6 use strict;
7 use warnings;
8 use bytes (); # only for bytes::length
9 use PublicInbox::Linkify;
10 use PublicInbox::WwwStream;
11 use PublicInbox::Hval qw(ascii_html);
12 use URI::Escape qw(uri_escape_utf8);
13 use PublicInbox::GzipFilter qw(gzf_maybe);
14 our $QP_URL = 'https://xapian.org/docs/queryparser.html';
15 our $WIKI_URL = 'https://en.wikipedia.org/wiki';
16 my $hl = eval {
17         require PublicInbox::HlMod;
18         PublicInbox::HlMod->new
19 };
20
21 # /$INBOX/_/text/$KEY/ # KEY may contain slashes
22 # For now, "help" is the only supported $KEY
23 sub get_text {
24         my ($ctx, $key) = @_;
25         my $code = 200;
26
27         $key = 'help' if !defined $key; # this 302s to _/text/help/
28
29         # get the raw text the same way we get mboxrds
30         my $raw = ($key =~ s!/raw\z!!);
31         my $have_tslash = ($key =~ s!/\z!!) if !$raw;
32
33         my $txt = '';
34         my $hdr = [ 'Content-Type', 'text/plain', 'Content-Length', undef ];
35         if (!_default_text($ctx, $key, $hdr, \$txt)) {
36                 $code = 404;
37                 $txt = "404 Not Found ($key)\n";
38         }
39         my $env = $ctx->{env};
40         if ($raw) {
41                 my $body;
42                 if (my $gzf = $code == 200 ? gzf_maybe($hdr, $env) : undef) {
43                         my $zbuf = $gzf->translate($txt);
44                         undef $txt;
45                         $body = [ $zbuf .= $gzf->translate(undef) ];
46                 } else {
47                         $body = [ $txt ];
48                 }
49                 $hdr->[3] = bytes::length($body->[0]);
50                 return [ $code, $hdr, $body ]
51         }
52
53         # enforce trailing slash for "wget -r" compatibility
54         if (!$have_tslash && $code == 200) {
55                 my $url = $ctx->{-inbox}->base_url($env);
56                 $url .= "_/text/$key/";
57
58                 return [ 302, [ 'Content-Type', 'text/plain',
59                                 'Location', $url ],
60                         [ "Redirecting to $url\n" ] ];
61         }
62
63         # Follow git commit message conventions,
64         # first line is the Subject/title
65         my ($title) = ($txt =~ /\A([^\n]*)/s);
66         $ctx->{-title_html} = ascii_html($title);
67         my $nslash = ($key =~ tr!/!/!);
68         $ctx->{-upfx} = '../../../' . ('../' x $nslash);
69         my $l = PublicInbox::Linkify->new;
70         $l->linkify_1($txt);
71         if ($hl) {
72                 $hl->do_hl_text(\$txt);
73         } else {
74                 $txt = ascii_html($txt);
75         }
76         $txt = '<pre>' . $l->linkify_2($txt) . '</pre>';
77         PublicInbox::WwwStream::html_oneshot($ctx, $code, \$txt);
78 }
79
80 sub _srch_prefix ($$) {
81         my ($srch, $txt) = @_;
82         my $pad = 0;
83         my $htxt = '';
84         my $help = $srch->help;
85         my $i;
86         for ($i = 0; $i < @$help; $i += 2) {
87                 my $pfx = $help->[$i];
88                 my $n = length($pfx);
89                 $pad = $n if $n > $pad;
90                 $htxt .= $pfx . "\0";
91                 $htxt .= $help->[$i + 1];
92                 $htxt .= "\f\n";
93         }
94         $pad += 2;
95         my $padding = ' ' x ($pad + 8);
96         $htxt =~ s/^/$padding/gms;
97         $htxt =~ s/^$padding(\S+)\0/"        $1".
98                                 (' ' x ($pad - length($1)))/egms;
99         $htxt =~ s/\f\n/\n/gs;
100         $$txt .= $htxt;
101         1;
102 }
103
104 sub _colors_help ($$) {
105         my ($ctx, $txt) = @_;
106         my $ibx = $ctx->{-inbox};
107         my $env = $ctx->{env};
108         my $base_url = $ibx->base_url($env);
109         $$txt .= "color customization for $base_url\n";
110         $$txt .= <<EOF;
111
112 public-inbox provides a stable set of CSS classes for users to
113 customize colors for highlighting diffs and code.
114
115 Users of browsers such as dillo, Firefox, or some browser
116 extensions may start by downloading the following sample CSS file
117 to control the colors they see:
118
119         ${base_url}userContent.css
120
121 CSS sample
122 ----------
123 ```css
124 EOF
125         $$txt .= PublicInbox::UserContent::sample($ibx, $env) . "```\n";
126 }
127
128 # git-config section names are quoted in the config file, so escape them
129 sub dq_escape ($) {
130         my ($name) = @_;
131         $name =~ s/\\/\\\\/g;
132         $name =~ s/"/\\"/g;
133         $name;
134 }
135
136 sub URI_PATH () { '^A-Za-z0-9\-\._~/' }
137
138 # n.b. this is a perfect candidate for memoization
139 sub inbox_config ($$$) {
140         my ($ctx, $hdr, $txt) = @_;
141         my $ibx = $ctx->{-inbox};
142         push @$hdr, 'Content-Disposition', 'inline; filename=inbox.config';
143         my $name = dq_escape($ibx->{name});
144         my $inboxdir = '/path/to/top-level-inbox';
145         $$txt .= <<EOS;
146 ; example public-inbox config snippet for "$name"
147 ; see public-inbox-config(5) manpage for more details:
148 ; https://public-inbox.org/public-inbox-config.html
149 [publicinbox "$name"]
150         inboxdir = $inboxdir
151         ; note: public-inbox before v1.2.0 used "mainrepo"
152         ; instead of "inboxdir", both remain supported after 1.2
153         mainrepo = $inboxdir
154         url = https://example.com/$name/
155         url = http://example.onion/$name/
156 EOS
157         for my $k (qw(address listid infourl watchheader)) {
158                 defined(my $v = $ibx->{$k}) or next;
159                 $$txt .= "\t$k = $_\n" for @$v;
160         }
161         if (my $altid = $ibx->{altid}) {
162                 my $base_url = $ibx->base_url($ctx->{env});
163                 my $altid_map = $ibx->altid_map;
164                 $$txt .= <<EOF;
165         ; altid DBs may be used to provide numeric article ID lookup from
166         ; old, pre-existing sources.  You can recreate them via curl(1),
167         ; gzip(1), and sqlite3(1) as documented:
168 EOF
169                 for (sort keys %$altid_map) {
170                         $$txt .= "\t;\tcurl -XPOST $base_url$_.sql.gz | \\\n" .
171                                 "\t;\tgzip -dc | \\\n" .
172                                 "\t;\tsqlite3 $inboxdir/$_.sqlite3\n";
173                         $$txt .= "\taltid = serial:$_:file=$_.sqlite3\n";
174                 }
175         }
176
177         for my $k (qw(filter newsgroup obfuscate replyto)) {
178                 defined(my $v = $ibx->{$k}) or next;
179                 $$txt .= "\t$k = $v\n";
180         }
181         $$txt .= "\tnntpmirror = $_\n" for (@{$ibx->nntp_url});
182
183         # note: this doesn't preserve cgitrc layout, since we parse cgitrc
184         # and drop the original structure
185         if (defined(my $cr = $ibx->{coderepo})) {
186                 $$txt .= "\tcoderepo = $_\n" for @$cr;
187
188                 my $pi_config = $ctx->{www}->{pi_config};
189                 for my $cr_name (@$cr) {
190                         my $urls = $pi_config->{"coderepo.$cr_name.cgiturl"};
191                         my $path = "/path/to/$cr_name";
192                         $cr_name = dq_escape($cr_name);
193
194                         $$txt .= qq([coderepo "$cr_name"]\n);
195                         if ($urls && scalar(@$urls)) {
196                                 $$txt .= "\t; ";
197                                 $$txt .= join(" ||\n\t;\t", map {;
198                                         my $cpath = $path;
199                                         if ($path !~ m![a-z0-9_/\.\-]!i) {
200                                                 $cpath = dq_escape($cpath);
201                                         }
202                                         qq(git clone $_ "$cpath");
203                                 } @$urls);
204                                 $$txt .= "\n";
205                         }
206                         $$txt .= "\tdir = $path\n";
207                         $$txt .= "\tcgiturl = https://example.com/";
208                         $$txt .= uri_escape_utf8($cr_name, URI_PATH)."\n";
209                 }
210         }
211         1;
212 }
213
214 sub _default_text ($$$$) {
215         my ($ctx, $key, $hdr, $txt) = @_;
216         return _colors_help($ctx, $txt) if $key eq 'color';
217         return inbox_config($ctx, $hdr, $txt) if $key eq 'config';
218         return if $key ne 'help'; # TODO more keys?
219
220         my $ibx = $ctx->{-inbox};
221         my $base_url = $ibx->base_url($ctx->{env});
222         $$txt .= "public-inbox help for $base_url\n";
223         $$txt .= <<EOF;
224
225 overview
226 --------
227
228     public-inbox uses Message-ID identifiers in URLs.
229     One may look up messages by substituting Message-IDs
230     (without the leading '<' or trailing '>') into the URL.
231     Forward slash ('/') characters in the Message-IDs
232     need to be escaped as "%2F" (without quotes).
233
234     Thus, it is possible to retrieve any message by its
235     Message-ID by going to:
236
237         $base_url<Message-ID>/
238
239         (without the '<' or '>')
240
241     Message-IDs are described at:
242
243         $WIKI_URL/Message-ID
244
245 EOF
246
247         # n.b. we use the Xapian DB for any regeneratable,
248         # order-of-arrival-independent data.
249         my $srch = $ibx->search;
250         if ($srch) {
251                 $$txt .= <<EOF;
252 search
253 ------
254
255     This public-inbox has search functionality provided by Xapian.
256
257     It supports typical AND, OR, NOT, '+', '-' queries present
258     in other search engines.
259
260     We also support search prefixes to limit the scope of the
261     search to certain fields.
262
263     Prefixes supported in this installation include:
264
265 EOF
266                 _srch_prefix($srch, $txt);
267
268                 $$txt .= <<EOF;
269
270     Most prefixes are probabilistic, meaning they support stemming
271     and wildcards ('*').  Ranges (such as 'd:') and boolean prefixes
272     do not support stemming or wildcards.
273     The upstream Xapian query parser documentation fully explains
274     the query syntax:
275
276         $QP_URL
277
278 EOF
279         } # $srch
280         my $over = $ibx->over;
281         if ($over) {
282                 $$txt .= <<EOF;
283 message threading
284 -----------------
285
286     Message threading is enabled for this public-inbox,
287     additional endpoints for message threads are available:
288
289     * $base_url<Message-ID>/T/#u
290
291       Loads the thread belonging to the given <Message-ID>
292       in flat chronological order.  The "#u" anchor
293       focuses the browser on the given <Message-ID>.
294
295     * $base_url<Message-ID>/t/#u
296
297       Loads the thread belonging to the given <Message-ID>
298       in threaded order with nesting.  For deep threads,
299       this requires a wide display or horizontal scrolling.
300
301     Both of these HTML endpoints are suitable for offline reading
302     using the thread overview at the bottom of each page.
303
304     Users of feed readers may follow a particular thread using:
305
306     * $base_url<Message-ID>/t.atom
307
308       Which loads the thread in Atom Syndication Standard
309       described at Wikipedia and RFC4287:
310
311         $WIKI_URL/Atom_(standard)
312         https://tools.ietf.org/html/rfc4287
313
314       Atom Threading Extensions (RFC4685) is supported:
315
316         https://tools.ietf.org/html/rfc4685
317
318     Finally, the gzipped mbox for a thread is available for
319     downloading and importing into your favorite mail client:
320
321     * $base_url<Message-ID>/t.mbox.gz
322
323     We use the mboxrd variant of the mbox format described
324     at:
325
326         $WIKI_URL/Mbox
327
328 EOF
329         } # $over
330
331         $$txt .= <<EOF;
332 contact
333 -------
334
335     This help text is maintained by public-inbox developers
336     reachable via plain-text email at: meta\@public-inbox.org
337
338 EOF
339         # TODO: support admin contact info in ~/.public-inbox/config
340         1;
341 }
342
343 1;