+use parent 'PublicInbox::GzipFilter';
+use PublicInbox::MID qw/mid_escape/;
+use PublicInbox::Hval qw/to_filename/;
+use PublicInbox::Smsg;
+use PublicInbox::Eml;
+
+# called by PSGI server as body response
+# this gets called twice for every message, once to return the header,
+# once to retrieve the body
+sub getline {
+ my ($ctx) = @_; # ctx
+ my $smsg = $ctx->{smsg} or return;
+ my $ibx = $ctx->{ibx};
+ my $eml = delete($ctx->{eml}) // $ibx->smsg_eml($smsg) // return;
+ if (($ctx->{smsg} = $ibx->over->next_by_mid(@{$ctx->{next_arg}}))) {
+ $ctx->translate(msg_hdr($ctx, $eml), msg_body($eml));
+ } else { # last message
+ $ctx->zflush(msg_hdr($ctx, $eml), msg_body($eml));
+ }
+}
+
+# called by PublicInbox::DS::write after http->next_step
+sub async_next {
+ my ($http) = @_; # PublicInbox::HTTP
+ my $ctx = $http->{forward} or return; # client aborted
+ eval {
+ my $smsg = $ctx->{smsg} or return $ctx->close;
+ $ctx->smsg_blob($smsg);
+ };
+ warn "E: $@" if $@;
+}
+
+sub async_eml { # for async_blob_cb
+ my ($ctx, $eml) = @_;
+ my $smsg = delete $ctx->{smsg};
+ # next message
+ $ctx->{smsg} = $ctx->{ibx}->over->next_by_mid(@{$ctx->{next_arg}});
+ local $ctx->{eml} = $eml; # for mbox_hdr
+ $ctx->write(msg_hdr($ctx, $eml), msg_body($eml));
+}
+
+sub mbox_hdr ($) {
+ my ($ctx) = @_;
+ my $eml = $ctx->{eml} //= $ctx->{ibx}->smsg_eml($ctx->{smsg});
+ my $fn = $eml->header_str('Subject') // '';
+ $fn =~ s/^re:\s+//i;
+ $fn = to_filename($fn) // 'no-subject';
+ my @hdr = ('Content-Type');
+ if ($ctx->{ibx}->{obfuscate}) {
+ # obfuscation is stupid, but maybe scrapers are, too...
+ push @hdr, 'application/mbox';
+ $fn .= '.mbox';
+ } else {
+ push @hdr, 'text/plain';
+ $fn .= '.txt';
+ }
+ my $cs = $ctx->{eml}->ct->{attributes}->{charset} // 'UTF-8';
+ $cs = 'UTF-8' if $cs =~ /[^a-zA-Z0-9\-\_]/; # avoid header injection
+ $hdr[-1] .= "; charset=$cs";
+ push @hdr, 'Content-Disposition', "inline; filename=$fn";
+ [ 200, \@hdr ];
+}
+
+# for rare cases where v1 inboxes aren't indexed w/ ->over at all
+sub no_over_raw ($) {
+ my ($ctx) = @_;
+ my $mref = $ctx->{ibx}->msg_by_mid($ctx->{mid}) or return;
+ my $eml = $ctx->{eml} = PublicInbox::Eml->new($mref);
+ [ @{mbox_hdr($ctx)}, [ msg_hdr($ctx, $eml) . msg_body($eml) ] ]
+}