}
sub walk_thread {
- my ($th, $ctx, $cb) = @_;
- my @q = map { (0, $_, -1) } @{$th->{rootset}};
+ my ($rootset, $ctx, $cb) = @_;
+ my @q = map { (0, $_, -1) } @$rootset;
while (@q) {
my ($level, $node, $i) = splice(@q, 0, 3);
defined $node or next;
}
sub stream_thread ($$) {
- my ($th, $ctx) = @_;
+ my ($rootset, $ctx) = @_;
my $inbox = $ctx->{-inbox};
my $mime;
- my @q = map { (0, $_) } @{$th->{rootset}};
+ my @q = map { (0, $_) } @$rootset;
my $level;
while (@q) {
$level = shift @q;
sub thread_html {
my ($ctx) = @_;
my $mid = $ctx->{mid};
- my $sres = $ctx->{srch}->get_thread($mid, { asc => 1 });
- my $msgs = load_results($sres);
+ my $srch = $ctx->{srch};
+ my $sres = $srch->get_thread($mid);
+ my $msgs = load_results($srch, $sres);
my $nr = $sres->{total};
return missing_thread($ctx) if $nr == 0;
my $skel = '<hr><pre>';
$ctx->{mapping} = {};
$ctx->{s_nr} = "$nr+ messages in thread";
- my $th = thread_results($msgs);
- walk_thread($th, $ctx, *pre_thread);
+ my $rootset = thread_results($msgs);
+ walk_thread($rootset, $ctx, *pre_thread);
$skel .= '</pre>';
- return stream_thread($th, $ctx) unless $ctx->{flat};
+ return stream_thread($rootset, $ctx) unless $ctx->{flat};
# flat display: lazy load the full message from smsg
my $inbox = $ctx->{-inbox};
sub add_text_body {
my ($upfx, $p) = @_; # from msg_iter: [ Email::MIME, depth, @idx ]
- my ($part, $depth, @idx) = @$p;
+ my ($part, $depth) = @$p; # attachment @idx is unused
my $ct = $part->content_type || 'text/plain';
my $fn = $part->filename;
}
my @quot;
my $l = PublicInbox::Linkify->new;
- while (defined(my $cur = shift @lines)) {
+ foreach my $cur (@lines) {
if ($cur !~ /^>/) {
# show the previously buffered quote inline
flush_quote(\$s, $l, \@quot) if @quot;
}
}
- my $end = "\n";
- if (@quot) {
- $end = '';
+ if (@quot) { # ugh, top posted
flush_quote(\$s, $l, \@quot);
+ } elsif ($s =~ /\n\z/s) { # common, last line ends with a newline
+ $s;
+ } else { # some editors don't do newlines...
+ $s .= "\n";
}
- $s =~ s/[ \t]+$//sgm; # kill per-line trailing whitespace
- $s =~ s/\A\n+//s; # kill leading blank lines
- $s =~ s/\s+\z//s; # kill all trailing spaces
- $s .= $end;
}
sub _msg_html_prepare {
$ctx->{prev_attr} = '';
$ctx->{prev_level} = 0;
$ctx->{dst} = $dst;
- walk_thread(thread_results(load_results($sres)), $ctx, *skel_dump);
+ $sres = load_results($srch, $sres);
+ walk_thread(thread_results($sres), $ctx, *skel_dump);
$ctx->{parent_msg} = $parent;
}
}
sub load_results {
- my ($sres) = @_;
-
- [ map { $_->ensure_metadata; $_ } @{delete $sres->{msgs}} ];
+ my ($srch, $sres) = @_;
+ my $msgs = delete $sres->{msgs};
+ $srch->retry_reopen(sub { [ map { $_->mid; $_ } @$msgs ] });
}
sub msg_timestamp {
sub thread_results {
my ($msgs) = @_;
require PublicInbox::SearchThread;
- my $th = PublicInbox::SearchThread->new($msgs);
- $th->thread;
- $th->order(*sort_ts);
- $th
+ PublicInbox::SearchThread::thread($msgs, *sort_ts);
}
sub missing_thread {
sub fmt_ts { POSIX::strftime('%Y-%m-%d %k:%M', gmtime($_[0])) }
-sub _skel_header {
- my ($ctx, $smsg, $level) = @_;
+sub skel_dump {
+ my ($ctx, $level, $node) = @_;
+ my $smsg = $node->{smsg} or return _skel_ghost($ctx, $level, $node);
my $dst = $ctx->{dst};
my $cur = $ctx->{cur};
$$dst .= $d . "<a\nhref=\"$m\"$id>" . $end;
}
-sub skel_dump {
+sub _skel_ghost {
my ($ctx, $level, $node) = @_;
- if (my $smsg = $node->{smsg}) {
- _skel_header($ctx, $smsg, $level);
+
+ my $mid = $node->{id};
+ my $d = $ctx->{pct} ? ' [irrelevant] ' # search result
+ : ' [not found] ';
+ $d .= indent_for($level) . th_pfx($level);
+ my $upfx = $ctx->{-upfx};
+ my $m = PublicInbox::Hval->new_msgid($mid);
+ my $href = $upfx . $m->{href} . '/';
+ my $html = $m->as_html;
+
+ my $mapping = $ctx->{mapping};
+ my $map = $mapping->{$mid} if $mapping;
+ if ($map) {
+ my $id = id_compress($mid, 1);
+ $map->[0] = $d . qq{<<a\nhref=#r$id>$html</a>>\n};
+ $d .= qq{<<a\nhref="$href"\nid=r$id>$html</a>>\n};
} else {
- my $mid = $node->{id};
- my $dst = $ctx->{dst};
- my $d = $ctx->{pct} ? ' [irrelevant] ' # search result
- : ' [not found] ';
- $d .= indent_for($level) . th_pfx($level);
- my $upfx = $ctx->{-upfx};
- my $m = PublicInbox::Hval->new_msgid($mid);
- my $href = $upfx . $m->{href} . '/';
- my $html = $m->as_html;
-
- my $mapping = $ctx->{mapping};
- my $map = $mapping->{$mid} if $mapping;
- if ($map) {
- my $id = id_compress($mid, 1);
- $map->[0] = $d . qq{<<a\nhref=#r$id>$html</a>>\n};
- $d .= qq{<<a\nhref="$href"\nid=r$id>$html</a>>\n};
- } else {
- $d .= qq{<<a\nhref="$href">$html</a>>\n};
- }
- $$dst .= $d;
+ $d .= qq{<<a\nhref="$href">$html</a>>\n};
}
+ my $dst = $ctx->{dst};
+ $$dst .= $d;
}
sub sort_ts {
my $opts = { offset => $off, limit => 200 };
$ctx->{order} = [];
- my $sres = $ctx->{srch}->query('', $opts);
+ my $srch = $ctx->{srch};
+ my $sres = $srch->query('', $opts);
my $nr = scalar @{$sres->{msgs}};
if ($nr) {
- $sres = load_results($sres);
+ $sres = load_results($srch, $sres);
walk_thread(thread_results($sres), $ctx, *acc_topic);
}
$ctx->{-next_o} = $off+ $nr;