+ delete $ctx->{obuf};
+ $$obuf .= html_footer($ctx, $ctx->{first_hdr}) if !$ctx->{smsg};
+ $$obuf;
+ } else { # called by WwwStream::async_next or getline
+ $ctx->{smsg}; # may be undef
+ }
+}
+
+# /$INBOX/$MSGID/ for unindexed v1 inboxes
+sub no_over_html ($) {
+ my ($ctx) = @_;
+ my $bref = $ctx->{ibx}->msg_by_mid($ctx->{mid}) or return; # 404
+ my $eml = PublicInbox::Eml->new($bref);
+ $ctx->{mhref} = '';
+ PublicInbox::WwwStream::init($ctx);
+ my $obuf = $ctx->{obuf} = _msg_page_prepare_obuf($eml, $ctx);
+ if (length($$obuf)) {
+ multipart_text_as_html($eml, $ctx);
+ $$obuf .= '</pre><hr>';
+ }
+ delete $ctx->{obuf};
+ eval { $$obuf .= html_footer($ctx, $eml) };
+ html_oneshot($ctx, 200, $obuf);
+}
+
+# public functions: (unstable)
+
+sub msg_page {
+ my ($ctx) = @_;
+ my $ibx = $ctx->{ibx};
+ $ctx->{-obfs_ibx} = $ibx->{obfuscate} ? $ibx : undef;
+ my $over = $ibx->over or return no_over_html($ctx);
+ my ($id, $prev);
+ my $next_arg = $ctx->{next_arg} = [ $ctx->{mid}, \$id, \$prev ];
+
+ my $smsg = $ctx->{smsg} = $over->next_by_mid(@$next_arg) or
+ return; # undef == 404
+
+ # allow user to easily browse the range around this message if
+ # they have ->over
+ $ctx->{-t_max} = $smsg->{ts};
+ PublicInbox::WwwStream::aresponse($ctx, 200, \&msg_page_i);