X-Git-Url: http://www.git.stargrave.org/?a=blobdiff_plain;f=lib%2FPublicInbox%2FView.pm;h=94058ed09ecd8039c678e271ace689a3b131f44d;hb=fad9acd35e56a289ade90a62d056b2a6663d448c;hp=133c30a8e517e70e879a7fc9bc9a7c252d504f77;hpb=6efc0df8d3e00da0257b131e96f74d18fce290ab;p=public-inbox.git diff --git a/lib/PublicInbox/View.pm b/lib/PublicInbox/View.pm index 133c30a8..94058ed0 100644 --- a/lib/PublicInbox/View.pm +++ b/lib/PublicInbox/View.pm @@ -9,13 +9,13 @@ use warnings; use PublicInbox::MsgTime qw(msg_datestamp); use PublicInbox::Hval qw/ascii_html obfuscate_addrs/; use PublicInbox::Linkify; -use PublicInbox::MID qw/mid_clean id_compress mid_mime mid_escape mids - references/; +use PublicInbox::MID qw/id_compress mid_escape mids references/; use PublicInbox::MsgIter; use PublicInbox::Address; use PublicInbox::WwwStream; use PublicInbox::Reply; require POSIX; +use Time::Local qw(timegm); use constant INDENT => ' '; use constant TCHILD => '` '; @@ -24,7 +24,7 @@ sub th_pfx ($) { $_[0] == 0 ? '' : TCHILD }; # public functions: (unstable) sub msg_html { - my ($ctx, $mime, $more) = @_; + my ($ctx, $mime, $more, $smsg) = @_; my $hdr = $mime->header_obj; my $ibx = $ctx->{-inbox}; my $obfs_ibx = $ctx->{-obfs_ibx} = $ibx->{obfuscate} ? $ibx : undef; @@ -33,7 +33,9 @@ sub msg_html { PublicInbox::WwwStream->response($ctx, 200, sub { my ($nr, undef) = @_; if ($nr == 1) { - $tip . multipart_text_as_html($mime, '', $obfs_ibx) . + # $more cannot be true w/o $smsg being defined: + my $upfx = $more ? '../'.mid_escape($smsg->mid).'/' : ''; + $tip . multipart_text_as_html($mime, $upfx, $obfs_ibx) . '
' } elsif ($more && @$more) { ++$end; @@ -56,45 +58,36 @@ sub msg_page { my ($ctx) = @_; my $mid = $ctx->{mid}; my $ibx = $ctx->{-inbox}; - my ($first, $more, $head, $tail, $db); + my ($first, $more); + my $smsg; if (my $srch = $ibx->search) { - $srch->retry_reopen(sub { - ($head, $tail, $db) = $srch->each_smsg_by_mid($mid); - for (; !defined($first) && $head != $tail; $head++) { - my @args = ($head, $db, $mid); - my $smsg = PublicInbox::SearchMsg->get(@args); - $first = $ibx->msg_by_smsg($smsg); - } - if ($head != $tail) { - $more = [ $head, $tail, $db ]; - } - }); + my ($id, $prev); + $smsg = $srch->next_by_mid($mid, \$id, \$prev); + $first = $ibx->msg_by_smsg($smsg) if $smsg; + if ($first) { + my $next = $srch->next_by_mid($mid, \$id, \$prev); + $more = [ $id, $prev, $next ] if $next; + } return unless $first; } else { $first = $ibx->msg_by_mid($mid) or return; } - msg_html($ctx, PublicInbox::MIME->new($first), $more); + msg_html($ctx, PublicInbox::MIME->new($first), $more, $smsg); } sub msg_html_more { my ($ctx, $more, $nr) = @_; my $str = eval { - my $smsg; - my ($head, $tail, $db) = @$more; + my ($id, $prev, $smsg) = @$more; my $mid = $ctx->{mid}; - for (; !defined($smsg) && $head != $tail; $head++) { - my $m = PublicInbox::SearchMsg->get($head, $db, $mid); - $smsg = $ctx->{-inbox}->smsg_mime($m); - } - if ($head == $tail) { # done - @$more = (); - } else { - $more->[0] = $head; - } + $smsg = $ctx->{-inbox}->smsg_mime($smsg); + my $next = $ctx->{srch}->next_by_mid($mid, \$id, \$prev); + @$more = $next ? ($id, $prev, $next) : (); if ($smsg) { my $mime = $smsg->{mime}; + my $upfx = '../' . mid_escape($smsg->mid) . '/'; _msg_html_prepare($mime->header_obj, $ctx, $more, $nr) . - multipart_text_as_html($mime, '', + multipart_text_as_html($mime, $upfx, $ctx->{-obfs_ibx}) . '
' } else { @@ -405,9 +398,7 @@ sub thread_html { my ($ctx) = @_; my $mid = $ctx->{mid}; my $srch = $ctx->{srch}; - my $sres = $srch->get_thread($mid); - my $msgs = load_results($srch, $sres); - my $nr = $sres->{total}; + my ($nr, $msgs) = $srch->get_thread($mid); return missing_thread($ctx) if $nr == 0; my $skel = '
';
 	$skel .= $nr == 1 ? 'only message in thread' : 'end of thread';
