+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;
+ });
+}