X-Git-Url: http://www.git.stargrave.org/?a=blobdiff_plain;f=lib%2FPublicInbox%2FMbox.pm;h=2ea326a5a87fbf8788064e0be61819c8fe79b8da;hb=ec24b4af88d7922e4bf9846e76b9455fb6a5bda4;hp=9dad0f6da25dc0c28c26484e1254b81dabafbaeb;hpb=e358bd7a3833f8c5bf9db57d228888f9c5f3692e;p=public-inbox.git diff --git a/lib/PublicInbox/Mbox.pm b/lib/PublicInbox/Mbox.pm index 9dad0f6d..2ea326a5 100644 --- a/lib/PublicInbox/Mbox.pm +++ b/lib/PublicInbox/Mbox.pm @@ -6,16 +6,44 @@ package PublicInbox::Mbox; use strict; use warnings; -use PublicInbox::MID qw/mid_clean/; -use URI::Escape qw/uri_escape_utf8/; -use Plack::Util; -require Email::Simple; +use PublicInbox::MID qw/mid_clean mid_escape/; +use PublicInbox::Hval qw/to_filename/; +use Email::Simple; +use Email::MIME::Encode; + +sub subject_fn ($) { + my ($simple) = @_; + my $fn = $simple->header('Subject'); + return 'no-subject' unless defined($fn); + + # no need for full Email::MIME, here + if ($fn =~ /=\?/) { + eval { $fn = Encode::decode('MIME-Header', $fn) }; + $fn = 'no-subject' if $@; + } + $fn =~ s/^re:\s+//i; + $fn = to_filename($fn); + $fn eq '' ? 'no-subject' : $fn; +} sub emit1 { my ($ctx, $msg) = @_; $msg = Email::Simple->new($msg); - # single message should be easily renderable in browsers - [200, ['Content-Type', 'text/plain'], [ msg_str($ctx, $msg)] ] + my $fn = subject_fn($msg); + my @hdr = ('Content-Type'); + if ($ctx->{-inbox}->{obfuscate}) { + # obfuscation is stupid, but maybe scrapers are, too... + push @hdr, 'application/mbox'; + $fn .= '.mbox'; + } else { + push @hdr, 'text/plain'; + $fn .= '.txt'; + } + push @hdr, 'Content-Disposition', "inline; filename=$fn"; + + # single message should be easily renderable in browsers, + # unless obfuscation is enabled :< + [ 200, \@hdr, [ msg_str($ctx, $msg) ] ] } sub msg_str { @@ -30,7 +58,7 @@ sub msg_str { my $ibx = $ctx->{-inbox}; my $base = $ibx->base_url($ctx->{env}); my $mid = mid_clean($header_obj->header('Message-ID')); - $mid = uri_escape_utf8($mid); + $mid = mid_escape($mid); my @append = ( 'Archived-At', "<$base$mid/>", 'List-Archive', "<$base>", @@ -67,9 +95,7 @@ sub thread_mbox { return sub { need_gzip(@_) } if $@; my $cb = sub { $srch->get_thread($ctx->{mid}, @_) }; - # http://www.iana.org/assignments/media-types/application/gzip - [200, ['Content-Type' => 'application/gzip'], - PublicInbox::MboxGz->new($ctx, $cb) ]; + PublicInbox::MboxGz->response($ctx, $cb); } sub emit_range { @@ -83,11 +109,9 @@ sub emit_range { } else { return [404, [qw(Content-Type text/plain)], []]; } - my $cb = sub { $ctx->{srch}->query($query, @_) }; - # http://www.iana.org/assignments/media-types/application/gzip - [200, [qw(Content-Type application/gzip)], - PublicInbox::MboxGz->new($ctx, $cb) ]; + my $cb = sub { $ctx->{srch}->query($query, @_) }; + PublicInbox::MboxGz->response($ctx, $cb); } sub need_gzip { @@ -117,10 +141,19 @@ sub new { cb => $cb, ctx => $ctx, msgs => [], - opts => { asc => 1, offset => 0 }, + opts => { offset => 0 }, }, $class; } +sub response { + my ($class, $ctx, $cb) = @_; + my $body = $class->new($ctx, $cb); + # http://www.iana.org/assignments/media-types/application/gzip + $body->{hdr} = [ 'Content-Type', 'application/gzip' ]; + my $hdr = $body->getline; # fill in Content-Disposition filename + [ 200, $hdr, $body ]; +} + # called by Plack::Util::foreach or similar sub getline { my ($self) = @_; @@ -129,17 +162,31 @@ sub getline { 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_mid($smsg->mid) } or next; + 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 = PublicInbox::Mbox::subject_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}};