+ if (my $next = $node->next) {
+ my $nmid = $next->messageid;
+ $rv .= $pad . $mapping->{$nmid}->[1];
+ my $nnext = $nr_s - $idx;
+ if ($nnext > 2) {
+ my $s = ($nnext - 1).' subsequent siblings';
+ $rv .= pad_link($nmid, $level, $s);
+ } elsif (my $nn = $next->next) {
+ $rv .= $pad . $mapping->{$nn->messageid}->[1];
+ }
+ }
+ $rv .= $pad ."<a\nhref=#r$id>$s_s, $s_c; $ctx->{s_nr}</a>\n";
+}
+
+sub walk_thread {
+ my ($th, $ctx, $cb) = @_;
+ my @q = map { (0, $_) } $th->rootset;
+ while (@q) {
+ my $level = shift @q;
+ my $node = shift @q or next;
+ $cb->($ctx, $level, $node);
+ unshift @q, $level+1, $node->child, $level, $node->next;
+ }
+}
+
+sub pre_thread {
+ my ($ctx, $level, $node) = @_;
+ my $mapping = $ctx->{mapping};
+ my $idx = -1;
+ if (my $parent = $node->parent) {
+ my $m = $mapping->{$parent->messageid}->[0];
+ $idx = scalar @$m;
+ push @$m, $node;
+ }
+ $mapping->{$node->messageid} = [ [], '', $node, $idx, $level ];
+ skel_dump($ctx, $level, $node);
+}
+
+sub thread_index_entry {
+ my ($ctx, $level, $mime) = @_;
+ my ($beg, $end) = thread_adj_level($ctx, $level);
+ $beg . '<pre>' . index_entry($mime, $ctx, 0) . '</pre>' . $end;
+}
+
+sub stream_thread ($$) {
+ my ($th, $ctx) = @_;
+ my $inbox = $ctx->{-inbox};
+ my $mime;
+ my @q = map { (0, $_) } $th->rootset;
+ my $level;
+ while (@q) {
+ $level = shift @q;
+ my $node = shift @q or next;
+ unshift @q, $level+1, $node->child, $level, $node->next;
+ $mime = $inbox->msg_by_mid($node->messageid) and last;
+ }
+ return missing_thread($ctx) unless $mime;
+
+ $mime = Email::MIME->new($mime);
+ $ctx->{-title_html} = ascii_html($mime->header('Subject'));
+ $ctx->{-html_tip} = thread_index_entry($ctx, $level, $mime);
+ PublicInbox::WwwStream->response($ctx, 200, sub {
+ return unless $ctx;
+ while (@q) {
+ $level = shift @q;
+ my $node = shift @q or next;
+ unshift @q, $level+1, $node->child, $level, $node->next;
+ my $mid = $node->messageid;
+ if ($mime = $inbox->msg_by_mid($mid)) {
+ $mime = Email::MIME->new($mime);
+ return thread_index_entry($ctx, $level, $mime);
+ } else {
+ return ghost_index_entry($ctx, $level, $mid);
+ }
+ }
+ my $ret = join('', thread_adj_level($ctx, 0));
+ $ret .= ${$ctx->{dst}}; # skel
+ $ctx = undef;
+ $ret;
+ });