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