MIME-Mini
view release on metacpan or search on metacpan
lib/MIME/Mini.pm view on Meta::CPAN
body message parts
newparam newmail
);
our %EXPORT_TAGS = (all => [@EXPORT_OK]);
sub formail # rfc2822 + mboxrd format (see http://www.qmail.org/man/man5/mbox.html)
{
sub mime # rfc2045, rfc2046
{
my ($mail, $parent) = @_;
return $mail unless exists $mail->{header} && exists $mail->{header}->{'content-type'} || defined $parent && exists $parent->{mime_type} && $parent->{mime_type} =~ /^multipart\/digest$/i;
my ($content_type) = (exists $mail->{header} && exists $mail->{header}->{'content-type'}) ? @{$mail->{header}->{'content-type'}} : "Content-Type: message/rfc822\n";
my ($type) = $content_type =~ /^content-type:\s*([\w\/.-]+)/i;
my $boundary = param($mail, 'content-type', 'boundary') if $type =~ /^multipart\//i;
return $mail unless defined $type && ($type =~ /^multipart\//i && $boundary || $type =~ /^message\/rfc822$/i);
($mail->{mime_boundary}) = $boundary =~ /^(.*\S)/ if $boundary;
$mail->{mime_type} = $type;
$mail->{mime_message} = mimepart(delete $mail->{body} || '', $mail), return $mail if $type =~ /^message\/(?:rfc822|external-body)$/i;
return tnef2mime(mimeparts($mail, $parent));
}
sub mimeparts
{
my ($mail, $parent) = @_;
lib/MIME/Mini.pm view on Meta::CPAN
}
return join '', map { $_->[1] } sort { my ($ad) = $a->[0] =~ /(\d+)/; my ($bd) = $b->[0] =~ /(\d+)/; $ad <=> $bd } @p;
}
sub mimetype # rfc2045, rfc2046
{
my ($m, $p) = @_;
my ($e) = header($m, 'content-transfer-encoding');
return 'application/octet-stream' if defined $e && $e !~ /^(?:[78]bit|binary|quoted-printable|base64)$/i;
my ($type) = header($m, 'content-type');
return lc $1 if defined $type && $type =~ /^((?:text|image|audio|video|application|message|multipart)\/[^\s;]+)/i;
return 'message/rfc822' if !defined $type && defined $p && exists $p->{mime_type} && $p->{mime_type} =~ /^multipart\/digest/i;
return 'text/plain';
}
sub encoding # rfc2045
{
my $m = shift;
my ($e) = header($m, 'content-transfer-encoding');
return (defined $e && $e =~ /^([78]bit|binary|quoted-printable|base64)$/i) ? lc $1 : (exists $m->{body} && $m->{body} =~ tr/\x80-\xff//) ? '8bit' : '7bit';
}
my $filename_counter;
sub filename # rfc2183, rfc2045?
{
my $p = shift;
my $fn = param($p, 'content-disposition', 'filename') || param($p, 'content-type', 'name') || 'attachment' . ++$filename_counter;
$fn =~ s/^.*[\\\/]//, $fn =~ tr/\x00-\x1f !"#\$%&'()*\/:;<=>?@[\\]^`{|}~\x7f/_/s;
return $fn;
}
sub body
{
my $m = shift;
return exists $m->{body} ? decode($m->{body}, encoding($m)) : undef;
}
t/01_MIME_Mini.latin1.t view on Meta::CPAN
};
# Test parsing of nasty header parameters
subtest param => sub
{
plan tests => 1;
my $m = {};
append_header($m, (my $h = "Content-Type: multipart/mixed; boundary*0*=\"iso-8859-1'en'%61a%61\" boundary*2=ccc boundary*1*=%62b%62"));
is param($m, 'content-type', 'boundary'), 'aaabbbccc', 'param: split into out-of-order pieces with encoding';
};
# Test mimetype identification and defaults
subtest mimetype => sub
{
plan tests => 5;
my $m = {};
append_header($m, "Content-Transfer-Encoding: wierd");
t/01_MIME_Mini.latin1.t view on Meta::CPAN
name*=iso-8859-1'en'h%E9%20h%E9;
long1*0=1234567890123456789012345678901234567890;
long1*1=1234567890123456789012345678901234567890; long1*2=1234567890;
long2*0=\"123456789 123456789 123456789 123456789 \";
long2*1=\"123456789 123456789 123456789 123456789 \"; long2*2=\"123456789 \";
french*0*=iso-8859-1'fr'Ceci%20est%20un%20exemple%20tr%E8s%20s;
french*1*=\"imple mais un peu long et avec un accent\";
french*2*=%20grave%20sur%20deux%20%E8
", 'newparam';
is param($m, 'content-type', 'charset'), 'us-ascii', 'newparam: charset';
is param($m, 'content-type', 'filename'), 'he he he', 'newparam: filename';
is param($m, 'content-type', 'name'), 'hé hé', 'newparam: name';
is param($m, 'content-type', 'long1'), '123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890', 'newparam: long1';
is param($m, 'content-type', 'long2'), '123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 ', 'newparam: long2';
is param($m, 'content-type', 'french'), 'Ceci est un exemple très simple mais un peu long et avec un accent grave sur deux è', 'newparam: french';
};
# Test creating mail objects
subtest newmail => sub
{
plan tests => 10;
like mail2str(mail2mbox(newmail(To => 'to@to.org', From => 'from@from.org', Subject => 'plain', body => "hello mail\n"))),
"/^From from\@from\.org $mboxdate_re
t/01_MIME_Mini.latin1.t view on Meta::CPAN
return $m;
}
# Test the boundary2test helper function
subtest boundary2test => sub
{
plan tests => 7;
is boundary2test("Content-Type: multipart/mixed; boundary=asdfasdf\n"), "Content-Type: multipart/mixed; boundary=test-boundary\n", 'boundary2test: Content-Type noquotes';
is boundary2test("content-type: multipart/mixed; boundary=asdfasdf\n"), "content-type: multipart/mixed; boundary=test-boundary\n", 'boundary2test: content-type noquotes';
is boundary2test("Content-Type: multipart/mixed; boundary=\"asdfasdf\"\n"), "Content-Type: multipart/mixed; boundary=\"test-boundary\"\n", 'boundary2test: Content-Type noquotes';
is boundary2test("content-type: multipart/mixed; boundary=\"asdfasdf\"\n"), "content-type: multipart/mixed; boundary=\"test-boundary\"\n", 'boundary2test: content-type noquotes';
is boundary2test("--asdfadf\n"), "--test-boundary\n", 'boundary2test: --asdfasdf\n';
is boundary2test("--asdfadf-\n"), "--test-boundary\n", 'boundary2test: --asdfasdf-\n';
is boundary2test("--asdfadf--\n"), "--test-boundary--\n", 'boundary2test: --asdfasdf--\n';
};
# Test parser: mbox filter with mail2multipart
subtest parse2multi => sub
{
my @fname = glob 't/in.m/*' or return;
t/02_MIME_Mini.utf8.t view on Meta::CPAN
};
# Test parsing of nasty header parameters
subtest param => sub
{
plan tests => 1;
my $m = {};
append_header($m, (my $h = "Content-Type: multipart/mixed; boundary*0*=\"iso-8859-1'en'%61a%61\" boundary*2=ccc boundary*1*=%62b%62"));
is param($m, 'content-type', 'boundary'), 'aaabbbccc', 'param: split into out-of-order pieces with encoding';
};
# Test mimetype identification and defaults
subtest mimetype => sub
{
plan tests => 5;
my $m = {};
append_header($m, "Content-Transfer-Encoding: wierd");
t/02_MIME_Mini.utf8.t view on Meta::CPAN
name*=iso-8859-1'en'h%E9%20h%E9;
long1*0=1234567890123456789012345678901234567890;
long1*1=1234567890123456789012345678901234567890; long1*2=1234567890;
long2*0=\"123456789 123456789 123456789 123456789 \";
long2*1=\"123456789 123456789 123456789 123456789 \"; long2*2=\"123456789 \";
french*0*=iso-8859-1'fr'Ceci%20est%20un%20exemple%20tr%E8s%20s;
french*1*=\"imple mais un peu long et avec un accent\";
french*2*=%20grave%20sur%20deux%20%E8
", 'newparam';
is param($m, 'content-type', 'charset'), 'us-ascii', 'newparam: charset';
is param($m, 'content-type', 'filename'), 'he he he', 'newparam: filename';
is param($m, 'content-type', 'name'), 'hé hé', 'newparam: name';
is param($m, 'content-type', 'long1'), '123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890', 'newparam: long1';
is param($m, 'content-type', 'long2'), '123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 ', 'newparam: long2';
is param($m, 'content-type', 'french'), 'Ceci est un exemple très simple mais un peu long et avec un accent grave sur deux è', 'newparam: french';
};
# Test creating mail objects
subtest newmail => sub
{
plan tests => 10;
like mail2str(mail2mbox(newmail(To => 'to@to.org', From => 'from@from.org', Subject => 'plain', body => "hello mail\n"))),
"/^From from\@from\.org $mboxdate_re
t/02_MIME_Mini.utf8.t view on Meta::CPAN
return $m;
}
# Test the boundary2test helper function
subtest boundary2test => sub
{
plan tests => 7;
is boundary2test("Content-Type: multipart/mixed; boundary=asdfasdf\n"), "Content-Type: multipart/mixed; boundary=test-boundary\n", 'boundary2test: Content-Type noquotes';
is boundary2test("content-type: multipart/mixed; boundary=asdfasdf\n"), "content-type: multipart/mixed; boundary=test-boundary\n", 'boundary2test: content-type noquotes';
is boundary2test("Content-Type: multipart/mixed; boundary=\"asdfasdf\"\n"), "Content-Type: multipart/mixed; boundary=\"test-boundary\"\n", 'boundary2test: Content-Type noquotes';
is boundary2test("content-type: multipart/mixed; boundary=\"asdfasdf\"\n"), "content-type: multipart/mixed; boundary=\"test-boundary\"\n", 'boundary2test: content-type noquotes';
is boundary2test("--asdfadf\n"), "--test-boundary\n", 'boundary2test: --asdfasdf\n';
is boundary2test("--asdfadf-\n"), "--test-boundary\n", 'boundary2test: --asdfasdf-\n';
is boundary2test("--asdfadf--\n"), "--test-boundary--\n", 'boundary2test: --asdfasdf--\n';
};
# Test parser: mbox filter with mail2multipart
subtest parse2multi => sub
{
my @fname = glob 't/in.m/*' or return;
t/good/malformed-multipart-truncated view on Meta::CPAN
[127.0.0.1]) (amavisd-new, port 10024) with ESMTP id rHGmEA9yZU-R for
<meego-dev@meego.com>; Wed, 13 Oct 2010 09:48:27 -0700 (PDT)
Received: from mail-ww0-f48.google.com (mail-ww0-f48.google.com
[74.125.82.48]) by mail.meego.com (Postfix) with ESMTP for
<meego-dev@meego.com>; Wed, 13 Oct 2010 09:48:26 -0700 (PDT)
Received: by wwi14 with SMTP id 14so92446wwi.5 for <meego-dev@meego.com>; Wed,
13 Oct 2010 09:48:25 -0700 (PDT)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=gamma;
h=domainkey-signature:received:received:sender:message-id:date:from
:reply-to:organization:user-agent:mime-version:to:subject
:x-enigmail-version:content-type;
bh=8mOSD8KfW+FGSmGIumHAs9auaL6zBlPdozt0rbw14IE=;
b=HCWFXbpQqAk8Tebb5dAk+Loj29ek3gg/KIeGgVqi/0bmW9KU3rgPZHZ4UGosFFdOti
T4kaLbACBBq0RfsKQz8JWzNa9cKrn5QexEm0iuxylxzC4qc2LxRKcnQCPK1G2WeuieCr
2HIRgWPm6wAQr9KjWMKq/SquYSACIpJzkkC18=
DomainKey-Signature: a=rsa-sha1; c=nofws; d=gmail.com; s=gamma;
h=sender:message-id:date:from:reply-to:organization:user-agent
:mime-version:to:subject:x-enigmail-version:content-type;
b=Yno3wge63XPt2MOW80/tIXtQz9tQyzgy1Sy8m4wCeP8H4rCoi4/ZKUOum9UlHqKCbx
NR0UaMzS6gZ86AFLyArS9mnFRSFOg8hBomojUhspQXJrxr/l2+wN2Ld5IRnFwn1LykW/
jYG+Dz9x79EFEqlD0dj9+5EkFC7ZK9ZLENLT0=
Received: by 10.227.152.131 with SMTP id g3mr8838258wbw.108.1286988504131;
Wed, 13 Oct 2010 09:48:24 -0700 (PDT)
Received: from [192.168.1.10] (ALyon-152-1-99-113.w86-202.abo.wanadoo.fr
[86.202.50.113]) by mx.google.com with ESMTPS id
g9sm8456296wbh.19.2010.10.13.09.48.22 (version=SSLv3 cipher=RC4-MD5); Wed, 13
Oct 2010 09:48:23 -0700 (PDT)
Message-ID: <4CB5E2D5.2040509@maemo.org>
t/in/malformed-multipart-truncated view on Meta::CPAN
[127.0.0.1]) (amavisd-new, port 10024) with ESMTP id rHGmEA9yZU-R for
<meego-dev@meego.com>; Wed, 13 Oct 2010 09:48:27 -0700 (PDT)
Received: from mail-ww0-f48.google.com (mail-ww0-f48.google.com
[74.125.82.48]) by mail.meego.com (Postfix) with ESMTP for
<meego-dev@meego.com>; Wed, 13 Oct 2010 09:48:26 -0700 (PDT)
Received: by wwi14 with SMTP id 14so92446wwi.5 for <meego-dev@meego.com>; Wed,
13 Oct 2010 09:48:25 -0700 (PDT)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=gamma;
h=domainkey-signature:received:received:sender:message-id:date:from
:reply-to:organization:user-agent:mime-version:to:subject
:x-enigmail-version:content-type;
bh=8mOSD8KfW+FGSmGIumHAs9auaL6zBlPdozt0rbw14IE=;
b=HCWFXbpQqAk8Tebb5dAk+Loj29ek3gg/KIeGgVqi/0bmW9KU3rgPZHZ4UGosFFdOti
T4kaLbACBBq0RfsKQz8JWzNa9cKrn5QexEm0iuxylxzC4qc2LxRKcnQCPK1G2WeuieCr
2HIRgWPm6wAQr9KjWMKq/SquYSACIpJzkkC18=
DomainKey-Signature: a=rsa-sha1; c=nofws; d=gmail.com; s=gamma;
h=sender:message-id:date:from:reply-to:organization:user-agent
:mime-version:to:subject:x-enigmail-version:content-type;
b=Yno3wge63XPt2MOW80/tIXtQz9tQyzgy1Sy8m4wCeP8H4rCoi4/ZKUOum9UlHqKCbx
NR0UaMzS6gZ86AFLyArS9mnFRSFOg8hBomojUhspQXJrxr/l2+wN2Ld5IRnFwn1LykW/
jYG+Dz9x79EFEqlD0dj9+5EkFC7ZK9ZLENLT0=
Received: by 10.227.152.131 with SMTP id g3mr8838258wbw.108.1286988504131;
Wed, 13 Oct 2010 09:48:24 -0700 (PDT)
Received: from [192.168.1.10] (ALyon-152-1-99-113.w86-202.abo.wanadoo.fr
[86.202.50.113]) by mx.google.com with ESMTPS id
g9sm8456296wbh.19.2010.10.13.09.48.22 (version=SSLv3 cipher=RC4-MD5); Wed, 13
Oct 2010 09:48:23 -0700 (PDT)
Message-ID: <4CB5E2D5.2040509@maemo.org>
( run in 3.169 seconds using v1.01-cache-2.11-cpan-524268b4103 )