+ my $ctx = $self->{ctx} or return;
+ my $res;
+ my $ibx = $ctx->{-inbox};
+ my $gz = $self->{gz};
+ do {
+ # work on existing result set
+ while (defined(my $smsg = shift @{$self->{msgs}})) {
+ my $msg = eval { $ibx->msg_by_smsg($smsg) } or next;
+ $msg = Email::Simple->new($msg);
+ $gz->write(PublicInbox::Mbox::msg_str($ctx, $msg));
+
+ # use subject of first message as subject
+ if (my $hdr = delete $self->{hdr}) {
+ my $fn = set_filename($self->{fn}, $msg);
+ push @$hdr, 'Content-Disposition',
+ "inline; filename=$fn.mbox.gz";
+ return $hdr;
+ }
+ my $bref = $self->{buf};
+ if (length($$bref) >= 8192) {
+ my $ret = $$bref; # copy :<
+ ${$self->{buf}} = '';
+ return $ret;
+ }
+
+ # be fair to other clients on public-inbox-httpd:
+ return '';
+ }
+
+ # refill result set
+ $res = $self->{cb}->($self->{opts});
+ $self->{msgs} = $res->{msgs};
+ $res = scalar @{$self->{msgs}};
+ $self->{opts}->{offset} += $res;
+ } while ($res);
+ $gz->close;
+ delete $self->{ctx};
+ ${delete $self->{buf}};