lib/PublicInbox/Listener.pm
lib/PublicInbox/MDA.pm
lib/PublicInbox/MID.pm
+lib/PublicInbox/MIME.pm
lib/PublicInbox/Mbox.pm
lib/PublicInbox/MsgIter.pm
lib/PublicInbox/Msgmap.pm
t/main-bin/spamc
t/mda.t
t/mid.t
+t/mime.t
t/msg_iter.t
t/msgmap.t
t/nntp.t
package PublicInbox::Feed;
use strict;
use warnings;
-use Email::MIME;
+use PublicInbox::MIME;
use PublicInbox::View;
use PublicInbox::WwwAtomStream;
PublicInbox::WwwAtomStream->response($ctx, 200, sub {
while (my $msg = shift @$msgs) {
$msg = $ibx->msg_by_smsg($msg) and
- return Email::MIME->new($msg);
+ return PublicInbox::MIME->new($msg);
}
});
}
sub do_cat_mail {
my ($ibx, $path) = @_;
my $mime = eval { $ibx->msg_by_path($path) } or return;
- Email::MIME->new($mime);
+ PublicInbox::MIME->new($mime);
}
1;
# so in multipart (e.g. GPG-signed) messages, the list trailer
# becomes invisible to MIME-aware email clients.
if ($s =~ s/$l0\n$l1\n$l2\n$l3\n($l4\n)?\z//os) {
- $mime = Email::MIME->new(\$s);
+ $mime = PublicInbox::MIME->new(\$s);
}
$self->ACCEPT($mime);
}
$n = read($r, my $lf, 1);
defined($n) or die "read final byte of cat-blob failed: $!";
die "bad read on final byte: <$lf>" if $lf ne "\n";
- my $cur = Email::MIME->new($buf);
+ my $cur = PublicInbox::MIME->new($buf);
my $cur_s = $cur->header('Subject');
$cur_s = '' unless defined $cur_s;
my $cur_m = $mime->header('Subject');
--- /dev/null
+# This library is free software; you can redistribute it and/or modify
+# it under the same terms as Perl itself.
+#
+# The license for this file differs from the rest of public-inbox.
+#
+# It monkey patches the "parts_multipart" subroutine with patches
+# from Matthew Horsfall <wolfsage@gmail.com> at:
+#
+# git clone --mirror https://github.com/rjbs/Email-MIME.git refs/pull/28/head
+#
+# commit fe0eb870ab732507aa39a1070a2fd9435c7e4877
+# ("Make sure we don't modify the body of a message when injecting a header.")
+# commit 981d8201a7239b02114489529fd366c4c576a146
+# ("GH #14 - Handle CRLF emails properly.")
+# commit 2338d93598b5e8432df24bda8dfdc231bdeb666e
+# ("GH #14 - Support multipart messages without content-type in subparts.")
+#
+# For Email::MIME >= 1.923 && < 1.935,
+# commit dcef9be66c49ae89c7a5027a789bbbac544499ce
+# ("removing all trailing newlines was too much")
+# is also included
+package PublicInbox::MIME;
+use strict;
+use warnings;
+use base qw(Email::MIME);
+
+if ($Email::MIME::VERSION <= 1.937) {
+sub parts_multipart {
+ my $self = shift;
+ my $boundary = $self->{ct}->{attributes}->{boundary};
+
+ # Take a message, join all its lines together. Now try to Email::MIME->new
+ # it with 1.861 or earlier. Death! It tries to recurse endlessly on the
+ # body, because every time it splits on boundary it gets itself. Obviously
+ # that means it's a bogus message, but a mangled result (or exception) is
+ # better than endless recursion. -- rjbs, 2008-01-07
+ return $self->parts_single_part
+ unless $boundary and $self->body_raw =~ /^--\Q$boundary\E\s*$/sm;
+
+ $self->{body_raw} = $self->SUPER::body;
+
+ # rfc1521 7.2.1
+ my ($body, $epilogue) = split /^--\Q$boundary\E--\s*$/sm, $self->body_raw, 2;
+
+ # Split on boundaries, but keep blank lines after them intact
+ my @bits = split /^--\Q$boundary\E\s*?(?=$self->{mycrlf})/m, ($body || '');
+
+ $self->SUPER::body_set(undef);
+
+ # If there are no headers in the potential MIME part, it's just part of the
+ # body. This is a horrible hack, although it's debatable whether it was
+ # better or worse when it was $self->{body} = shift @bits ... -- rjbs,
+ # 2006-11-27
+ $self->SUPER::body_set(shift @bits) if ($bits[0] || '') !~ /.*:.*/;
+
+ my $bits = @bits;
+
+ my @parts;
+ for my $bit (@bits) {
+ # Parts don't need headers. If they don't have them, they look like this:
+ #
+ # --90e6ba6e8d06f1723604fc1b809a
+ #
+ # Part 2
+ #
+ # Part 2a
+ #
+ # $bit will contain two new lines before Part 2.
+ #
+ # Anything with headers will only have one new line.
+ #
+ # RFC 1341 Section 7.2 says parts without headers are to be considered
+ # plain US-ASCII text. -- alh
+ # 2016-08-01
+ my $added_header;
+
+ if ($bit =~ /^(?:$self->{mycrlf}){2}/) {
+ $bit = "Content-type: text/plain; charset=us-ascii" . $bit;
+
+ $added_header = 1;
+ }
+
+ $bit =~ s/\A[\n\r]+//smg;
+ $bit =~ s/(?<!\x0d)$self->{mycrlf}\Z//sm;
+
+ my $email = (ref $self)->new($bit);
+
+ if ($added_header) {
+ # Remove our changes so we don't change the raw email content
+ $email->header_str_set('Content-Type');
+ }
+
+ push @parts, $email;
+ }
+
+ $self->{parts} = \@parts;
+
+ return @{ $self->{parts} };
+}
+}
+
+1;
use warnings;
use base qw(Exporter);
our @EXPORT = qw(msg_iter);
-use Email::MIME;
-use Scalar::Util qw(readonly);
-
-# Workaround Email::MIME versions without
-# commit dcef9be66c49ae89c7a5027a789bbbac544499ce
-# ("removing all trailing newlines was too much")
-# This is necessary for Debian jessie
-my $bad = 1.923;
-my $good = 1.935;
-my $ver = $Email::MIME::VERSION;
-my $extra_nl = 1 if ($ver >= $bad && $ver < $good);
+use PublicInbox::MIME;
# Like Email::MIME::walk_parts, but this is:
# * non-recursive
@sub = map { [ $_, $depth, @idx, ++$i ] } @sub;
@parts = (@sub, @parts);
} else {
- if ($extra_nl) {
- my $lf = $part->{mycrlf};
- my $bref = $part->{body};
- if (readonly($$bref)) {
- my $s = $$bref . $lf;
- $part->{body} = \$s;
- } else {
- $$bref .= $lf;
- }
- }
$cb->($p);
}
}
use Search::Xapian qw/:standard/;
use PublicInbox::SearchMsg;
-use Email::MIME;
+use PublicInbox::MIME;
use PublicInbox::MID qw/mid_clean id_compress/;
# This is English-only, everything else is non-standard and may be confused as
use strict;
use warnings;
use Fcntl qw(:flock :DEFAULT);
-use Email::MIME;
+use PublicInbox::MIME;
use Email::MIME::ContentType;
$Email::MIME::ContentType::STRICT_PARAMS = 0;
use base qw(PublicInbox::Search);
my $str = $git->cat_file($blob, $sizeref);
# fixup bugs from import:
$$str =~ s/\A[\r\n]*From [^\r\n]*\r?\n//s;
- Email::MIME->new($str);
+ PublicInbox::MIME->new($str);
};
$@ ? undef : $mime;
}
use PublicInbox::View;
use PublicInbox::WwwAtomStream;
use PublicInbox::MID qw(mid2path mid_mime mid_clean mid_escape);
-use Email::MIME;
+use PublicInbox::MIME;
require PublicInbox::Git;
require PublicInbox::SearchThread;
our $LIM = 50;
$mime = $inbox->msg_by_smsg($mime) and last;
}
if ($mime) {
- $mime = Email::MIME->new($mime);
+ $mime = PublicInbox::MIME->new($mime);
return PublicInbox::View::index_entry($mime, $ctx,
scalar @$msgs);
}
while (my $x = shift @items) {
$x = load_doc_retry($srch, $x);
$x = $ibx->msg_by_smsg($x) and
- return Email::MIME->new($x);
+ return PublicInbox::MIME->new($x);
}
return undef;
});
}
return missing_thread($ctx) unless $mime;
- $mime = Email::MIME->new($mime);
+ $mime = PublicInbox::MIME->new($mime);
$ctx->{-title_html} = ascii_html($mime->header('Subject'));
$ctx->{-html_tip} = thread_index_entry($ctx, $level, $mime);
PublicInbox::WwwStream->response($ctx, 200, sub {
unshift @q, map { ($cl, $_) } @{$node->{children}};
my $mid = $node->{id};
if ($mime = $inbox->msg_by_smsg($node->{smsg})) {
- $mime = Email::MIME->new($mime);
+ $mime = PublicInbox::MIME->new($mime);
return thread_index_entry($ctx, $level, $mime);
} else {
return ghost_index_entry($ctx, $level, $node);
$mime = $inbox->msg_by_smsg($mime) and last;
}
return missing_thread($ctx) unless $mime;
- $mime = Email::MIME->new($mime);
+ $mime = PublicInbox::MIME->new($mime);
$ctx->{-title_html} = ascii_html($mime->header('Subject'));
$ctx->{-html_tip} = '<pre>'.index_entry($mime, $ctx, scalar @$msgs);
$mime = undef;
$mime = $inbox->msg_by_smsg($mime) and last;
}
if ($mime) {
- $mime = Email::MIME->new($mime);
+ $mime = PublicInbox::MIME->new($mime);
return index_entry($mime, $ctx, scalar @$msgs);
}
$msgs = undef;
require PublicInbox::Feed;
require PublicInbox::View;
require PublicInbox::SearchThread;
- require Email::MIME;
+ require PublicInbox::MIME;
require Digest::SHA;
require POSIX;
my $x = mid2blob($ctx) or return r404($ctx);
require PublicInbox::View;
- require Email::MIME;
- my $mime = Email::MIME->new($x);
+ require PublicInbox::MIME;
+ my $mime = PublicInbox::MIME->new($x);
searcher($ctx);
PublicInbox::View::msg_html($ctx, $mime);
}
package PublicInbox::WatchMaildir;
use strict;
use warnings;
-use Email::MIME;
+use PublicInbox::MIME;
use Email::MIME::ContentType;
$Email::MIME::ContentType::STRICT_PARAMS = 0; # user input is imperfect
use PublicInbox::Git;
local $/;
my $str = <$fh>;
$str or return;
- return Email::MIME->new(\$str);
+ return PublicInbox::MIME->new(\$str);
} elsif ($!{ENOENT}) {
return;
} else {
my ($mime) = @_;
my $tmp = '';
if ($sc->spamcheck($mime, \$tmp)) {
- return Email::MIME->new(\$tmp);
+ return PublicInbox::MIME->new(\$tmp);
}
warn $mime->header('Message-ID')." failed spam check\n";
undef;
package PublicInbox::WwwAttach; # internal package
use strict;
use warnings;
-use Email::MIME;
+use PublicInbox::MIME;
use Email::MIME::ContentType qw(parse_content_type);
$Email::MIME::ContentType::STRICT_PARAMS = 0;
use PublicInbox::MsgIter;
my ($ctx, $idx, $fn) = @_;
my $res = [ 404, [ 'Content-Type', 'text/plain' ], [ "Not found\n" ] ];
my $mime = $ctx->{-inbox}->msg_by_mid($ctx->{mid}) or return $res;
- $mime = Email::MIME->new($mime);
+ $mime = PublicInbox::MIME->new($mime);
msg_iter($mime, sub {
my ($part, $depth, @idx) = @{$_[0]};
return if join('.', @idx) ne $idx;
use PublicInbox::Config;
use PublicInbox::Git;
use PublicInbox::Import;
-use Email::MIME;
+use PublicInbox::MIME;
use Email::MIME::ContentType;
$Email::MIME::ContentType::STRICT_PARAMS = 0; # user input is imperfect
use PublicInbox::Address;
my $spamc = PublicInbox::Spamcheck::Spamc->new;
my $pi_config = PublicInbox::Config->new;
my $err;
-my $mime = Email::MIME->new(eval {
+my $mime = PublicInbox::MIME->new(eval {
local $/;
my $data = scalar <STDIN>;
$data =~ s/\A[\r\n]*From [^\r\n]*\r?\n//s;
$emm = PublicInbox::Emergency->new($emergency);
$emm->prepare(\$str);
$ems = $ems->abort;
-my $mime = Email::MIME->new(\$str);
+my $mime = PublicInbox::MIME->new(\$str);
$str = '';
do_exit(0) unless $spam_ok;
use strict;
use warnings;
use Test::More;
-use Email::MIME;
+use PublicInbox::MIME;
use PublicInbox::Git;
use PublicInbox::Import;
use File::Temp qw/tempdir/;
my $git = PublicInbox::Git->new($dir);
my $im = PublicInbox::Import->new($git, 'testbox', 'test@example');
-my $mime = Email::MIME->create(
+my $mime = PublicInbox::MIME->create(
header => [
From => 'a@example.com',
To => 'b@example.com',
is(scalar @revs, 26, '26 revisions exist after mass import');
my ($mark, $msg) = $im->remove($mime);
like($mark, qr/\A:\d+\z/, 'got mark');
-is(ref($msg), 'Email::MIME', 'got old message deleted');
+is(ref($msg), 'PublicInbox::MIME', 'got old message deleted');
is(undef, $im->remove($mime), 'remove is idempotent');
--- /dev/null
+# Copyright (C) 2017 all contributors <meta@public-inbox.org>
+# This library is free software; you can redistribute it and/or modify
+# it under the same terms as Perl itself.
+# Artistic or GPL-1+ <https://www.gnu.org/licenses/gpl-1.0.txt>
+use strict;
+use warnings;
+use Test::More;
+use_ok 'PublicInbox::MIME';
+
+my $msg = PublicInbox::MIME->new(
+'From: Richard Hansen <hansenr@google.com>
+To: git@vger.kernel.org
+Cc: Richard Hansen <hansenr@google.com>
+Subject: [PATCH 0/2] minor diff orderfile documentation improvements
+Date: Mon, 9 Jan 2017 19:40:29 -0500
+Message-Id: <20170110004031.57985-1-hansenr@google.com>
+X-Mailer: git-send-email 2.11.0.390.gc69c2f50cf-goog
+Content-Type: multipart/signed; protocol="application/pkcs7-signature"; micalg=sha-256;
+ boundary="94eb2c0bc864b76ba30545b2bca9"
+
+--94eb2c0bc864b76ba30545b2bca9
+
+Richard Hansen (2):
+ diff: document behavior of relative diff.orderFile
+ diff: document the pattern format for diff.orderFile
+
+ Documentation/diff-config.txt | 5 ++++-
+ Documentation/diff-options.txt | 3 ++-
+ 2 files changed, 6 insertions(+), 2 deletions(-)
+
+
+--94eb2c0bc864b76ba30545b2bca9
+Content-Type: application/pkcs7-signature; name="smime.p7s"
+Content-Transfer-Encoding: base64
+Content-Disposition: attachment; filename="smime.p7s"
+Content-Description: (truncated) S/MIME Cryptographic Signature
+
+dkTlB69771K2eXK4LcHSH/2LqX+VYa3K44vrx1ruzjXdNWzIpKBy0weFNiwnJCGofvCysM2RCSI1
+--94eb2c0bc864b76ba30545b2bca9--
+
+');
+
+my @parts = $msg->parts;
+my $exp = 'Richard Hansen (2):
+ diff: document behavior of relative diff.orderFile
+ diff: document the pattern format for diff.orderFile
+
+ Documentation/diff-config.txt | 5 ++++-
+ Documentation/diff-options.txt | 3 ++-
+ 2 files changed, 6 insertions(+), 2 deletions(-)
+
+';
+
+ok($msg->isa('Email::MIME'), 'compatible with Email::MIME');
+is($parts[0]->body, $exp, 'body matches expected');
+
+done_testing();