@@ -426,7 +417,7 @@ sub thread_html {
 	$ctx->{mapping} = {};
 	$ctx->{s_nr} = "$nr+ messages in thread";
 
-	my $rootset = thread_results($msgs, $srch);
+	my $rootset = thread_results($ctx, $msgs);
 
 	# reduce hash lookups in pre_thread->skel_dump
 	my $inbox = $ctx->{-inbox};
@@ -646,8 +637,7 @@ sub thread_skel {
 	my ($dst, $ctx, $hdr, $tpfx) = @_;
 	my $srch = $ctx->{srch};
 	my $mid = mids($hdr)->[0];
-	my $sres = $srch->get_thread($mid);
-	my $nr = $sres->{total};
+	my ($nr, $msgs) = $srch->get_thread($mid);
 	my $expand = qq(expand[flat) .
 	                qq(|nested]  ) .
 			qq(mbox.gz  ) .
@@ -677,12 +667,11 @@ sub thread_skel {
 	$ctx->{prev_attr} = '';
 	$ctx->{prev_level} = 0;
 	$ctx->{dst} = $dst;
-	$sres = load_results($srch, $sres);
 
 	# reduce hash lookups in skel_dump
 	my $ibx = $ctx->{-inbox};
 	$ctx->{-obfs_ibx} = $ibx->{obfuscate} ? $ibx : undef;
-	walk_thread(thread_results($sres, $srch), $ctx, *skel_dump);
+	walk_thread(thread_results($ctx, $msgs), $ctx, *skel_dump);
 
 	$ctx->{parent_msg} = $parent;
 }
@@ -798,16 +787,10 @@ sub indent_for {
 	$level ? INDENT x ($level - 1) : '';
 }
 
-sub load_results {
-	my ($srch, $sres) = @_;
-	my $msgs = delete $sres->{msgs};
-	$srch->retry_reopen(sub { [ map { $_->mid; $_ } @$msgs ] });
-}
-
 sub thread_results {
-	my ($msgs, $srch) = @_;
+	my ($ctx, $msgs) = @_;
 	require PublicInbox::SearchThread;
-	PublicInbox::SearchThread::thread($msgs, *sort_ds, $srch);
+	PublicInbox::SearchThread::thread($msgs, *sort_ds, $ctx->{-inbox});
 }
 
 sub missing_thread {
@@ -948,7 +931,7 @@ sub acc_topic {
 	my ($ctx, $level, $node) = @_;
 	my $srch = $ctx->{srch};
 	my $mid = $node->{id};
-	my $x = $node->{smsg} || $srch->lookup_mail($mid);
+	my $x = $node->{smsg} || $ctx->{-inbox}->smsg_by_mid($mid);
 	my ($subj, $ds);
 	my $topic;
 	if ($x) {
@@ -1039,45 +1022,82 @@ sub dump_topics {
 	200;
 }
 
+sub ts2str ($) {
+	my ($ts) = @_;
+	POSIX::strftime('%Y%m%d%H%M%S', gmtime($ts));
+}
+
+sub str2ts ($) {
+	my ($yyyy, $mon, $dd, $hh, $mm, $ss) = unpack('A4A2A2A2A2A2', $_[0]);
+	timegm($ss, $mm, $hh, $dd, $mon - 1, $yyyy);
+}
+
+sub pagination_footer ($$) {
+	my ($ctx, $latest) = @_;
+	delete $ctx->{qp} or return;
+	my $next = $ctx->{next_page} || '';
+	my $prev = $ctx->{prev_page} || '';
+	if ($prev) {
+		$next = $next ? "$next " : '     ';
+		$prev .= qq! latest!;
+	}
+	"
page: $next$prev
"; +} + sub index_nav { # callback for WwwStream my (undef, $ctx) = @_; - delete $ctx->{qp} or return; - my ($next, $prev); - $next = $prev = ' '; - my $latest = ''; + pagination_footer($ctx, '.') +} + +sub paginate_recent ($) { + my ($ctx) = @_; + my $t = $ctx->{qp}->{t} || ''; + my $lim = 200; # this is our window + my $opts = { limit => $lim }; + my ($after, $before); + + # Xapian uses '..' but '-' is perhaps friendier to URL linkifiers + # if only $after exists "YYYYMMDD.." because "." could be skipped + # if interpreted as an end-of-sentence + $t =~ s/\A(\d{8,14})-// and $after = str2ts($1); + $t =~ /\A(\d{8,14})\z/ and $before = str2ts($1); - my $next_o = $ctx->{-next_o}; - if ($next_o) { - $next = qq!next!; + my $ibx = $ctx->{-inbox}; + my $msgs = $ibx->recent($opts, $after, $before); + my $nr = scalar @$msgs; + if ($nr < $lim && defined($after)) { + $after = $before = undef; + $msgs = $ibx->recent($opts); + $nr = scalar @$msgs; } - if (my $cur_o = $ctx->{-cur_o}) { - $latest = qq! latest!; - - my $o = $cur_o - ($next_o - $cur_o); - if ($o > 0) { - $prev = qq!prev!; - } elsif ($o == 0) { - $prev = qq!prev!; + my $more = $nr == $lim; + my ($newest, $oldest); + if ($nr) { + $newest = $msgs->[0]->{ts}; + $oldest = $msgs->[-1]->{ts}; + # if we only had $after, our SQL query in ->recent ordered + if ($newest < $oldest) { + ($oldest, $newest) = ($newest, $oldest); + $more = 0 if defined($after) && $after < $oldest; } } - "
page: $next $prev$latest
"; + if (defined($oldest) && $more) { + my $s = ts2str($oldest); + $ctx->{next_page} = qq!next!; + } + if (defined($newest) && (defined($before) || defined($after))) { + my $s = ts2str($newest); + $ctx->{prev_page} = qq!prev!; + } + $msgs; } sub index_topics { my ($ctx) = @_; - my ($off) = (($ctx->{qp}->{o} || '0') =~ /(\d+)/); - my $opts = { offset => $off, limit => 200 }; - - $ctx->{order} = []; - my $srch = $ctx->{srch}; - my $sres = $srch->query('', $opts); - my $nr = scalar @{$sres->{msgs}}; - if ($nr) { - $sres = load_results($srch, $sres); - walk_thread(thread_results($sres, $srch), $ctx, *acc_topic); + my $msgs = paginate_recent($ctx); + if (@$msgs) { + walk_thread(thread_results($ctx, $msgs), $ctx, *acc_topic); } - $ctx->{-next_o} = $off+ $nr; - $ctx->{-cur_o} = $off; PublicInbox::WwwStream->response($ctx, dump_topics($ctx), *index_nav); }