]> Sergey Matveev's repositories - public-inbox.git/blobdiff - lib/PublicInbox/WwwText.pm
get rid of unnecessary bytes::length usage
[public-inbox.git] / lib / PublicInbox / WwwText.pm
index b8beb97c6d5983e9c319a2f7733a4e232fc7f884..db5060eaa460bf002c4377b93eb1b14c1cd5c7ba 100644 (file)
@@ -1,15 +1,21 @@
-# Copyright (C) 2016 all contributors <meta@public-inbox.org>
+# Copyright (C) 2016-2021 all contributors <meta@public-inbox.org>
 # License: AGPL-3.0+ <https://www.gnu.org/licenses/agpl-3.0.txt>
 # License: AGPL-3.0+ <https://www.gnu.org/licenses/agpl-3.0.txt>
-#
-# serves the /$INBOX/_/* endpoints from :text/* of the git tree
+
+# used for displaying help texts and other non-mail content
 package PublicInbox::WwwText;
 use strict;
 package PublicInbox::WwwText;
 use strict;
-use warnings;
+use v5.10.1;
 use PublicInbox::Linkify;
 use PublicInbox::WwwStream;
 use PublicInbox::Hval qw(ascii_html);
 use PublicInbox::Linkify;
 use PublicInbox::WwwStream;
 use PublicInbox::Hval qw(ascii_html);
+use URI::Escape qw(uri_escape_utf8);
+use PublicInbox::GzipFilter qw(gzf_maybe);
 our $QP_URL = 'https://xapian.org/docs/queryparser.html';
 our $WIKI_URL = 'https://en.wikipedia.org/wiki';
 our $QP_URL = 'https://xapian.org/docs/queryparser.html';
 our $WIKI_URL = 'https://en.wikipedia.org/wiki';
+my $hl = eval {
+       require PublicInbox::HlMod;
+       PublicInbox::HlMod->new
+};
 
 # /$INBOX/_/text/$KEY/ # KEY may contain slashes
 # For now, "help" is the only supported $KEY
 
 # /$INBOX/_/text/$KEY/ # KEY may contain slashes
 # For now, "help" is the only supported $KEY
