]> Sergey Matveev's repositories - public-inbox.git/blob - lib/PublicInbox/Mbox.pm
mbox: stream entire thread, regardless of size
[public-inbox.git] / lib / PublicInbox / Mbox.pm
1 # Copyright (C) 2015, all contributors <meta@public-inbox.org>
2 # License: AGPLv3 or later (https://www.gnu.org/licenses/agpl-3.0.txt)
3 # Streaming interface for formatting messages as an mbox
4 package PublicInbox::Mbox;
5 use strict;
6 use warnings;
7 use PublicInbox::MID qw/mid_clean mid_compressed mid2path/;
8 use Fcntl qw(SEEK_SET);
9
10 sub thread_mbox {
11         my ($ctx, $srch) = @_;
12         sub {
13                 my ($response) = @_; # Plack callback
14                 my $w = $response->([200, ['Content-Type' => 'text/plain']]);
15                 emit_mbox($w, $ctx, $srch);
16         }
17 }
18
19 sub emit_msg {
20         my ($fh, $simple) = @_; # Email::Simple object
21
22         # drop potentially confusing headers, ssoma already should've dropped
23         # Lines and Content-Length
24         foreach my $d (qw(Lines Content-Length Status)) {
25                 $simple->header_set($d);
26         }
27
28         my $buf = $simple->header_obj->as_string;
29         unless ($buf =~ /\AFrom /) {
30                 $fh->write("From a\@a Thu Jan  1 00:00:00 1970\n");
31         }
32         $fh->write($buf .= $simple->crlf);
33
34         $buf = $simple->body;
35         $simple->body_set('');
36         $buf =~ s/^(From )/>$1/gm;
37         $buf .= "\n" unless $buf =~ /\n\z/s;
38
39         $fh->write($buf);
40 }
41
42 sub emit_mbox {
43         my ($fh, $ctx, $srch) = @_;
44
45         require PublicInbox::GitCatFile;
46         require Email::Simple;
47         my $mid = mid_compressed($ctx->{mid});
48         my $git = PublicInbox::GitCatFile->new($ctx->{git_dir});
49         my %opts = (offset => 0);
50         my $nr;
51         do {
52                 my $res = $srch->get_thread($mid, \%opts);
53                 my $msgs = $res->{msgs};
54                 $nr = scalar @$msgs;
55                 while (defined(my $smsg = shift @$msgs)) {
56                         my $msg = eval {
57                                 my $p = 'HEAD:'.mid2path($smsg->mid);
58                                 Email::Simple->new($git->cat_file($p));
59                         };
60                         emit_msg($fh, $msg) if $msg;
61                 }
62
63                 $opts{offset} += $nr;
64         } while ($nr > 0);
65 }
66
67 1;