about summary refs log tree commit homepage
path: root/lib/PublicInbox/WwwAttach.pm
diff options
context:
space:
mode:
Diffstat (limited to 'lib/PublicInbox/WwwAttach.pm')
-rw-r--r--lib/PublicInbox/WwwAttach.pm46
1 files changed, 46 insertions, 0 deletions
diff --git a/lib/PublicInbox/WwwAttach.pm b/lib/PublicInbox/WwwAttach.pm
new file mode 100644
index 00000000..5cf56a80
--- /dev/null
+++ b/lib/PublicInbox/WwwAttach.pm
@@ -0,0 +1,46 @@
+# Copyright (C) 2016 all contributors <meta@public-inbox.org>
+# License: AGPL-3.0+ <https://www.gnu.org/licenses/agpl-3.0.txt>
+
+# For retrieving attachments from messages in the WWW interface
+package PublicInbox::WwwAttach; # internal package
+use strict;
+use warnings;
+use Email::MIME;
+use Email::MIME::ContentType qw(parse_content_type);
+$Email::MIME::ContentType::STRICT_PARAMS = 0;
+use PublicInbox::MID qw(mid2path);
+use PublicInbox::MsgIter;
+
+# /$LISTNAME/$MESSAGE_ID/$IDX-$FILENAME
+sub get_attach ($$$) {
+        my ($ctx, $idx, $fn) = @_;
+        my $path = mid2path($ctx->{mid});
+
+        my $res = [ 404, [ 'Content-Type', 'text/plain' ], [ "Not found\n" ] ];
+        my $mime = $ctx->{git}->cat_file("HEAD:$path") or return $res;
+        $mime = Email::MIME->new($mime);
+        msg_iter($mime, sub {
+                my ($part, $depth, @idx) = @{$_[0]};
+                return if join('.', @idx) ne $idx;
+                $res->[0] = 200;
+                my $ct = $part->content_type;
+                $ct = parse_content_type($ct) if $ct;
+
+                # discrete == type, we remain Debian wheezy-compatible
+                if ($ct && (($ct->{discrete} || '') eq 'text')) {
+                        # display all text as text/plain:
+                        my $cset = $ct->{attributes}->{charset};
+                        if ($cset && ($cset =~ /\A[\w-]+\z/)) {
+                                $res->[1]->[1] .= qq(; charset=$cset);
+                        }
+                } else { # TODO: allow user to configure safe types
+                        $res->[1]->[1] = 'application/octet-stream';
+                }
+                $part = $part->body;
+                push @{$res->[1]}, 'Content-Length', bytes::length($part);
+                $res->[2]->[0] = $part;
+        });
+        $res;
+}
+
+1;