@@ -24,19 +30,25 @@ sub get_text {
        my $have_tslash = ($key =~ s!/\z!!) if !$raw;
 
        my $txt = '';
        my $have_tslash = ($key =~ s!/\z!!) if !$raw;
 
        my $txt = '';
-       if (!_default_text($ctx, $key, \$txt)) {
+       my $hdr = [ 'Content-Type', 'text/plain', 'Content-Length', undef ];
+       if (!_default_text($ctx, $key, $hdr, \$txt)) {
                $code = 404;
                $txt = "404 Not Found ($key)\n";
        }
                $code = 404;
                $txt = "404 Not Found ($key)\n";
        }
+       my $env = $ctx->{env};
        if ($raw) {
        if ($raw) {
-               return [ $code, [ 'Content-Type', 'text/plain',
-                                 'Content-Length', bytes::length($txt) ],
-                       [ $txt ] ]
+               if ($code == 200) {
+                       my $gzf = gzf_maybe($hdr, $env);
+                       $txt = $gzf->translate($txt);
+                       $txt .= $gzf->zflush;
+               }
+               $hdr->[3] = length($txt);
+               return [ $code, $hdr, [ $txt ] ]
        }
 
        # enforce trailing slash for "wget -r" compatibility
        if (!$have_tslash && $code == 200) {
        }
 
        # enforce trailing slash for "wget -r" compatibility
        if (!$have_tslash && $code == 200) {
-               my $url = $ctx->{-inbox}->base_url($ctx->{env});
+               my $url = $ctx->{ibx}->base_url($env);
                $url .= "_/text/$key/";
 
                return [ 302, [ 'Content-Type', 'text/plain',
                $url .= "_/text/$key/";
 
                return [ 302, [ 'Content-Type', 'text/plain',
@@ -47,21 +59,18 @@ sub get_text {
        # Follow git commit message conventions,
        # first line is the Subject/title
        my ($title) = ($txt =~ /\A([^\n]*)/s);
        # Follow git commit message conventions,
        # first line is the Subject/title
        my ($title) = ($txt =~ /\A([^\n]*)/s);
-       _do_linkify($txt);
        $ctx->{-title_html} = ascii_html($title);
        $ctx->{-title_html} = ascii_html($title);
-
        my $nslash = ($key =~ tr!/!/!);
        $ctx->{-upfx} = '../../../' . ('../' x $nslash);
        my $nslash = ($key =~ tr!/!/!);
        $ctx->{-upfx} = '../../../' . ('../' x $nslash);
-
-       PublicInbox::WwwStream->response($ctx, $code, sub {
-               my ($nr, undef) = @_;
-               $nr == 1 ? '<pre>'.$txt.'</pre>' : undef
-       });
-}
-
-sub _do_linkify {
        my $l = PublicInbox::Linkify->new;
        my $l = PublicInbox::Linkify->new;
-       $_[0] = $l->linkify_2(ascii_html($l->linkify_1($_[0])));
+       $l->linkify_1($txt);
+       if ($hl) {
+               $hl->do_hl_text(\$txt);
+       } else {
+               $txt = ascii_html($txt);
+       }
+       $txt = '<pre>' . $l->linkify_2($txt) . '</pre>';
+       PublicInbox::WwwStream::html_oneshot($ctx, $code, \$txt);
 }
 
 sub _srch_prefix ($$) {
 }
 
 sub _srch_prefix ($$) {
@@ -88,12 +97,130 @@ sub _srch_prefix ($$) {
        1;
 }
 
        1;
 }
 
+sub _colors_help ($$) {
+       my ($ctx, $txt) = @_;
+       my $ibx = $ctx->{ibx};
+       my $env = $ctx->{env};
+       my $base_url = $ibx->base_url($env);
+       $$txt .= "color customization for $base_url\n";
+       $$txt .= <<EOF;
+
+public-inbox provides a stable set of CSS classes for users to
+customize colors for highlighting diffs and code.
+
+Users of browsers such as dillo, Firefox, or some browser
+extensions may start by downloading the following sample CSS file
+to control the colors they see:
+
+       ${base_url}userContent.css
 
 
-sub _default_text ($$$) {
-       my ($ctx, $key, $txt) = @_;
+CSS sample
+----------
+```css
+EOF
+       $$txt .= PublicInbox::UserContent::sample($ibx, $env) . "```\n";
+}
+
+# git-config section names are quoted in the config file, so escape them
+sub dq_escape ($) {
+       my ($name) = @_;
+       $name =~ s/\\/\\\\/g;
+       $name =~ s/"/\\"/g;
+       $name;
+}
+
+sub URI_PATH () { '^A-Za-z0-9\-\._~/' }
+
+# n.b. this is a perfect candidate for memoization
+sub inbox_config ($$$) {
+       my ($ctx, $hdr, $txt) = @_;
+       my $ibx = $ctx->{ibx};
+       push @$hdr, 'Content-Disposition', 'inline; filename=inbox.config';
+       my $name = dq_escape($ibx->{name});
+       my $inboxdir = '/path/to/top-level-inbox';
+       my $base_url = $ibx->base_url($ctx->{env});
+       $$txt .= <<EOS;
+; Example public-inbox config snippet for a mirror of
+; $base_url
+; See public-inbox-config(5) manpage for more details:
+; https://public-inbox.org/public-inbox-config.html
+[publicinbox "$name"]
+       inboxdir = $inboxdir
+       ; note: public-inbox before v1.2.0 used `mainrepo' instead of
+       ; `inboxdir', both remain supported after 1.2
+       mainrepo = $inboxdir
+       url = https://example.com/$name/
+       url = http://example.onion/$name/
+EOS
+       for my $k (qw(address listid infourl watchheader)) {
+               defined(my $v = $ibx->{$k}) or next;
+               $$txt .= "\t$k = $_\n" for @$v;
+       }
+       if (my $altid = $ibx->{altid}) {
+               my $altid_map = $ibx->altid_map;
+               $$txt .= <<EOF;
+       ; altid DBs may be used to provide numeric article ID lookup from
+       ; old, pre-existing sources.  You can recreate them via curl(1),
+       ; gzip(1), and sqlite3(1) as documented:
+EOF
+               for (sort keys %$altid_map) {
+                       $$txt .= "\t;\tcurl -d '' $base_url$_.sql.gz | \\\n" .
+                               "\t;\tgzip -dc | \\\n" .
+                               "\t;\tsqlite3 $inboxdir/$_.sqlite3\n";
+                       $$txt .= "\taltid = serial:$_:file=$_.sqlite3\n";
+               }
+       }
+
+       for my $k (qw(filter newsgroup obfuscate replyto)) {
+               defined(my $v = $ibx->{$k}) or next;
+               $$txt .= "\t$k = $v\n";
+       }
+       $$txt .= "\tnntpmirror = $_\n" for (@{$ibx->nntp_url});
+
+       # note: this doesn't preserve cgitrc layout, since we parse cgitrc
+       # and drop the original structure
+       if (defined(my $cr = $ibx->{coderepo})) {
+               $$txt .= "\tcoderepo = $_\n" for @$cr;
+               $$txt .= <<'EOF';
+
+; `coderepo' entries allows blob reconstruction via patch emails if
+; the inbox is indexed with Xapian.  `@@ <from-range> <to-range> @@'
+; line number ranges in `[PATCH]' emails link to /$INBOX_NAME/$OID/s/,
+; an HTTP endpoint which reconstructs git blobs via git-apply(1).
+EOF
+               my $pi_cfg = $ctx->{www}->{pi_cfg};
+               for my $cr_name (@$cr) {
+                       my $urls = $pi_cfg->get_all("coderepo.$cr_name.cgiturl");
+                       my $path = "/path/to/$cr_name";
+                       $cr_name = dq_escape($cr_name);
+
+                       $$txt .= qq([coderepo "$cr_name"]\n);
+                       if ($urls && scalar(@$urls)) {
+                               $$txt .= "\t; ";
+                               $$txt .= join(" ||\n\t;\t", map {;
+                                       my $dst = $path;
+                                       if ($path !~ m![a-z0-9_/\.\-]!i) {
+                                               $dst = '"'.dq_escape($dst).'"';
+                                       }
+                                       qq(git clone $_ $dst);
+                               } @$urls);
+                               $$txt .= "\n";
+                       }
+                       $$txt .= "\tdir = $path\n";
+                       $$txt .= "\tcgiturl = https://example.com/";
+                       $$txt .= uri_escape_utf8($cr_name, URI_PATH)."\n";
+               }
+       }
+       1;
+}
+
+sub _default_text ($$$$) {
+       my ($ctx, $key, $hdr, $txt) = @_;
+       return _colors_help($ctx, $txt) if $key eq 'color';
+       return inbox_config($ctx, $hdr, $txt) if $key eq 'config';
        return if $key ne 'help'; # TODO more keys?
 
        return if $key ne 'help'; # TODO more keys?
 
-       my $ibx = $ctx->{-inbox};
+       my $ibx = $ctx->{ibx};
        my $base_url = $ibx->base_url($ctx->{env});
        $$txt .= "public-inbox help for $base_url\n";
        $$txt .= <<EOF;
        my $base_url = $ibx->base_url($ctx->{env});
        $$txt .= "public-inbox help for $base_url\n";
        $$txt .= <<EOF;
@@ -122,7 +249,7 @@ EOF
 
        # n.b. we use the Xapian DB for any regeneratable,
        # order-of-arrival-independent data.
 
        # n.b. we use the Xapian DB for any regeneratable,
        # order-of-arrival-independent data.
-       my $srch = $ibx->search;
+       my $srch = $ibx->isrch;
        if ($srch) {
                $$txt .= <<EOF;
 search
        if ($srch) {
                $$txt .= <<EOF;
 search
@@ -134,7 +261,7 @@ search
     in other search engines.
 
     We also support search prefixes to limit the scope of the
     in other search engines.
 
     We also support search prefixes to limit the scope of the
-    search to certain fields using prefixes.
+    search to certain fields.
 
     Prefixes supported in this installation include:
 
 
     Prefixes supported in this installation include:
 
@@ -142,11 +269,20 @@ EOF
                _srch_prefix($srch, $txt);
 
                $$txt .= <<EOF;
                _srch_prefix($srch, $txt);
 
                $$txt .= <<EOF;
+
+    Most prefixes are probabilistic, meaning they support stemming
+    and wildcards ('*').  Ranges (such as 'd:') and boolean prefixes
+    do not support stemming or wildcards.
     The upstream Xapian query parser documentation fully explains
     the query syntax:
 
        $QP_URL
 
     The upstream Xapian query parser documentation fully explains
     the query syntax:
 
        $QP_URL
 
+EOF
+       } # $srch
+       my $over = $ibx->over;
+       if ($over) {
+               $$txt .= <<EOF;
 message threading
 -----------------
 
 message threading
 -----------------
 
@@ -178,6 +314,10 @@ message threading
        $WIKI_URL/Atom_(standard)
        https://tools.ietf.org/html/rfc4287
 
        $WIKI_URL/Atom_(standard)
        https://tools.ietf.org/html/rfc4287
 
+      Atom Threading Extensions (RFC4685) is supported:
+
+       https://tools.ietf.org/html/rfc4685
+
     Finally, the gzipped mbox for a thread is available for
     downloading and importing into your favorite mail client:
 
     Finally, the gzipped mbox for a thread is available for
     downloading and importing into your favorite mail client:
 
@@ -188,15 +328,19 @@ message threading
 
        $WIKI_URL/Mbox
 
 
        $WIKI_URL/Mbox
 
+EOF
+       } # $over
+
+       $$txt .= <<EOF;
 contact
 -------
 
     This help text is maintained by public-inbox developers
     reachable via plain-text email at: meta\@public-inbox.org
 contact
 -------
 
     This help text is maintained by public-inbox developers
     reachable via plain-text email at: meta\@public-inbox.org
+    Their inbox is archived at: https://public-inbox.org/meta/
 
 EOF
        # TODO: support admin contact info in ~/.public-inbox/config
 
 EOF
        # TODO: support admin contact info in ~/.public-inbox/config
-       }
        1;
 }
 
        1;
 }