use constant TCHILD => '` ';
sub th_pfx ($) { $_[0] == 0 ? '' : TCHILD };
+sub msg_html_i {
+ my ($nr, $ctx) = @_;
+ my $more = $ctx->{more};
+ if ($nr == 1) {
+ # $more cannot be true w/o $smsg being defined:
+ my $upfx = $more ? '../'.mid_escape($ctx->{smsg}->mid).'/' : '';
+ $ctx->{tip} .
+ multipart_text_as_html($ctx->{mime}, $upfx, $ctx) .
+ '</pre><hr>'
+ } elsif ($more && @$more) {
+ ++$ctx->{end_nr};
+ msg_html_more($ctx, $more, $nr);
+ } elsif ($nr == $ctx->{end_nr}) {
+ # fake an EOF if generating the footer fails;
+ # we want to at least show the message if something
+ # here crashes:
+ eval {
+ my $hdr = delete($ctx->{mime})->header_obj;
+ '<pre>' . html_footer($hdr, 1, $ctx) .
+ '</pre>' . msg_reply($ctx, $hdr)
+ };
+ } else {
+ undef
+ }
+}
+
# public functions: (unstable)
sub msg_html {
my ($ctx, $mime, $more, $smsg) = @_;
- my $hdr = $mime->header_obj;
my $ibx = $ctx->{-inbox};
$ctx->{-obfs_ibx} = $ibx->{obfuscate} ? $ibx : undef;
- my $tip = _msg_html_prepare($hdr, $ctx, $more, 0);
- my $end = 2;
- PublicInbox::WwwStream->response($ctx, 200, sub {
- my ($nr, undef) = @_;
- if ($nr == 1) {
- # $more cannot be true w/o $smsg being defined:
- my $upfx = $more ? '../'.mid_escape($smsg->mid).'/' : '';
- $tip . multipart_text_as_html($mime, $upfx, $ctx) .
- '</pre><hr>'
- } elsif ($more && @$more) {
- ++$end;
- msg_html_more($ctx, $more, $nr);
- } elsif ($nr == $end) {
- # fake an EOF if generating the footer fails;
- # we want to at least show the message if something
- # here crashes:
- eval {
- '<pre>' . html_footer($hdr, 1, $ctx) .
- '</pre>' . msg_reply($ctx, $hdr)
- };
- } else {
- undef
- }
- });
+ $ctx->{tip} = _msg_html_prepare($mime->header_obj, $ctx, $more, 0);
+ $ctx->{more} = $more;
+ $ctx->{end_nr} = 2;
+ $ctx->{smsg} = $smsg;
+ $ctx->{mime} = $mime;
+ PublicInbox::WwwStream->response($ctx, 200, \&msg_html_i);
}
sub msg_page {
$beg . '<pre>' . index_entry($smsg, $ctx, 0) . '</pre>' . $end;
}
+sub stream_thread_i { # PublicInbox::WwwStream::getline callback
+ my ($nr, $ctx) = @_;
+ return unless exists($ctx->{dst});
+ my $q = $ctx->{-queue};
+ while (@$q) {
+ my $level = shift @$q;
+ my $node = shift @$q or next;
+ my $cl = $level + 1;
+ unshift @$q, map { ($cl, $_) } @{$node->{children}};
+ if (my $smsg = $ctx->{-inbox}->smsg_mime($node->{smsg})) {
+ return thread_index_entry($ctx, $level, $smsg);
+ } else {
+ return ghost_index_entry($ctx, $level, $node);
+ }
+ }
+ join('', thread_adj_level($ctx, 0)) . ${delete $ctx->{dst}}; # skel
+}
+
sub stream_thread ($$) {
my ($rootset, $ctx) = @_;
my $ibx = $ctx->{-inbox};
my @q = map { (0, $_) } @$rootset;
- my $level;
- my $smsg;
+ my ($smsg, $level);
while (@q) {
$level = shift @q;
my $node = shift @q or next;
$ctx->{-obfs_ibx} = $ibx->{obfuscate} ? $ibx : undef;
$ctx->{-title_html} = ascii_html($smsg->subject);
$ctx->{-html_tip} = thread_index_entry($ctx, $level, $smsg);
- $smsg = undef;
- PublicInbox::WwwStream->response($ctx, 200, sub {
- return unless $ctx;
- while (@q) {
- $level = shift @q;
- my $node = shift @q or next;
- my $cl = $level + 1;
- unshift @q, map { ($cl, $_) } @{$node->{children}};
- if ($smsg = $ibx->smsg_mime($node->{smsg})) {
- return thread_index_entry($ctx, $level, $smsg);
- } else {
- return ghost_index_entry($ctx, $level, $node);
- }
- }
- my $ret = join('', thread_adj_level($ctx, 0));
- $ret .= ${$ctx->{dst}}; # skel
- $ctx = undef;
- $ret;
- });
+ $ctx->{-queue} = \@q;
+ PublicInbox::WwwStream->response($ctx, 200, \&stream_thread_i);
}
sub thread_html {
return missing_thread($ctx) unless $smsg;
$ctx->{-title_html} = ascii_html($smsg->subject);
$ctx->{-html_tip} = '<pre>'.index_entry($smsg, $ctx, scalar @$msgs);
- $smsg = undef;
- PublicInbox::WwwStream->response($ctx, 200, sub {
- return unless $msgs;
- $smsg = undef;
- while (my $m = shift @$msgs) {
- $smsg = $ibx->smsg_mime($m) and last;
- }
- return index_entry($smsg, $ctx, scalar @$msgs) if $smsg;
- $msgs = undef;
- $skel;
- });
+ $ctx->{msgs} = $msgs;
+ PublicInbox::WwwStream->response($ctx, 200, \&thread_html_i);
+}
+
+sub thread_html_i { # PublicInbox::WwwStream::getline callback
+ my ($nr, $ctx) = @_;
+ my $msgs = $ctx->{msgs} or return;
+ while (my $smsg = shift @$msgs) {
+ $ctx->{-inbox}->smsg_mime($smsg) or next;
+ return index_entry($smsg, $ctx, scalar @$msgs);
+ }
+ my ($skel) = delete @$ctx{qw(dst msgs)};
+ $$skel;
}
sub multipart_text_as_html {
sub thread_results {
my ($ctx, $msgs) = @_;
require PublicInbox::SearchThread;
- my $ibx = $ctx->{-inbox};
- my $rootset = PublicInbox::SearchThread::thread($msgs, *sort_ds, $ibx);
+ my $rootset = PublicInbox::SearchThread::thread($msgs, \&sort_ds, $ctx);
# FIXME: `tid' is broken on --reindex, so that needs to be fixed
# and preserved in the future. This bug is hidden by `sid' matches
my $obfs_ibx = $ctx->{-obfs_ibx};
obfuscate_addrs($obfs_ibx, $f) if $obfs_ibx;
- my $d = fmt_ts($smsg->{ds}) . ' ' . indent_for($level) . th_pfx($level);
+ my $d = fmt_ts($smsg->{ds});
+ my $unmatched; # if lazy-loaded by SearchThread::Msg::visible()
+ if (my $pct = $ctx->{pct}) {
+ $pct = $pct->{$smsg->{mid}};
+ if (defined $pct) {
+ $d .= (sprintf(' % 2u', $pct) . '%');
+ } else {
+ $unmatched = 1;
+ $d .= ' ';
+ }
+ }
+ $d .= ' ' . indent_for($level) . th_pfx($level);
my $attr = $f;
$ctx->{first_level} ||= $level;
# our Xapian which would've resulted in '' if it were
# really missing (and Filter rejects empty subjects)
my @subj = split(/ /, subject_normalized($smsg->subject));
-
# remove common suffixes from the subject if it matches the previous,
# so we do not show redundant text at the end.
my $prev_subj = $ctx->{prev_subj} || [];
}
my $m;
my $id = '';
- my $mapping = $ctx->{mapping};
+ my $mapping = $unmatched ? undef : $ctx->{mapping};
if ($mapping) {
my $map = $mapping->{$mid};
$id = id_compress($mid, 1);
my ($ctx, $level, $node) = @_;
my $mid = $node->{id};
- my $d = $ctx->{pct} ? ' [irrelevant] ' # search result
- : ' [not found] ';
+ my $d = ' [not found] ';
+ $d .= ' ' if exists $ctx->{pct};
$d .= indent_for($level) . th_pfx($level);
my $upfx = $ctx->{-upfx};
my $m = PublicInbox::Hval->new_msgid($mid);