public-inbox.git  about / heads / tags
an "archives first" approach to mailing lists
blob 383c0250d83ccd5782b88b2b13598daecc58833a 2886 bytes (raw)
$ git show stable-1.6:lib/PublicInbox/WwwListing.pm	# shows this blob on the CLI

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
 
# Copyright (C) 2019-2020 all contributors <meta@public-inbox.org>
# License: AGPL-3.0+ <https://www.gnu.org/licenses/agpl-3.0.txt>

# Provide an HTTP-accessible listing of inboxes.
# Used by PublicInbox::WWW
package PublicInbox::WwwListing;
use strict;
use PublicInbox::Hval qw(prurl fmt_ts);
use PublicInbox::Linkify;
use PublicInbox::GzipFilter qw(gzf_maybe);
use PublicInbox::ConfigIter;
use PublicInbox::WwwStream;
use bytes (); # bytes::length

sub ibx_entry {
	my ($ctx, $ibx) = @_;
	my $mtime = $ibx->modified;
	my $ts = fmt_ts($mtime);
	my $url = prurl($ctx->{env}, $ibx->{url});
	my $tmp = <<"";
* $ts - $url
  ${\$ibx->description}

	if (defined(my $info_url = $ibx->{infourl})) {
		$tmp .= '  ' . prurl($ctx->{env}, $info_url) . "\n";
	}
	push @{$ctx->{-list}}, [ $mtime, $tmp ];
}

sub list_match_i { # ConfigIter callback
	my ($cfg, $section, $re, $ctx) = @_;
	if (defined($section)) {
		return if $section !~ m!\Apublicinbox\.([^/]+)\z!;
		my $ibx = $cfg->lookup_name($1) or return;
		if (!$ibx->{-hide}->{$ctx->hide_key} &&
					grep(/$re/, @{$ibx->{url}})) {
			$ctx->ibx_entry($ibx);
		}
	} else { # undef == "EOF"
		$ctx->{-wcb}->($ctx->psgi_triple);
	}
}

sub url_regexp {
	my ($ctx, $key, $default) = @_;
	$key //= 'publicInbox.wwwListing';
	$default //= '404';
	my $v = $ctx->{www}->{pi_config}->{lc $key} // $default;
again:
	if ($v eq 'match=domain') {
		my $h = $ctx->{env}->{HTTP_HOST} // $ctx->{env}->{SERVER_NAME};
		$h =~ s/:[0-9]+\z//;
		qr!\A(?:https?:)?//\Q$h\E(?::[0-9]+)?/!i;
	} elsif ($v eq 'all') {
		qr/./;
	} elsif ($v eq '404') {
		undef;
	} else {
		warn <<EOF;
`$v' is not a valid value for `$key'
$key be one of `all', `match=domain', or `404'
EOF
		$v = $default; # 'match=domain' or 'all'
		goto again;
	}
}

sub hide_key { 'www' }

sub response {
	my ($class, $ctx) = @_;
	bless $ctx, $class;
	my $re = $ctx->url_regexp or return $ctx->psgi_triple;
	my $iter = PublicInbox::ConfigIter->new($ctx->{www}->{pi_config},
						\&list_match_i, $re, $ctx);
	sub {
		$ctx->{-wcb} = $_[0]; # HTTP server callback
		$ctx->{env}->{'pi-httpd.async'} ?
				$iter->event_step : $iter->each_section;
	}
}

sub psgi_triple {
	my ($ctx) = @_;
	my $h = [ 'Content-Type', 'text/html; charset=UTF-8',
			'Content-Length', undef ];
	my $gzf = gzf_maybe($h, $ctx->{env});
	$gzf->zmore('<html><head><title>' .
				'public-inbox listing</title>' .
				'</head><body><pre>');
	my $code = 404;
	if (my $list = $ctx->{-list}) {
		$code = 200;
		# sort by ->modified
		@$list = map { $_->[1] } sort { $b->[0] <=> $a->[0] } @$list;
		$list = join("\n", @$list);
		my $l = PublicInbox::Linkify->new;
		$gzf->zmore($l->to_html($list));
	} else {
		$gzf->zmore('no inboxes, yet');
	}
	my $out = $gzf->zflush('</pre><hr><pre>'.
			PublicInbox::WwwStream::code_footer($ctx->{env}) .
			'</pre></body></html>');
	$h->[3] = bytes::length($out);
	[ $code, $h, [ $out ] ];
}

1;

git clone https://public-inbox.org/public-inbox.git
git clone http://7fh6tueqddpjyxjmgtdiueylzoqt6pt7hec3pukyptlmohoowvhde4yd.onion/public-inbox.git